vue2-client 1.16.25 → 1.16.27
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/.cursorrules +19 -19
- package/.env.apply +19 -19
- package/.env.gaslink +19 -19
- package/.env.his +19 -19
- package/.env.liuli +20 -20
- package/.env.scada +19 -19
- package/.eslintrc.js +90 -90
- package/CHANGELOG.md +824 -824
- package/Components.md +60 -60
- package/docs/LowCode/lowcode.md +155 -155
- package/docs/LowCode/lowcodeForDeveloper.md +230 -230
- package/docs/index.md +30 -30
- package/index.js +31 -31
- package/jest-transform-stub.js +8 -8
- package/jest.setup.js +7 -7
- package/jsconfig.json +19 -19
- package/package.json +112 -112
- package/public/his/editor/editor.html +51 -51
- package/public/his/editor/mock/bind_data.html +779 -779
- package/public/his/editor/mock/data_table.html +40 -40
- package/public/his/editor/mock/sign.html +75 -75
- package/public/his/editor/vender/JsBarcode.all.js +3669 -3669
- package/public/his/editor/vender/date97/My97DatePicker.htm +65 -65
- package/public/his/editor/vender/date97/WdatePicker.js +677 -677
- package/public/his/editor/vender/date97/calendar.js +4 -4
- package/public/his/editor/vender/date97/lang/en.js +13 -13
- package/public/his/editor/vender/date97/lang/zh-cn.js +13 -13
- package/public/his/editor/vender/date97/lang/zh-tw.js +13 -13
- package/public/his/editor/vender/date97/skin/WdatePicker.css +10 -10
- package/public/his/editor/vender/date97/skin/default/datepicker.css +328 -328
- package/public/his/editor/vender/date97/skin/ext/datepicker.css +308 -308
- package/public/his/editor/vender/date97/skin/whyGreen/datepicker.css +255 -255
- package/public/his/editor/vender/diff.js +1627 -1627
- package/public/his/editor/vender/editor.js +1 -1
- package/public/his/editor/vender/fabric.js +31187 -31187
- package/public/his/editor/vender/jquery/jquery.base64.js +190 -190
- package/public/his/editor/vender/jquery/jquery.js +10872 -10872
- package/public/his/editor/vender/jquery/jquery.print.js +255 -255
- package/public/his/editor/vender/jquery/zTreeStyle/zTreeStyle.css +96 -96
- package/public/his/editor/vender/mui/mui.min.css +4 -4
- package/public/his/editor/vender/mui/mui.min.js +5 -5
- package/public/his/editor/vender/mui/mui.picker.min.css +6 -6
- package/public/his/editor/vender/mui/mui.picker.min.js +6 -6
- package/public/his/editor/vender/qrcode.js +7 -7
- package/public/his/editor/vender/requirejs/require.js +2145 -2145
- package/public/his/editor/vender/signature/jSignature.CompressorSVG.js +518 -518
- package/public/his/editor/vender/signature/jSignature.UndoButton.js +164 -164
- package/public/his/editor/vender/signature/jSignature.js +1486 -1486
- package/public/his/editor/vender/validator.js +5094 -5094
- package/public/his/editor/vender/weui/weui.css +5659 -5659
- package/public/his/editor/vender/weui/weui.min.css +4 -4
- package/public/his/editor/vender/weui/weui.min.js +11 -11
- package/src/assets/img/querySlotDemo.svg +15 -15
- package/src/assets/svg/badtwo.svg +1 -1
- package/src/assets/svg/goodtwo.svg +1 -1
- package/src/base-client/components/AI/AskAiBtn.vue +136 -136
- package/src/base-client/components/AI/demo.vue +31 -31
- package/src/base-client/components/common/AddressSearchCombobox/IcMapIcon.vue +16 -16
- package/src/base-client/components/common/AddressSearchCombobox/demo.vue +36 -36
- package/src/base-client/components/common/AddressSearchCombobox/ic_map.svg +6 -6
- package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
- package/src/base-client/components/common/CitySelect/CitySelect.vue +1 -1
- package/src/base-client/components/common/CitySelect/index.js +3 -3
- package/src/base-client/components/common/CitySelect/index.md +109 -109
- package/src/base-client/components/common/CreateQuery/CreateQuery.vue +669 -669
- package/src/base-client/components/common/CreateQuery/CreateQueryItem.vue +1014 -1014
- package/src/base-client/components/common/CreateQuery/index.js +3 -3
- package/src/base-client/components/common/CreateQuery/index.md +42 -42
- package/src/base-client/components/common/CreateSimpleFormQuery/CreateSimpleFormQuery.vue +452 -452
- package/src/base-client/components/common/CreateSimpleFormQuery/CreateSimpleFormQueryItem.vue +511 -511
- package/src/base-client/components/common/CreateSimpleFormQuery/index.js +3 -3
- package/src/base-client/components/common/CreateSimpleFormQuery/index.md +42 -42
- package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
- package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
- package/src/base-client/components/common/FormGroupQuery/FormGroupQuery.vue +166 -166
- package/src/base-client/components/common/FormGroupQuery/index.js +3 -3
- package/src/base-client/components/common/FormGroupQuery/index.md +43 -43
- package/src/base-client/components/common/HIS/HForm/HForm.vue +133 -0
- package/src/base-client/components/common/HIS/HForm/index.js +3 -0
- package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
- package/src/base-client/components/common/LowCodeComponent/LowCodeEditorModal.vue +108 -108
- package/src/base-client/components/common/LowCodeComponent/LowCodeEditorPanel.vue +413 -413
- package/src/base-client/components/common/LowCodeComponent/LowCodePageOrganization.vue +502 -502
- package/src/base-client/components/common/LowCodeComponent/LowCodeRender.vue +728 -728
- package/src/base-client/components/common/LowCodeComponent/LowCodeRenderEnter.vue +29 -29
- package/src/base-client/components/common/LowCodeComponent/LowCodeUIStore.vue +219 -219
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeAddPageModal.vue +117 -117
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeCustomJSModal.vue +80 -80
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeEventEditorModal.vue +398 -398
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeLifeCycleModal.vue +65 -65
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeLogicCallbackModal.vue +64 -64
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeLogicParamModal.vue +73 -73
- package/src/base-client/components/common/LowCodeComponent/modal/lowCodeRunFunctionParamModal.vue +76 -76
- package/src/base-client/components/common/PersonSetting/PersonSetting.vue +208 -208
- package/src/base-client/components/common/PersonSetting/index.js +3 -3
- package/src/base-client/components/common/Recording/Recording.vue +243 -243
- package/src/base-client/components/common/Recording/index.js +3 -3
- package/src/base-client/components/common/Tree/Tree.vue +149 -149
- package/src/base-client/components/common/Tree/index.js +2 -2
- package/src/base-client/components/common/Upload/Upload.vue +333 -323
- package/src/base-client/components/common/Upload/index.js +3 -3
- package/src/base-client/components/common/XAddForm/XAddForm.vue +113 -113
- package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
- package/src/base-client/components/common/XAddNativeFormOA/XAddNativeFormOA.vue +303 -303
- package/src/base-client/components/common/XAddNativeFormOA/index.js +3 -3
- package/src/base-client/components/common/XAddNativeFormOA/index.md +146 -146
- package/src/base-client/components/common/XAddReport/index.js +3 -3
- package/src/base-client/components/common/XAddReport/index.md +56 -56
- package/src/base-client/components/common/XBadge/XBadge.vue +94 -94
- package/src/base-client/components/common/XButtons/XButtonDemo.vue +28 -28
- package/src/base-client/components/common/XButtons/index.js +3 -3
- package/src/base-client/components/common/XButtons/index.md +61 -61
- package/src/base-client/components/common/XCard/XCard.vue +64 -64
- package/src/base-client/components/common/XCheckList/XCheckList.vue +106 -106
- package/src/base-client/components/common/XCheckList/XCheckListDemo.vue +41 -41
- package/src/base-client/components/common/XDataCard/index.js +3 -3
- package/src/base-client/components/common/XDataCard/index.md +1 -1
- package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
- package/src/base-client/components/common/XDataDrawer/index.js +3 -3
- package/src/base-client/components/common/XDataDrawer/index.md +41 -41
- package/src/base-client/components/common/XDatePicker/demo.vue +153 -153
- package/src/base-client/components/common/XDescriptions/index.js +3 -3
- package/src/base-client/components/common/XDescriptions/index.md +83 -83
- package/src/base-client/components/common/XDetailsView/XDetailsView.vue +238 -238
- package/src/base-client/components/common/XDetailsView/index.js +3 -3
- package/src/base-client/components/common/XForm/XFormItem.vue +1504 -1503
- package/src/base-client/components/common/XForm/XStatusButton.vue +54 -54
- package/src/base-client/components/common/XForm/index.md +178 -178
- package/src/base-client/components/common/XForm/itemComponent/XClickChangeBtn/index.vue +49 -49
- package/src/base-client/components/common/XFormGroup/index.js +3 -3
- package/src/base-client/components/common/XFormGroup/index.md +38 -38
- package/src/base-client/components/common/XFormGroupDetails/XFormGroupDetails.vue +72 -72
- package/src/base-client/components/common/XFormGroupDetails/index.js +3 -3
- package/src/base-client/components/common/XFormTable/index.md +92 -92
- package/src/base-client/components/common/XLabelSelect/XLabelSelect.vue +110 -110
- package/src/base-client/components/common/XLabelSelect/XLabelSelectDemo.vue +35 -35
- package/src/base-client/components/common/XLicensePlate/XLicensePlate.vue +193 -193
- package/src/base-client/components/common/XLicensePlate/XLicensePlateDemo.vue +48 -48
- package/src/base-client/components/common/XPrint/OpenInvoice.vue +21 -21
- package/src/base-client/components/common/XPrint/PrintHtml.js +98 -98
- package/src/base-client/components/common/XPrint/css/hiPrintCss.js +359 -359
- package/src/base-client/components/common/XPrint/css/lodopCss.js +26 -26
- package/src/base-client/components/common/XPrint/css/print-lock.css +351 -351
- package/src/base-client/components/common/XPrint/index.vue +97 -97
- package/src/base-client/components/common/XReport/XReportDesign.vue +463 -463
- package/src/base-client/components/common/XReport/XReportJsonRender.vue +381 -381
- package/src/base-client/components/common/XReport/index.js +3 -3
- package/src/base-client/components/common/XReport/print.js +186 -186
- package/src/base-client/components/common/XReportDrawer/index.js +3 -3
- package/src/base-client/components/common/XReportGrid/XReportTrGroup.vue +4 -1
- package/src/base-client/components/common/XReportGrid/index.js +3 -3
- package/src/base-client/components/common/XReportGrid/index.md +44 -44
- package/src/base-client/components/common/XReportSlot/XReportSlot.vue +110 -110
- package/src/base-client/components/common/XReportSlot/index.js +3 -3
- package/src/base-client/components/common/XReportSlot/index.md +48 -48
- package/src/base-client/components/common/XSimpleDescriptions/XSimpleDescriptions.vue +166 -166
- package/src/base-client/components/common/XSimpleDescriptions/index.js +3 -3
- package/src/base-client/components/common/XSimpleDescriptions/index.md +7 -7
- package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
- package/src/base-client/components/common/XStepView/index.js +3 -3
- package/src/base-client/components/common/XStepView/index.md +31 -31
- package/src/base-client/components/common/XTab/XTabDemo.vue +22 -22
- package/src/base-client/components/common/XTab/index.js +3 -3
- package/src/base-client/components/common/XTable/CustomFuncCel.vue +51 -51
- package/src/base-client/components/common/XTable/TableCellRenderer.vue +161 -161
- package/src/base-client/components/common/XTable/index.md +255 -255
- package/src/base-client/components/common/XTagGroup/index.vue +52 -52
- package/src/base-client/components/common/XTree/XTree.vue +424 -424
- package/src/base-client/components/common/XTree/index.js +3 -3
- package/src/base-client/components/common/XTree/index.md +36 -36
- package/src/base-client/components/common/XTreeOne/XTreeOne.vue +113 -113
- package/src/base-client/components/common/XTreeOne/XTreeOnePro.vue +128 -128
- package/src/base-client/components/common/richTextModal/index.vue +56 -56
- package/src/base-client/components/common/richTextModal/richDemo.vue +48 -48
- package/src/base-client/components/his/XHisEditor/index.js +3 -3
- package/src/base-client/components/index.js +51 -51
- package/src/base-client/components/layout/XTreeView/XTreeView.vue +130 -130
- package/src/base-client/components/layout/XTreeView/index.js +3 -3
- package/src/base-client/components/layout/XTreeView/index.md +46 -46
- package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
- package/src/base-client/components/system/QueryParamsDetailsView/QueryParamsDetailsView.vue +281 -281
- package/src/base-client/plugins/Config.js +19 -19
- package/src/base-client/plugins/GetLoginInfoService.js +183 -183
- package/src/base-client/plugins/Recording.js +258 -258
- package/src/base-client/plugins/index.js +23 -23
- package/src/base-client/plugins/tabs-page-plugin.js +39 -39
- package/src/components/Charts/Bar.vue +62 -62
- package/src/components/Charts/ChartCard.vue +134 -134
- package/src/components/Charts/Liquid.vue +67 -67
- package/src/components/Charts/MiniArea.vue +39 -39
- package/src/components/Charts/MiniBar.vue +39 -39
- package/src/components/Charts/MiniProgress.vue +75 -75
- package/src/components/Charts/MiniSmoothArea.vue +40 -40
- package/src/components/Charts/Radar.vue +68 -68
- package/src/components/Charts/RankList.vue +77 -77
- package/src/components/Charts/TagCloud.vue +113 -113
- package/src/components/Charts/TransferBar.vue +64 -64
- package/src/components/Charts/Trend.vue +82 -82
- package/src/components/Charts/chart.less +12 -12
- package/src/components/Charts/smooth.area.less +13 -13
- package/src/components/CodeMirror/inedx.vue +118 -118
- package/src/components/CodeMirror/setting.js +40 -40
- package/src/components/FileImageItem/FileItem.vue +320 -320
- package/src/components/NumberInfo/NumberInfo.vue +54 -54
- package/src/components/NumberInfo/index.js +3 -3
- package/src/components/NumberInfo/index.less +54 -54
- package/src/components/NumberInfo/index.md +43 -43
- package/src/components/card/ChartCard.vue +79 -79
- package/src/components/chart/Bar.vue +60 -60
- package/src/components/chart/MiniArea.vue +67 -67
- package/src/components/chart/MiniBar.vue +59 -59
- package/src/components/chart/MiniProgress.vue +57 -57
- package/src/components/chart/Radar.vue +80 -80
- package/src/components/chart/RankingList.vue +60 -60
- package/src/components/chart/Trend.vue +79 -79
- package/src/components/chart/index.less +9 -9
- package/src/components/checkbox/ColorCheckbox.vue +157 -157
- package/src/components/checkbox/ImgCheckbox.vue +117 -117
- package/src/components/checkbox/ImgCheckboxGroup.vue +76 -76
- package/src/components/checkbox/index.js +9 -9
- package/src/components/exception/ExceptionPage.vue +70 -70
- package/src/components/g2Charts/constants.js +202 -202
- package/src/components/g2Charts/demo.vue +808 -808
- package/src/components/g2Charts/designer.vue +228 -228
- package/src/components/g2Charts/designerBaseConfig.vue +61 -61
- package/src/components/g2Charts/designerDataConfig.vue +259 -259
- package/src/components/g2Charts/designerStyleConfig.vue +16 -16
- package/src/components/g2Charts/index.vue +397 -397
- package/src/components/index.js +36 -36
- package/src/components/input/IInput.vue +66 -66
- package/src/components/menu/SideMenu.vue +75 -75
- package/src/components/menu/menu.js +273 -273
- package/src/components/setting/Setting.vue +234 -234
- package/src/components/tool/AStepItem.vue +60 -60
- package/src/config/CreateQueryConfig.js +325 -325
- package/src/config/default/antd.config.js +89 -89
- package/src/config/default/setting.config.js +55 -55
- package/src/font-style/font.css +60 -60
- package/src/layouts/CommonLayout.vue +56 -56
- package/src/layouts/PageLayout.vue +151 -151
- package/src/layouts/SinglePageView.vue +136 -136
- package/src/layouts/header/AdminHeader.vue +132 -132
- package/src/layouts/header/HeaderNotice.vue +177 -177
- package/src/layouts/header/InstitutionDetail.vue +181 -181
- package/src/layouts/tabs/TabsHead.vue +189 -189
- package/src/lib.js +1 -1
- package/src/mock/extend/index.js +84 -84
- package/src/mock/goods/index.js +108 -108
- package/src/pages/DefaultExample/index.vue +77 -77
- package/src/pages/DynamicStatistics/ChartSelector.vue +331 -331
- package/src/pages/DynamicStatistics/DataTabs.vue +83 -83
- package/src/pages/DynamicStatistics/DynamicTable.vue +128 -128
- package/src/pages/DynamicStatistics/EvaluationArea.vue +69 -69
- package/src/pages/DynamicStatistics/FavoriteList.vue +50 -50
- package/src/pages/DynamicStatistics/QuestionHistoryAndFavorites.vue +591 -591
- package/src/pages/DynamicStatistics/SearchBar.vue +192 -192
- package/src/pages/DynamicStatistics/index.vue +282 -282
- package/src/pages/Example/childIndex.vue +15 -15
- package/src/pages/Example/index.vue +30 -30
- package/src/pages/NewDynamicStatistics/ChartSelector.vue +331 -331
- package/src/pages/NewDynamicStatistics/DataTabs.vue +122 -122
- package/src/pages/NewDynamicStatistics/DynamicTable.vue +128 -128
- package/src/pages/NewDynamicStatistics/EvaluationArea.vue +69 -69
- package/src/pages/NewDynamicStatistics/FavoriteList.vue +50 -50
- package/src/pages/NewDynamicStatistics/QuestionHistoryAndFavorites.vue +289 -289
- package/src/pages/NewDynamicStatistics/SearchBar.vue +193 -193
- package/src/pages/NewDynamicStatistics/index.vue +258 -258
- package/src/pages/Recording/index.vue +77 -77
- package/src/pages/ServiceReview/index.vue +284 -284
- package/src/pages/SubExample/index.vue +26 -26
- package/src/pages/WorkflowDetail/WorkflowPageDetail/TrimTextTail.vue +23 -23
- package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowHandle.vue +1766 -1766
- package/src/pages/XReportView/index.vue +64 -64
- package/src/pages/XTreeOneProExample/index.vue +67 -67
- package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
- package/src/pages/login/Login.vue +379 -379
- package/src/pages/login/LoginV3.vue +389 -389
- package/src/pages/lowCode/lowCodeEditor.vue +1219 -1219
- package/src/pages/lowCode/lowCodeRenderPage.vue +43 -43
- package/src/pages/report/ReportTable.js +124 -124
- package/src/pages/resourceManage/orgListManage.vue +98 -98
- package/src/pages/system/dictionary/index.vue +44 -44
- package/src/pages/system/monitor/loginInfor/index.vue +37 -37
- package/src/pages/system/monitor/operLog/index.vue +37 -37
- package/src/pages/system/settings/modifyPassword.vue +117 -117
- package/src/pages/system/ticket/index.vue +480 -480
- package/src/pages/system/ticket/submitTicketSuccess.vue +484 -484
- package/src/pages/userInfoDetailManage/ChangeMeterRecordQuery/index.vue +64 -64
- package/src/pages/userInfoDetailManage/InfoChangeRecordQuery/index.vue +64 -64
- package/src/pages/userInfoDetailManage/InstructRecordQuery/index.vue +64 -64
- package/src/pages/userInfoDetailManage/MeterParamRecordQuery/index.vue +64 -64
- package/src/pages/userInfoDetailManage/TransferRecordQuery/index.vue +66 -66
- package/src/pages/userInfoDetailManage/WatchCollectionRecordQuery/index.vue +64 -64
- package/src/plugins/EventLogPlugin.js +33 -33
- package/src/plugins/FindParentsData.js +17 -17
- package/src/router/async/config.async.js +35 -35
- package/src/router/index.js +27 -27
- package/src/services/DataModel.js +30 -30
- package/src/services/LodopFuncs.js +137 -137
- package/src/services/api/TicketDetailsViewApi.js +46 -46
- package/src/services/api/cas.js +79 -79
- package/src/services/api/common.js +346 -346
- package/src/services/api/entity.js +18 -18
- package/src/services/api/index.js +17 -17
- package/src/store/modules/account.js +115 -115
- package/src/store/modules/index.js +5 -5
- package/src/store/modules/lowCode.js +33 -33
- package/src/store/modules/setting.js +119 -119
- package/src/theme/default/style.less +58 -58
- package/src/utils/authority-utils.js +85 -85
- package/src/utils/errorCode.js +6 -6
- package/src/utils/formatter.js +74 -74
- package/src/utils/htmlToPDF.js +108 -108
- package/src/utils/htmlToPDFApi.js +5 -5
- package/src/utils/login.js +188 -188
- package/src/utils/lowcode/lowcodeComponentMixin.js +120 -120
- package/src/utils/lowcode/lowcodeLog.js +29 -29
- package/src/utils/lowcode/lowcodeUtils.js +373 -373
- package/src/utils/lowcode/registerComponentForEditor.js +1 -1
- package/src/utils/lowcode/registerComponentForRender.js +11 -11
- package/src/utils/map-utils.js +47 -47
- package/src/utils/reg.js +95 -95
- package/src/utils/runEvalFunction.js +14 -14
- package/src/utils/theme-color-replacer-extend.js +92 -92
- package/src/utils/util.js +329 -329
- package/src/utils/waterMark.js +31 -31
- package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
@@ -1,1766 +1,1766 @@
|
|
1
|
-
<template>
|
2
|
-
<div>
|
3
|
-
<!-- 上方流程显示 -->
|
4
|
-
<a-card :bordered="false" :loading="loading">
|
5
|
-
<!-- 项目进度流程 -->
|
6
|
-
<work-flow-timeline
|
7
|
-
:current-step-id="currentStepId"
|
8
|
-
:active-step-id="activeStepId"
|
9
|
-
:workflow-id="workflowId"
|
10
|
-
:steps="stepsForChild"
|
11
|
-
:state="workflowState"
|
12
|
-
change-able
|
13
|
-
@activeStep="activeStep"/>
|
14
|
-
</a-card>
|
15
|
-
<!-- 无权访问的提示 -->
|
16
|
-
<a-result v-show="!canSubmit" status="403" title="无权操作" sub-title="您没有访问该步骤的权限.">
|
17
|
-
</a-result>
|
18
|
-
<div v-show="canSubmit">
|
19
|
-
<!-- 流程被退回的提示 -->
|
20
|
-
<a-alert v-if="currentStep && currentStep.back && !(beforeStepActive || workflowState)" type="info" show-icon style="margin-bottom: 14px">
|
21
|
-
<div slot="message">
|
22
|
-
<span style="font-weight: bold">流程被退回</span>
|
23
|
-
<span style="margin-left: 14px; font-size: 14px; color: rgba(0, 0, 0, 0.65)">请重新填写信息发起提交</span>
|
24
|
-
</div>
|
25
|
-
<div slot="description">
|
26
|
-
<div>操作人:{{
|
27
|
-
currentStep.back.f_operator
|
28
|
-
}} 操作时间:{{ currentStep.back.f_date }}
|
29
|
-
</div>
|
30
|
-
<div>原因:{{ currentStep.back.f_notes }}</div>
|
31
|
-
</div>
|
32
|
-
</a-alert>
|
33
|
-
<!-- 步骤内容主体 -->
|
34
|
-
<a-tabs default-active-key="1" @change="note = ''" type="card">
|
35
|
-
<a-tab-pane key="0" tab="步骤详情" v-if="beforeStepActive || workflowState">
|
36
|
-
<a-card :bordered="false" :loading="loadingHistory" :body-style="{ paddingTop: 0 }">
|
37
|
-
<!-- 当前步骤历史记录 -->
|
38
|
-
<template v-if="showTab">
|
39
|
-
<x-tab
|
40
|
-
:compProp="{ buttonState: { add: false, edit: false, delete: false, import: false, extra: false }, disableAction: true }"
|
41
|
-
:local-config="tabDesigner"
|
42
|
-
:body-style="{ padding: 0 }"
|
43
|
-
:tabBarGutter="24"
|
44
|
-
:extra-data="{ workflowId: workflowId }"
|
45
|
-
default-active-key="workFlowTab">
|
46
|
-
<a-tab-pane
|
47
|
-
:forceRender="true"
|
48
|
-
v-if="formCompletedDataPreview"
|
49
|
-
slot="extraBeforeTabs"
|
50
|
-
key="workFlowTab"
|
51
|
-
tab="表单"
|
52
|
-
>
|
53
|
-
<work-flow-preview :form-completed-data-preview="formCompletedDataPreview"/>
|
54
|
-
</a-tab-pane>
|
55
|
-
</x-tab>
|
56
|
-
</template>
|
57
|
-
<template v-else-if="formCompletedDataPreview">
|
58
|
-
<work-flow-preview :form-completed-data-preview="formCompletedDataPreview"/>
|
59
|
-
</template>
|
60
|
-
<template v-else>
|
61
|
-
<a-result status="404" title="暂无数据" sub-title="该步骤暂无数据。">
|
62
|
-
</a-result>
|
63
|
-
</template>
|
64
|
-
</a-card>
|
65
|
-
</a-tab-pane>
|
66
|
-
<a-tab-pane key="1" tab="业务操作" v-else v-show="renderCurrentNode">
|
67
|
-
<a-card :bordered="false" :loading="loadingHistory" :body-style="{ paddingTop: 0 }">
|
68
|
-
<x-tab
|
69
|
-
v-if="showTab"
|
70
|
-
:compProp="{ buttonState: { extra: true }, disableAction: false }"
|
71
|
-
:local-config="tabDesigner"
|
72
|
-
:extra-data="{ workflowId:workflowId }"
|
73
|
-
:body-style="{ padding: 0 }"
|
74
|
-
:tabBarGutter="24"
|
75
|
-
default-active-key="workFlowTab">
|
76
|
-
<a-tab-pane
|
77
|
-
:forceRender="true"
|
78
|
-
v-if="showForm"
|
79
|
-
slot="extraBeforeTabs"
|
80
|
-
key="workFlowTab"
|
81
|
-
tab="表单"
|
82
|
-
>
|
83
|
-
<x-add-native-form
|
84
|
-
ref="xAddForm"
|
85
|
-
@x-form-item-emit-func="formItemEmitFunc"
|
86
|
-
@onSubmit="submitForm"/>
|
87
|
-
</a-tab-pane>
|
88
|
-
</x-tab>
|
89
|
-
<x-add-native-form
|
90
|
-
v-else
|
91
|
-
ref="xAddForm"
|
92
|
-
@x-form-item-emit-func="formItemEmitFunc"
|
93
|
-
@onSubmit="submitForm"/>
|
94
|
-
<a-divider/>
|
95
|
-
|
96
|
-
<!-- 分支节点状态提示 -->
|
97
|
-
<a-alert
|
98
|
-
v-if="isBranchLastNode.isBranchNode && !isBranchLastNode.isLastBranch"
|
99
|
-
type="info"
|
100
|
-
show-icon
|
101
|
-
style="margin-bottom: 16px"
|
102
|
-
>
|
103
|
-
<template slot="message">
|
104
|
-
<span style="font-weight: bold;">分支节点等待中</span>
|
105
|
-
</template>
|
106
|
-
<template slot="description">
|
107
|
-
<div>当前为分支节点,其他分支仍在进行中。完成当前分支后将等待其他分支完成,然后自动汇合到下一环节。</div>
|
108
|
-
<div style="margin-top: 8px; color: #666; font-size: 12px;">
|
109
|
-
<a-icon type="info-circle" style="margin-right: 4px;" />
|
110
|
-
提示:此操作无需选择下一环节负责人,系统将自动处理流程流转。
|
111
|
-
</div>
|
112
|
-
</template>
|
113
|
-
</a-alert>
|
114
|
-
|
115
|
-
<a-alert
|
116
|
-
v-if="isBranchLastNode.isBranchNode && isBranchLastNode.isLastBranch"
|
117
|
-
type="success"
|
118
|
-
show-icon
|
119
|
-
style="margin-bottom: 16px"
|
120
|
-
>
|
121
|
-
<template slot="message">
|
122
|
-
<span style="font-weight: bold;">分支汇合节点</span>
|
123
|
-
</template>
|
124
|
-
<template slot="description">
|
125
|
-
<div>您正在处理最后一个未完成的分支节点,完成后将触发分支汇合并进入下一环节。</div>
|
126
|
-
</template>
|
127
|
-
</a-alert>
|
128
|
-
|
129
|
-
<a-form v-show="!lastStep" label-align="left" :label-col="{ span: 3 }" :wrapper-col="{ span: 13 }">
|
130
|
-
<a-form-item v-if="showStepNextBtn" label="操作类型" required>
|
131
|
-
<a-radio-group v-model="operationType" @change="handleOperationTypeChange">
|
132
|
-
<a-radio value="submit">到下一步</a-radio>
|
133
|
-
<a-radio value="skip">{{ stepNextBtnTitle }}</a-radio>
|
134
|
-
</a-radio-group>
|
135
|
-
</a-form-item>
|
136
|
-
|
137
|
-
<!-- 智能分支人员选择组件 - 只有非分支节点或最后一个分支才显示 -->
|
138
|
-
<WorkflowPersonSelector
|
139
|
-
v-if="!isBranchLastNode.isBranchNode || isBranchLastNode.isLastBranch"
|
140
|
-
ref="personSelector"/>
|
141
|
-
|
142
|
-
<a-form-item
|
143
|
-
v-if="!isBranchLastNode.isBranchNode || isBranchLastNode.isLastBranch"
|
144
|
-
label="下一环节截止时间"
|
145
|
-
:validate-status="deadlineValidateStatus"
|
146
|
-
:help="deadlineHelp"
|
147
|
-
required>
|
148
|
-
<a-date-picker
|
149
|
-
:getCalendarContainer="(triggerNode) => triggerNode.parentNode"
|
150
|
-
v-model="deadline"
|
151
|
-
value-format="YYYY-MM-DD HH:mm"
|
152
|
-
format="YYYY-MM-DD HH:mm"
|
153
|
-
:allow-clear="false"
|
154
|
-
:show-today="false"
|
155
|
-
show-time
|
156
|
-
placeholder="请选择"/>
|
157
|
-
</a-form-item>
|
158
|
-
</a-form>
|
159
|
-
<a-divider/>
|
160
|
-
<!-- 备注信息 -->
|
161
|
-
<a-textarea
|
162
|
-
v-model="note"
|
163
|
-
:auto-size="{ minRows: 3, maxRows: 5 }"
|
164
|
-
placeholder="填写本环节备注事项"
|
165
|
-
/>
|
166
|
-
<!-- 当前步骤完成后,控制流程按钮 -->
|
167
|
-
<div style="text-align: center">
|
168
|
-
<a-radio-group style="margin-top: 20px">
|
169
|
-
<a-space>
|
170
|
-
<!-- 动态按钮渲染 -->
|
171
|
-
<template v-if="buttonGroup && buttonGroup.actionArr">
|
172
|
-
<a-button
|
173
|
-
v-for="(button, index) in buttonGroup.actionArr"
|
174
|
-
:key="index"
|
175
|
-
v-show="checkButtonVisible(button)"
|
176
|
-
:type="button.type ? button.type : 'default'"
|
177
|
-
@click="handleCustomButtonClick(button)"
|
178
|
-
>
|
179
|
-
{{ button.text }}
|
180
|
-
</a-button>
|
181
|
-
</template>
|
182
|
-
<!-- 原有的按钮逻辑 -->
|
183
|
-
<template>
|
184
|
-
<a-popover v-if="operationType === 'submit'">
|
185
|
-
<template slot="content">
|
186
|
-
<p v-if="isBranchLastNode.isBranchNode && !isBranchLastNode.isLastBranch">
|
187
|
-
完成当前分支,等待其他分支完成后自动汇合
|
188
|
-
</p>
|
189
|
-
<p v-else-if="isBranchLastNode.isBranchNode && isBranchLastNode.isLastBranch">
|
190
|
-
完成最后一个分支并触发汇合到下一环节
|
191
|
-
</p>
|
192
|
-
<p v-else>{{ nextBtnTitle }}</p>
|
193
|
-
</template>
|
194
|
-
<a-button
|
195
|
-
v-if="!lastStep"
|
196
|
-
:disabled="!showNextBtn && !stepDone"
|
197
|
-
type="primary"
|
198
|
-
@click="nextClick"
|
199
|
-
>
|
200
|
-
完成提交
|
201
|
-
<a-icon type="right"/>
|
202
|
-
</a-button>
|
203
|
-
</a-popover>
|
204
|
-
<a-popover v-else :title="stepNextBtnTitle">
|
205
|
-
<template slot="content">
|
206
|
-
<p v-for="(item,index) in stepNextBtnText" :key="index">{{ item }}</p>
|
207
|
-
</template>
|
208
|
-
<a-button
|
209
|
-
v-if="showStepNextBtn && !lastStep"
|
210
|
-
type="primary"
|
211
|
-
@click="stepNextClick"
|
212
|
-
>
|
213
|
-
跳过
|
214
|
-
</a-button>
|
215
|
-
</a-popover>
|
216
|
-
<a-button
|
217
|
-
v-if="lastStep"
|
218
|
-
type="primary"
|
219
|
-
@click="lastStepNextClick"
|
220
|
-
>
|
221
|
-
确认完成
|
222
|
-
</a-button>
|
223
|
-
</template>
|
224
|
-
</a-space>
|
225
|
-
</a-radio-group>
|
226
|
-
</div>
|
227
|
-
</a-card>
|
228
|
-
</a-tab-pane>
|
229
|
-
<!-- 退回 -->
|
230
|
-
<a-tab-pane v-if="canSubmit && !beforeStepActive && showPrevBtn && !workflowState" key="2" tab="退回">
|
231
|
-
<a-form layout="vertical">
|
232
|
-
<a-form-item label="退回原因" :wrapper-col="{ span: 24 }" required>
|
233
|
-
<a-textarea
|
234
|
-
v-model="backNote"
|
235
|
-
:auto-size="{ minRows: 4, maxRows: 10 }"
|
236
|
-
placeholder="请填写退回原因 / 备注"
|
237
|
-
/>
|
238
|
-
</a-form-item>
|
239
|
-
<a-form-item :wrapper-col="{ offset: 11 }">
|
240
|
-
<a-popover :title="preBtnTitle">
|
241
|
-
<template slot="content">
|
242
|
-
<p v-for="(item,index) in preBtnText" :key="index">{{ item }}</p>
|
243
|
-
</template>
|
244
|
-
<a-button
|
245
|
-
type="danger"
|
246
|
-
@click="preClick"
|
247
|
-
>
|
248
|
-
<a-icon type="left"/>
|
249
|
-
退回
|
250
|
-
</a-button>
|
251
|
-
</a-popover>
|
252
|
-
</a-form-item>
|
253
|
-
</a-form>
|
254
|
-
</a-tab-pane>
|
255
|
-
<!-- <a-tab-pane v-if="canSubmit && !beforeStepActive && showPrevBtn && !workflowState" key="3" tab="工单拆分">
|
256
|
-
<!– 分配工单 –>
|
257
|
-
<workflow-list-resolution :workflow-project-id="workflowId" :details="details"></workflow-list-resolution>
|
258
|
-
</a-tab-pane>-->
|
259
|
-
</a-tabs>
|
260
|
-
</div>
|
261
|
-
</div>
|
262
|
-
</template>
|
263
|
-
|
264
|
-
<script>
|
265
|
-
import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm'
|
266
|
-
import XFormTable from '@vue2-client/base-client/components/common/XFormTable/XFormTable'
|
267
|
-
import XAddForm from '@vue2-client/base-client/components/common/XAddForm/XAddForm'
|
268
|
-
import { postByServiceName } from '@vue2-client/services/api/restTools'
|
269
|
-
import { workFlowViewApi } from '@vue2-client/services/api/workFlow'
|
270
|
-
import { commonApi } from '@vue2-client/services/api'
|
271
|
-
import { formatDate } from '@vue2-client/utils/util'
|
272
|
-
import { mapState } from 'vuex'
|
273
|
-
import moment from 'moment'
|
274
|
-
import FilePreview from '@vue2-client/components/FilePreview'
|
275
|
-
import WorkFlowTimeline from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowTimeline.vue'
|
276
|
-
import { FileItem, ImageItem } from '@vue2-client/components/FileImageItem'
|
277
|
-
import WorkflowListResolution from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkflowListResolution'
|
278
|
-
import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
|
279
|
-
import * as util from '@vue2-client/utils/util'
|
280
|
-
import { getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
|
281
|
-
import LogicRunner from '@vue2-client/logic/LogicRunner'
|
282
|
-
import XTab from '@vue2-client/base-client/components/common/XTab/XTab.vue'
|
283
|
-
import WorkFlowPreview from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowPreview'
|
284
|
-
import WorkflowPersonSelector from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/components/WorkflowPersonSelector.vue'
|
285
|
-
|
286
|
-
export default {
|
287
|
-
name: 'WorkFlowHandle',
|
288
|
-
provide () {
|
289
|
-
return {
|
290
|
-
formDataChange: this.handleFormDataChange,
|
291
|
-
workflowHandleWrap: this.workflowHandleWrap
|
292
|
-
}
|
293
|
-
},
|
294
|
-
components: {
|
295
|
-
XTab,
|
296
|
-
WorkflowListResolution,
|
297
|
-
XAddNativeForm,
|
298
|
-
WorkFlowTimeline,
|
299
|
-
XFormTable,
|
300
|
-
XAddForm,
|
301
|
-
FilePreview,
|
302
|
-
FileItem,
|
303
|
-
ImageItem,
|
304
|
-
WorkFlowPreview,
|
305
|
-
WorkflowPersonSelector
|
306
|
-
},
|
307
|
-
computed: {
|
308
|
-
workflowHandleWrap () {
|
309
|
-
return this
|
310
|
-
},
|
311
|
-
...mapState('account', { currUser: 'user' }),
|
312
|
-
// 判断当前节点的分支状态
|
313
|
-
isBranchLastNode () {
|
314
|
-
// 默认返回值
|
315
|
-
const defaultResult = {
|
316
|
-
isBranchNode: false, // 是否为分支流程中的节点
|
317
|
-
isLastBranch: false // 是否为最后一个未完成的分支(需要选择下一环节人员)
|
318
|
-
}
|
319
|
-
|
320
|
-
// 如果是最后一步或没有下一步或者不能提交,则不是分支节点
|
321
|
-
if (this.lastStep || !this.nextBtnTo || !this.canSubmit) {
|
322
|
-
return defaultResult
|
323
|
-
}
|
324
|
-
|
325
|
-
// 检查下一个节点是否为分支退出节点
|
326
|
-
const nextStep = this.stepsDefine.find(step => step.id === this.nextBtnTo)
|
327
|
-
|
328
|
-
// 如果下一个节点的flowRole不是branchExit,说明不是分支的最后一个节点
|
329
|
-
if (!nextStep || nextStep.properties?.flowRole !== 'branchExit') {
|
330
|
-
return defaultResult
|
331
|
-
}
|
332
|
-
|
333
|
-
// 获取分支退出节点等待的所有分支步骤ID
|
334
|
-
const waitStepIds = nextStep.properties.waitStepIds || []
|
335
|
-
if (waitStepIds.length === 0) {
|
336
|
-
return {
|
337
|
-
isBranchNode: true,
|
338
|
-
isLastBranch: true // 如果没有等待步骤配置,默认认为是最后一个
|
339
|
-
}
|
340
|
-
}
|
341
|
-
|
342
|
-
// 当前步骤必须在等待列表中才算是分支节点
|
343
|
-
if (!waitStepIds.includes(this.activeStepId)) {
|
344
|
-
return defaultResult
|
345
|
-
}
|
346
|
-
|
347
|
-
// 检查除当前步骤外的其他分支步骤状态
|
348
|
-
const otherBranchSteps = waitStepIds.filter(stepId => stepId !== this.activeStepId)
|
349
|
-
|
350
|
-
// 判断其他所有分支步骤是否都已完成(状态为2)
|
351
|
-
const allOtherBranchesCompleted = otherBranchSteps.every(stepId => {
|
352
|
-
const step = this.stepsForChild.find(s => s.id === stepId)
|
353
|
-
return step && step.status === 2 // 已处理
|
354
|
-
})
|
355
|
-
|
356
|
-
return {
|
357
|
-
isBranchNode: true, // 当前节点是分支流程中的节点
|
358
|
-
isLastBranch: allOtherBranchesCompleted // 只有当其他所有分支都已完成时,当前分支才是最后一个
|
359
|
-
}
|
360
|
-
},
|
361
|
-
canSubmit () {
|
362
|
-
// 对于超级管理员直接认为可以提交
|
363
|
-
if (this.currUser.rolesnames.indexOf('超级管理员') > -1) {
|
364
|
-
return true
|
365
|
-
}
|
366
|
-
// currentStepId可能还没初始化,此处拿不到先返回false
|
367
|
-
if (!this.currentStepId) {
|
368
|
-
return false
|
369
|
-
}
|
370
|
-
const activeStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
371
|
-
// 如果当前选中节点不是正在进行的节点,则判断viewers权限
|
372
|
-
if (this.activeStepId !== this.currentStepId && activeStep != null && activeStep.status !== 1) {
|
373
|
-
// 历史节点为当前登录人操作则不做查看数据权限校验
|
374
|
-
if (activeStep.handler === this.currUser.name) {
|
375
|
-
return true
|
376
|
-
}
|
377
|
-
const viewers = activeStep?.properties?.otherProperty?.viewers ?? []
|
378
|
-
if (viewers.length > 0) {
|
379
|
-
// 使用some方法判断当前人员是否满足任一条件
|
380
|
-
return viewers.some(item => {
|
381
|
-
if (item.type === 'role') {
|
382
|
-
// 检查rolestr是否存在并包含指定角色
|
383
|
-
return this.currUser.rolestr && this.currUser.rolestr.split(',').includes(item.name)
|
384
|
-
}
|
385
|
-
if (item.type === 'department') {
|
386
|
-
// 检查depname是否存在并包含指定部门
|
387
|
-
return this.currUser.deps && this.currUser.deps.includes(item.name)
|
388
|
-
}
|
389
|
-
return false
|
390
|
-
})
|
391
|
-
} else {
|
392
|
-
return true
|
393
|
-
}
|
394
|
-
} else {
|
395
|
-
// 当前进行节点的数据
|
396
|
-
const step = this.stepsForChild.find(item => item.id === this.activeStepId)
|
397
|
-
// 检查角色和部门权限
|
398
|
-
if (step && step.properties && step.properties.chargePerson) {
|
399
|
-
// 如果当前节点的负责人选项中有设置选择人员 当前节点就只能由上一步设置的负责人操作
|
400
|
-
if (step.properties.chargePerson.needSelectPerson) {
|
401
|
-
return step.handler === this.currUser.name
|
402
|
-
}
|
403
|
-
if (step.properties.chargePerson.personList && step.properties.chargePerson.personList.length > 0) {
|
404
|
-
// 使用some方法判断当前人员是否满足任一条件
|
405
|
-
return step.properties.chargePerson.personList.some(item => {
|
406
|
-
if (item.type === 'role') {
|
407
|
-
// 检查rolestr是否存在并包含指定角色
|
408
|
-
return this.currUser.rolestr && this.currUser.rolestr.split(',').includes(item.name)
|
409
|
-
}
|
410
|
-
if (item.type === 'department') {
|
411
|
-
// 检查parentname是否存在并包含指定部门
|
412
|
-
return this.currUser.parentname && this.currUser.parentname.includes(item.name)
|
413
|
-
}
|
414
|
-
return false
|
415
|
-
})
|
416
|
-
}
|
417
|
-
}
|
418
|
-
|
419
|
-
// 检查handler是否包含当前用户
|
420
|
-
if (step && step.handler) {
|
421
|
-
return step.handler.includes(this.currUser.name)
|
422
|
-
}
|
423
|
-
}
|
424
|
-
return false
|
425
|
-
},
|
426
|
-
formPreviewNoFileData () {
|
427
|
-
return this.formCompletedDataPreview.data.filter(item => item.label !== '附件上传')
|
428
|
-
}
|
429
|
-
},
|
430
|
-
data () {
|
431
|
-
return {
|
432
|
-
// 显示供用户填写的当前步骤表单
|
433
|
-
showForm: false,
|
434
|
-
// 显示步骤的tab页
|
435
|
-
showTab: false,
|
436
|
-
// tab页的配置
|
437
|
-
tabDesigner: undefined,
|
438
|
-
// 当前步骤表单标题
|
439
|
-
formTitle: '',
|
440
|
-
// 当前步骤表单定义Json
|
441
|
-
stepDefine: [],
|
442
|
-
// 当前步骤
|
443
|
-
currentStep: undefined,
|
444
|
-
// 当前步骤完成状态
|
445
|
-
stepDone: false,
|
446
|
-
// 所有节点连通数据
|
447
|
-
directions: [],
|
448
|
-
// 所有流程定义数据
|
449
|
-
stepsDefine: [],
|
450
|
-
// 当前步骤能通向的节点
|
451
|
-
currentDirections: [],
|
452
|
-
// 当前节点id
|
453
|
-
currentStepId: undefined,
|
454
|
-
// 当前活动节点 id
|
455
|
-
activeStepId: 1,
|
456
|
-
// 下一步按钮显示
|
457
|
-
showNextBtn: false,
|
458
|
-
// 回退按钮显示
|
459
|
-
showPrevBtn: false,
|
460
|
-
// 跳过按钮显示
|
461
|
-
showStepNextBtn: false,
|
462
|
-
// 定义三个按钮气泡提示内容
|
463
|
-
preBtnTitle: '',
|
464
|
-
preBtnText: [],
|
465
|
-
nextBtnTitle: '',
|
466
|
-
stepNextBtnTitle: '',
|
467
|
-
stepNextBtnText: [],
|
468
|
-
// 控制三个按钮跳转目标
|
469
|
-
preBtnTo: undefined,
|
470
|
-
nextBtnTo: undefined,
|
471
|
-
stepNextBtnTo: undefined,
|
472
|
-
// 控制当前标签页显示
|
473
|
-
activeKey: '1',
|
474
|
-
// 之前的节点是否激活
|
475
|
-
beforeStepActive: false,
|
476
|
-
// 之前节点中的数据
|
477
|
-
beforeStepData: [],
|
478
|
-
// 用于将已有数据,填回x-add表单中
|
479
|
-
formCompletedData: {},
|
480
|
-
// 用于展示提交的数据
|
481
|
-
formCompletedDataPreview: null,
|
482
|
-
// 切换至目标流程时,目标流程定义
|
483
|
-
targetStepDefine: [],
|
484
|
-
// 控制历史记录加载
|
485
|
-
loadingHistory: true,
|
486
|
-
// 控制表单校验
|
487
|
-
formValid: false,
|
488
|
-
// 备忘
|
489
|
-
note: '',
|
490
|
-
backNote: '', // 新增退回原因专用变量
|
491
|
-
// 是否是最后一步
|
492
|
-
lastStep: false,
|
493
|
-
// 存储每一步骤填表人和时间数据
|
494
|
-
stepsExtraInfo: [],
|
495
|
-
// 控制基础信息页流程展示加载
|
496
|
-
loading: true,
|
497
|
-
createQueryVisible: false,
|
498
|
-
// 激活的步骤名
|
499
|
-
activeStepName: '',
|
500
|
-
stepsParse: undefined,
|
501
|
-
// 下一步处理人选择框数据
|
502
|
-
chargePersonOptions: [],
|
503
|
-
// 已选择下一步处理人
|
504
|
-
checkedChargePerson: undefined,
|
505
|
-
// 下一步截止时间
|
506
|
-
deadline: this.getDefaultDeadline(),
|
507
|
-
deadlineValidateStatus: '',
|
508
|
-
deadlineHelp: '',
|
509
|
-
// 当前任务是否延期
|
510
|
-
// taskIsOverdue: moment().isAfter(this.completeTime, 'day'),
|
511
|
-
// 操作类型,提交到下一步或跳过
|
512
|
-
operationType: 'submit',
|
513
|
-
// 获取微信推送是否成功信息
|
514
|
-
information: [],
|
515
|
-
// 是否需要选择人员
|
516
|
-
needSelectPerson: true,
|
517
|
-
// 下一环节人员信息
|
518
|
-
chargePerson: {},
|
519
|
-
// 动态按钮配置
|
520
|
-
buttonGroup: null,
|
521
|
-
// 分支节点相关数据
|
522
|
-
branchNodes: [], // 需要选择人员的分支节点列表
|
523
|
-
branchChargePersons: {}, // 分支节点人员选择 格式:{stepId: personId}
|
524
|
-
needMultipleBranchSelection: false, // 是否需要为多个分支节点预先选择人员(包含WF_RESULT的条件分支或并行分支)
|
525
|
-
calculatedTargetNode: null, // 前台计算出的目标节点
|
526
|
-
currentBranchActions: null // 缓存当前的分支动作,避免重复调用
|
527
|
-
}
|
528
|
-
},
|
529
|
-
async mounted () {
|
530
|
-
await this.init()
|
531
|
-
// this.checkDeadline()
|
532
|
-
},
|
533
|
-
props: {
|
534
|
-
workflowId: {
|
535
|
-
type: [String, Number],
|
536
|
-
required: true
|
537
|
-
},
|
538
|
-
visible: {
|
539
|
-
type: Boolean,
|
540
|
-
default: false
|
541
|
-
},
|
542
|
-
stepsForChild: {
|
543
|
-
type: Array,
|
544
|
-
required: true
|
545
|
-
},
|
546
|
-
workflowState: {
|
547
|
-
type: [Boolean, Number],
|
548
|
-
required: true
|
549
|
-
},
|
550
|
-
completeTime: {
|
551
|
-
type: String,
|
552
|
-
required: true
|
553
|
-
},
|
554
|
-
taskName: {
|
555
|
-
type: String,
|
556
|
-
required: true
|
557
|
-
},
|
558
|
-
details: {
|
559
|
-
type: Object,
|
560
|
-
required: true
|
561
|
-
},
|
562
|
-
// 展开详情初始化的节点
|
563
|
-
// 适用于不让第一个节点默认展示的情况
|
564
|
-
initStepId: {
|
565
|
-
type: [String, Number],
|
566
|
-
required: false,
|
567
|
-
default: null
|
568
|
-
},
|
569
|
-
renderCurrentNode: {
|
570
|
-
type: Boolean,
|
571
|
-
default: true
|
572
|
-
}
|
573
|
-
},
|
574
|
-
methods: {
|
575
|
-
init () {
|
576
|
-
this.getCurrentStep()
|
577
|
-
},
|
578
|
-
onClose () {
|
579
|
-
this.activeStepId = this.currentStepId
|
580
|
-
this.checkedChargePerson = undefined
|
581
|
-
this.loadingHistory = true
|
582
|
-
this.currentStepId = undefined
|
583
|
-
this.directions = []
|
584
|
-
this.currentDirections = []
|
585
|
-
this.preBtnText = []
|
586
|
-
this.stepNextBtnText = []
|
587
|
-
this.stepsExtraInfo = []
|
588
|
-
this.loading = true
|
589
|
-
this.showNextBtn = false
|
590
|
-
this.showStepNextBtn = false
|
591
|
-
this.showPrevBtn = false
|
592
|
-
this.stepDone = false
|
593
|
-
this.formCompletedData = {}
|
594
|
-
this.formCompletedDataPreview = null
|
595
|
-
this.operationType = 'submit'
|
596
|
-
|
597
|
-
// 清理分支节点相关数据
|
598
|
-
this.branchNodes = []
|
599
|
-
this.branchChargePersons = {}
|
600
|
-
this.needMultipleBranchSelection = false
|
601
|
-
this.calculatedTargetNode = null
|
602
|
-
this.currentBranchActions = null
|
603
|
-
},
|
604
|
-
async showQueryFormItemFunc () {
|
605
|
-
if (this.attr.showQueryFormItemFunc) {
|
606
|
-
const obj = executeStrFunctionByContext(this, this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
|
607
|
-
// 判断是 bool 还是 obj 兼容
|
608
|
-
if (typeof obj === 'boolean') {
|
609
|
-
this.show = obj
|
610
|
-
} else if (obj && typeof obj === 'object') {
|
611
|
-
// obj 是一个对象,并且不是数组
|
612
|
-
this.show = obj?.show
|
613
|
-
this.readOnly = obj?.readOnly
|
614
|
-
}
|
615
|
-
} else {
|
616
|
-
this.show = true
|
617
|
-
}
|
618
|
-
},
|
619
|
-
// 获取单个步骤的定义
|
620
|
-
getSingleStepDefine (name) {
|
621
|
-
for (const step of this.stepsDefine) {
|
622
|
-
if (name === step.name) {
|
623
|
-
return step.properties.form
|
624
|
-
}
|
625
|
-
}
|
626
|
-
},
|
627
|
-
// 日期格式化
|
628
|
-
format (date, format) {
|
629
|
-
return formatDate(date, format)
|
630
|
-
},
|
631
|
-
// 获取当前步骤
|
632
|
-
getCurrentStep () {
|
633
|
-
return postByServiceName(workFlowViewApi.getWorkFlowCurrentSubState, {
|
634
|
-
workflowId: this.workflowId
|
635
|
-
})
|
636
|
-
.then(res => {
|
637
|
-
// 优先级:主动传入的 > 获取到的
|
638
|
-
this.currentStepId = this.initStepId || res.id
|
639
|
-
|
640
|
-
// 如果指定了具体节点,同时设置activeStepId
|
641
|
-
if (this.initStepId) {
|
642
|
-
this.activeStepId = this.initStepId
|
643
|
-
}
|
644
|
-
|
645
|
-
const currentStep = this.stepsForChild.find(item => item.id === res.id)
|
646
|
-
res.state = currentStep.name
|
647
|
-
// 获取到当前步骤后复制下一步时间
|
648
|
-
this.deadline = this.getDefaultDeadline(currentStep.properties?.otherProperty?.nextNodeInterval)
|
649
|
-
this.currentStep = res
|
650
|
-
this.getDirection()
|
651
|
-
}, err => {
|
652
|
-
console.log(err)
|
653
|
-
})
|
654
|
-
},
|
655
|
-
// 完工按钮
|
656
|
-
async lastStepNextClick () {
|
657
|
-
this.$refs.xAddForm.asyncSubmit().then((res) => {
|
658
|
-
this.submitForm(res).then(_ => {
|
659
|
-
postByServiceName(workFlowViewApi.afterWorkFlowFinalStepSubmit, {
|
660
|
-
workflowId: this.workflowId,
|
661
|
-
stepId: this.currentStepId,
|
662
|
-
submitUser: this.currUser.name,
|
663
|
-
submitUserId: this.currUser.id
|
664
|
-
}).then(_res => {
|
665
|
-
this.saveWorkflowLog('确认完工', '最后一步: ' + this.getStepNameByStepId(this.currentStepId), { notes: this.note.trim() })
|
666
|
-
this.$message.success('已完工!')
|
667
|
-
this.loading = true
|
668
|
-
this.loadingHistory = true
|
669
|
-
this.onClose()
|
670
|
-
this.$emit('success', { note: this.note.trim(), form: res.realForm, workflowId: this.workflowId })
|
671
|
-
},
|
672
|
-
() => {
|
673
|
-
this.$message.error('提交失败!')
|
674
|
-
}
|
675
|
-
)
|
676
|
-
})
|
677
|
-
}).catch(err => {
|
678
|
-
if (err && err.message === 'Form validation failed') {
|
679
|
-
this.$message.error('请检查表单必填项!')
|
680
|
-
} else {
|
681
|
-
// 对于其他错误,继续向上抛出
|
682
|
-
throw err
|
683
|
-
}
|
684
|
-
})
|
685
|
-
},
|
686
|
-
// 三个按钮点击后逻辑
|
687
|
-
async nextClick () {
|
688
|
-
// 检查是否为非最后分支节点
|
689
|
-
const branchStatus = this.isBranchLastNode
|
690
|
-
const isWaitingBranch = branchStatus.isBranchNode && !branchStatus.isLastBranch
|
691
|
-
|
692
|
-
const extraData = this.getApplyStepExtraData(this.nextBtnTo)
|
693
|
-
if (!extraData) {
|
694
|
-
return
|
695
|
-
}
|
696
|
-
|
697
|
-
// 确认对话框
|
698
|
-
const confirmContent = isWaitingBranch
|
699
|
-
? '确定完成当前分支么?完成后将等待其他分支,不会立即流转到下一环节。'
|
700
|
-
: '确定提交么?提交之后数据不可更改!'
|
701
|
-
|
702
|
-
await new Promise(resolve => {
|
703
|
-
this.$confirm({
|
704
|
-
title: '提交确认',
|
705
|
-
content: confirmContent,
|
706
|
-
onOk () {
|
707
|
-
resolve()
|
708
|
-
return Promise.resolve()
|
709
|
-
}
|
710
|
-
})
|
711
|
-
})
|
712
|
-
|
713
|
-
this.$refs.xAddForm.asyncSubmit().then(res => {
|
714
|
-
this.submitForm(res).then(_ => {
|
715
|
-
extraData.form = res.realForm
|
716
|
-
postByServiceName(workFlowViewApi.submitToNextStep, extraData)
|
717
|
-
.then(
|
718
|
-
() => {
|
719
|
-
let successMessage = '提交成功'
|
720
|
-
|
721
|
-
// 只有非等待分支节点才保存工作流日志
|
722
|
-
if (!isWaitingBranch) {
|
723
|
-
const branchStatus = this.isBranchLastNode
|
724
|
-
const operation = branchStatus.isBranchNode && branchStatus.isLastBranch ? '分支汇合' : '提交'
|
725
|
-
|
726
|
-
const extra = {
|
727
|
-
setHandler: this.getStepHandler(),
|
728
|
-
setDeadline: this.deadline,
|
729
|
-
notes: this.note.trim()
|
730
|
-
}
|
731
|
-
this.saveWorkflowLog(operation, this.generateBranchStepChangeText(this.currentStepId), extra)
|
732
|
-
} else {
|
733
|
-
successMessage = '分支完成,等待其他分支完成后自动汇合'
|
734
|
-
}
|
735
|
-
|
736
|
-
this.$message.success(successMessage)
|
737
|
-
this.loading = true
|
738
|
-
this.loadingHistory = true
|
739
|
-
this.$emit('nextClick', {
|
740
|
-
note: this.note.trim(),
|
741
|
-
form: res.realForm,
|
742
|
-
workflowId: this.workflowId,
|
743
|
-
isBranchWaiting: isWaitingBranch, // 标记是否为分支等待状态
|
744
|
-
...this.generateStepChange(this.currentStepId, this.nextBtnTo)
|
745
|
-
})
|
746
|
-
this.$emit('refresh')
|
747
|
-
this.onClose()
|
748
|
-
this.init()
|
749
|
-
},
|
750
|
-
err => {
|
751
|
-
this.$message.error('提交失败!')
|
752
|
-
console.log(err)
|
753
|
-
}
|
754
|
-
)
|
755
|
-
})
|
756
|
-
}).catch((err) => {
|
757
|
-
if (err && err.message === 'Form validation failed') {
|
758
|
-
this.$message.error('请检查表单必填项!')
|
759
|
-
} else {
|
760
|
-
// 对于其他错误,继续向上抛出
|
761
|
-
throw err
|
762
|
-
}
|
763
|
-
})
|
764
|
-
},
|
765
|
-
async preClick () {
|
766
|
-
const notes = this.backNote.trim()
|
767
|
-
if (!notes) {
|
768
|
-
this.$message.error('退回请在备注中填写理由')
|
769
|
-
return
|
770
|
-
}
|
771
|
-
return postByServiceName(workFlowViewApi.updateWorkFlowState, {
|
772
|
-
stepId: this.preBtnTo,
|
773
|
-
workflowId: this.workflowId,
|
774
|
-
type: 'back'
|
775
|
-
})
|
776
|
-
.then(
|
777
|
-
res => {
|
778
|
-
this.saveWorkflowLog('退回', this.generateStepChangeText(this.currentStepId, this.preBtnTo), { notes })
|
779
|
-
this.$message.success('退回成功')
|
780
|
-
this.backNote = '' // 退回成功后清空退回原因
|
781
|
-
this.loading = true
|
782
|
-
this.loadingHistory = true
|
783
|
-
this.currentStepId = this.preBtnTo
|
784
|
-
this.activeStepId = this.preBtnTo
|
785
|
-
|
786
|
-
// 新增:重置按钮状态
|
787
|
-
this.stepDone = false
|
788
|
-
this.beforeStepActive = false
|
789
|
-
this.operationType = 'submit'
|
790
|
-
|
791
|
-
this.$emit('refresh')
|
792
|
-
this.onClose()
|
793
|
-
this.init()
|
794
|
-
},
|
795
|
-
err => {
|
796
|
-
this.$message.error('退回失败!')
|
797
|
-
console.log(err)
|
798
|
-
}
|
799
|
-
)
|
800
|
-
},
|
801
|
-
async stepNextClick () {
|
802
|
-
const extraData = this.getApplyStepExtraData(this.stepNextBtnTo)
|
803
|
-
if (!extraData) {
|
804
|
-
return
|
805
|
-
}
|
806
|
-
this.$refs.xAddForm.asyncSubmit().then(res => {
|
807
|
-
this.submitForm(res).then(_ => {
|
808
|
-
extraData.form = res.realForm
|
809
|
-
postByServiceName(workFlowViewApi.submitToNextStep, extraData)
|
810
|
-
.then(
|
811
|
-
() => {
|
812
|
-
const extra = {
|
813
|
-
setHandler: this.getStepHandler(),
|
814
|
-
setDeadline: this.deadline,
|
815
|
-
notes: this.note.trim()
|
816
|
-
}
|
817
|
-
this.saveWorkflowLog('跳过', this.generateBranchStepChangeText(this.currentStepId), extra)
|
818
|
-
this.$message.success('提交成功')
|
819
|
-
this.$emit('nextClick', {
|
820
|
-
note: this.note.trim(),
|
821
|
-
form: res.realForm,
|
822
|
-
workflowId: this.workflowId,
|
823
|
-
...this.generateStepChange(this.currentStepId, this.stepNextBtnTo)
|
824
|
-
})
|
825
|
-
this.loading = true
|
826
|
-
this.loadingHistory = true
|
827
|
-
this.$emit('refresh')
|
828
|
-
this.onClose()
|
829
|
-
this.init()
|
830
|
-
},
|
831
|
-
err => {
|
832
|
-
this.$message.error('提交失败!')
|
833
|
-
console.log(err)
|
834
|
-
}
|
835
|
-
)
|
836
|
-
})
|
837
|
-
}).catch(err => {
|
838
|
-
if (err && err.message === 'Form validation failed') {
|
839
|
-
this.$message.error('请检查表单必填项!')
|
840
|
-
} else {
|
841
|
-
// 对于其他错误,继续向上抛出
|
842
|
-
throw err
|
843
|
-
}
|
844
|
-
})
|
845
|
-
},
|
846
|
-
// 获取当前步骤节点,连通的节点
|
847
|
-
async getDirection () {
|
848
|
-
// 获取流程定义
|
849
|
-
return postByServiceName(workFlowViewApi.getWorkFlowDefine, {
|
850
|
-
id: this.workflowId
|
851
|
-
})
|
852
|
-
.then(async res => {
|
853
|
-
this.directions = []
|
854
|
-
this.stepsDefine = res.steps
|
855
|
-
await this.resolveDirections()
|
856
|
-
this.resolveStep()
|
857
|
-
}, err => {
|
858
|
-
console.log(err)
|
859
|
-
})
|
860
|
-
},
|
861
|
-
// 分析当前节点,能通向的节点
|
862
|
-
async resolveDirections () {
|
863
|
-
const currentStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
864
|
-
if (currentStep?.properties?.actions) {
|
865
|
-
this.currentDirections = currentStep.properties.actions
|
866
|
-
}
|
867
|
-
// 判断是否是最后ige节点
|
868
|
-
this.lastStep = (currentStep?.properties?.actions || []).filter(item => {
|
869
|
-
return item.type !== 'back'
|
870
|
-
}).length === 0
|
871
|
-
|
872
|
-
// 处理跳转按钮
|
873
|
-
this.workflowControl()
|
874
|
-
|
875
|
-
if (!this.lastStep) {
|
876
|
-
// 分析分支节点并设置智能人员选择
|
877
|
-
await this.analyzeBranchNodes()
|
878
|
-
}
|
879
|
-
},
|
880
|
-
// 根据步骤id获取步骤名称
|
881
|
-
getStepNameByStepId (stepId) {
|
882
|
-
return this.stepsDefine.find(item => item.id === stepId)?.name
|
883
|
-
},
|
884
|
-
// 根据步骤id获取步骤状态
|
885
|
-
getStepStatusByStepId (stepId) {
|
886
|
-
return this.stepsForChild.find(item => item.id === stepId)?.status
|
887
|
-
},
|
888
|
-
// 表单提交的回调
|
889
|
-
submitForm (obj) {
|
890
|
-
this.formValid = true
|
891
|
-
const formData = obj.realForm
|
892
|
-
const time = this.format(new Date(), 'yyyy-MM-dd hh:mm:ss')
|
893
|
-
return postByServiceName(workFlowViewApi.saveWorkFlowStepFormData, {
|
894
|
-
workflowId: this.workflowId,
|
895
|
-
stepId: this.activeStepId,
|
896
|
-
form: formData,
|
897
|
-
data: time,
|
898
|
-
handler: this.currUser.name,
|
899
|
-
note: this.note.trim()
|
900
|
-
})
|
901
|
-
.then(
|
902
|
-
res => {
|
903
|
-
console.log('表单提交成功')
|
904
|
-
this.note = ''
|
905
|
-
this.showForm = false
|
906
|
-
this.stepDone = true
|
907
|
-
},
|
908
|
-
err => {
|
909
|
-
this.$message.error('保存失败,请检查后重试')
|
910
|
-
console.log(err)
|
911
|
-
}
|
912
|
-
)
|
913
|
-
},
|
914
|
-
// 获取当前步骤定义内容,构建组件
|
915
|
-
async buildComp (stepId) {
|
916
|
-
const properties = this.stepsDefine.find(item => item.id === stepId).properties
|
917
|
-
// 表单的渲染
|
918
|
-
if (properties.form && properties.form.formJson) {
|
919
|
-
this.stepDefine = properties.form.formJson
|
920
|
-
this.showForm = true
|
921
|
-
this.$nextTick(() => {
|
922
|
-
this.$refs.xAddForm && this.$refs.xAddForm.init({
|
923
|
-
...properties.form,
|
924
|
-
businessType: '修改',
|
925
|
-
formItems: this.stepDefine,
|
926
|
-
layout: properties.form.xAddFormLayout,
|
927
|
-
showSubmitBtn: false
|
928
|
-
})
|
929
|
-
// 初始化的数据渲染(流程第一步)
|
930
|
-
console.log('导入的原始数据-json', this.stepsForChild[0].f_data)
|
931
|
-
console.log('转换后的数据-对象', JSON.parse(this.stepsForChild[0].f_data))
|
932
|
-
if (stepId === 1) {
|
933
|
-
this.$refs.xAddForm.setForm(JSON.parse(this.stepsForChild[0].f_data))
|
934
|
-
}
|
935
|
-
})
|
936
|
-
} else {
|
937
|
-
this.showForm = false
|
938
|
-
}
|
939
|
-
// Tab的渲染
|
940
|
-
this.tabDesigner = properties.tabDesigner
|
941
|
-
this.showTab = !!this.tabDesigner
|
942
|
-
// 以当前激活节点分析节点
|
943
|
-
await this.resolveDirections()
|
944
|
-
this.resolveStep()
|
945
|
-
},
|
946
|
-
// 根据当前节点,判断之后流程,以及按钮的显示
|
947
|
-
workflowControl () {
|
948
|
-
// 重置所有控制数据为默认值,避免之前状态的影响
|
949
|
-
this.showNextBtn = false
|
950
|
-
this.nextBtnTo = undefined
|
951
|
-
this.nextBtnTitle = ''
|
952
|
-
this.showStepNextBtn = false
|
953
|
-
this.stepNextBtnTo = undefined
|
954
|
-
this.stepNextBtnTitle = ''
|
955
|
-
this.stepNextBtnText = []
|
956
|
-
this.showPrevBtn = false
|
957
|
-
this.preBtnTo = undefined
|
958
|
-
this.preBtnTitle = ''
|
959
|
-
this.preBtnText = []
|
960
|
-
|
961
|
-
// 分类收集不同类型的actions
|
962
|
-
const submitActions = this.currentDirections.filter(item => item.type === 'submit')
|
963
|
-
const conditionalActions = this.currentDirections.filter(item => item.type === 'conditionalBranch')
|
964
|
-
const parallelActions = this.currentDirections.filter(item => item.type === 'parallelBranch')
|
965
|
-
const skipActions = this.currentDirections.filter(item => item.type === 'skip')
|
966
|
-
const backActions = this.currentDirections.filter(item => item.type === 'back')
|
967
|
-
|
968
|
-
// 处理提交按钮 - 优先级:submit > conditionalBranch > parallelBranch
|
969
|
-
if (submitActions.length > 0) {
|
970
|
-
this.showNextBtn = true
|
971
|
-
this.nextBtnTo = submitActions[0].to // 如果有多个submit,取第一个作为主要跳转目标
|
972
|
-
if (submitActions.length === 1) {
|
973
|
-
this.nextBtnTitle = '进行下一环节:' + this.getStepNameByStepId(submitActions[0].to)
|
974
|
-
} else {
|
975
|
-
this.nextBtnTitle = '将进入以下环节:' + submitActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
976
|
-
}
|
977
|
-
} else if (conditionalActions.length > 0) {
|
978
|
-
this.showNextBtn = true
|
979
|
-
this.nextBtnTo = conditionalActions[0].to // 条件分支的第一个作为主要跳转目标
|
980
|
-
const targetSteps = conditionalActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
981
|
-
this.nextBtnTitle = '后台判断后跳转到:' + targetSteps
|
982
|
-
} else if (parallelActions.length > 0) {
|
983
|
-
this.showNextBtn = true
|
984
|
-
this.nextBtnTo = parallelActions[0].to // 并行分支的第一个作为主要跳转目标
|
985
|
-
const targetSteps = parallelActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
986
|
-
this.nextBtnTitle = '将并行进入以下分支:' + targetSteps
|
987
|
-
}
|
988
|
-
|
989
|
-
// 处理跳过按钮
|
990
|
-
if (skipActions.length > 0) {
|
991
|
-
this.showStepNextBtn = true
|
992
|
-
this.stepNextBtnTo = skipActions[0].to
|
993
|
-
if (skipActions.length === 1) {
|
994
|
-
this.stepNextBtnTitle = '跳至:' + this.getStepNameByStepId(skipActions[0].to) + '环节'
|
995
|
-
this.stepNextBtnText.push('将跳过以下环节:')
|
996
|
-
for (let i = this.currentStepId; i < skipActions[0].to - 1; i++) {
|
997
|
-
this.stepNextBtnText.push(this.stepsDefine[i].name)
|
998
|
-
}
|
999
|
-
} else {
|
1000
|
-
const targetSteps = skipActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
1001
|
-
this.stepNextBtnTitle = '跳至:' + targetSteps
|
1002
|
-
}
|
1003
|
-
}
|
1004
|
-
|
1005
|
-
// 处理退回按钮
|
1006
|
-
if (backActions.length > 0) {
|
1007
|
-
const backAction = backActions[0] // 通常只有一个back action
|
1008
|
-
for (let i = this.currentStepId - 1; i > 0; i--) {
|
1009
|
-
if (backAction.to >= i && this.stepsForChild.find(item => item.id === i)?.handler) {
|
1010
|
-
this.preBtnTo = i
|
1011
|
-
this.preBtnTitle = '回退至:' + this.getStepNameByStepId(i) + '环节'
|
1012
|
-
this.showPrevBtn = true
|
1013
|
-
break
|
1014
|
-
} else {
|
1015
|
-
this.preBtnText.push(this.getStepNameByStepId(i))
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
if (this.preBtnText.length) {
|
1019
|
-
this.preBtnText.unshift('将跳过以下环节:')
|
1020
|
-
}
|
1021
|
-
}
|
1022
|
-
},
|
1023
|
-
// 获取表单字段实际值
|
1024
|
-
getRealKey (key, isHandleFormKey) {
|
1025
|
-
if (key === 'selected_id') return key
|
1026
|
-
if (isHandleFormKey) {
|
1027
|
-
return key.substring(key.indexOf('_') + 1)
|
1028
|
-
} else {
|
1029
|
-
return key
|
1030
|
-
}
|
1031
|
-
},
|
1032
|
-
// 加载完成
|
1033
|
-
resolveStep () {
|
1034
|
-
// 获取当前步骤的按钮组配置
|
1035
|
-
const currentStep = this.stepsDefine.find(item => item.id === this.activeStepId)
|
1036
|
-
if (currentStep && currentStep.properties && currentStep.properties.buttonGroup) {
|
1037
|
-
this.buttonGroup = currentStep.properties.buttonGroup
|
1038
|
-
} else {
|
1039
|
-
this.buttonGroup = null
|
1040
|
-
}
|
1041
|
-
this.loading = false
|
1042
|
-
},
|
1043
|
-
// 流程图组件给当前组件传值用,stepNo为用户点击的非当前步骤
|
1044
|
-
async activeStep (stepId) {
|
1045
|
-
// 开启加载
|
1046
|
-
this.loadingHistory = true
|
1047
|
-
this.activeStepId = stepId
|
1048
|
-
// 获取激活节点的步骤名
|
1049
|
-
this.activeStepName = this.getStepNameByStepId(stepId)
|
1050
|
-
const status = this.getStepStatusByStepId(stepId)
|
1051
|
-
// 清空回显数据
|
1052
|
-
this.formCompletedData = {}
|
1053
|
-
let formCompletedDataPreview = null
|
1054
|
-
this.getStepDefine(stepId)
|
1055
|
-
// 判断激活的节点,是不是待完成节点 (当前节点或者 当前节点状态是1的)
|
1056
|
-
if ((this.activeStepName !== this.currentStep.state && status !== 1) || this.workflowState) {
|
1057
|
-
// 获取激活节点历史数据,和字段定义
|
1058
|
-
await this.getCompletedFormData(stepId)
|
1059
|
-
// 将回显数据拷贝,避免引用传递
|
1060
|
-
formCompletedDataPreview = JSON.parse(JSON.stringify(this.formCompletedData))
|
1061
|
-
// 使用字段定义中内容,将回显数据的列名,替换为定义的中文名
|
1062
|
-
// 调整逻辑:formData中只显示流程配置表单中定义过的显示列,多余冗余的存储列不进行页面展示
|
1063
|
-
const formDataArr = []
|
1064
|
-
const dataObj = formCompletedDataPreview.data || {}
|
1065
|
-
const currentStepDefine = this.stepsDefine.find(item => item.id === stepId)
|
1066
|
-
const isKeyHandle = currentStepDefine?.properties?.form?.isKeyHandle || false
|
1067
|
-
for (let i = 0; i < this.targetStepDefine.length; i++) {
|
1068
|
-
const stepDefine = this.targetStepDefine[i]
|
1069
|
-
const key = this.getRealKey(stepDefine.model, isKeyHandle)
|
1070
|
-
if (Object.prototype.hasOwnProperty.call(dataObj, key)) {
|
1071
|
-
// 历史表单内容根据流程中配置的表单项顺序进行渲染,需要兼容表单项展示函数
|
1072
|
-
if (stepDefine.showFormItemFunc && !(await this.showFormItemFunc(stepDefine.showFormItemFunc, dataObj))) {
|
1073
|
-
continue
|
1074
|
-
}
|
1075
|
-
let value = dataObj[key]
|
1076
|
-
// 字典值处理
|
1077
|
-
if (stepDefine.formType === 'select' && stepDefine.selectType === 'key') {
|
1078
|
-
const dictList = this.$appdata.getDictionaryList(stepDefine.selectKey)
|
1079
|
-
const dictItem = dictList.find(item => item.value === value)
|
1080
|
-
value = dictItem ? dictItem.label : value
|
1081
|
-
}
|
1082
|
-
formDataArr.push({ label: stepDefine.name, value })
|
1083
|
-
}
|
1084
|
-
}
|
1085
|
-
// 如果一个都没匹配上,兼容旧逻辑:把原对象转成数组
|
1086
|
-
if (formDataArr.length === 0 && dataObj && typeof dataObj === 'object') {
|
1087
|
-
for (const key in dataObj) {
|
1088
|
-
if (Object.prototype.hasOwnProperty.call(dataObj, key)) {
|
1089
|
-
formDataArr.push({ label: key, value: dataObj[key] })
|
1090
|
-
}
|
1091
|
-
}
|
1092
|
-
}
|
1093
|
-
formCompletedDataPreview.data = formDataArr.length > 0 ? formDataArr : null
|
1094
|
-
if (!formCompletedDataPreview.data) {
|
1095
|
-
formCompletedDataPreview.data = null
|
1096
|
-
}
|
1097
|
-
// 备注
|
1098
|
-
formCompletedDataPreview.note = this.stepsForChild.find(item => item.id === stepId)?.note
|
1099
|
-
if (!formCompletedDataPreview.data && !formCompletedDataPreview.files.length && !formCompletedDataPreview.images.length && !formCompletedDataPreview.note) {
|
1100
|
-
formCompletedDataPreview = {}
|
1101
|
-
}
|
1102
|
-
this.formCompletedDataPreview = formCompletedDataPreview
|
1103
|
-
// 渲染已完成步骤的Tab
|
1104
|
-
const properties = this.stepsDefine.find(item => item.id === stepId).properties
|
1105
|
-
this.tabDesigner = properties.tabDesigner
|
1106
|
-
this.showTab = !!this.tabDesigner
|
1107
|
-
// 完成
|
1108
|
-
this.loadingHistory = false
|
1109
|
-
this.beforeStepActive = this.activeStepName !== this.currentStep.state
|
1110
|
-
} else {
|
1111
|
-
this.loadingHistory = false
|
1112
|
-
this.beforeStepActive = false
|
1113
|
-
if (!this.renderCurrentNode) {
|
1114
|
-
this.formCompletedDataPreview = null
|
1115
|
-
this.showTab = false
|
1116
|
-
this.beforeStepActive = true
|
1117
|
-
return
|
1118
|
-
}
|
1119
|
-
await this.buildComp(this.activeStepId)
|
1120
|
-
}
|
1121
|
-
},
|
1122
|
-
// 获取已经完成步骤的数据
|
1123
|
-
getCompletedFormData (stepId) {
|
1124
|
-
return postByServiceName(workFlowViewApi.getWorkFlowCompletedStepData, {
|
1125
|
-
workflowId: this.workflowId,
|
1126
|
-
stepId: stepId
|
1127
|
-
})
|
1128
|
-
.then(
|
1129
|
-
res => {
|
1130
|
-
this.formCompletedData = res
|
1131
|
-
},
|
1132
|
-
err => {
|
1133
|
-
console.log(err)
|
1134
|
-
}
|
1135
|
-
)
|
1136
|
-
},
|
1137
|
-
// 获取步骤定义表中,当前步骤定义
|
1138
|
-
getStepDefine (stepId) {
|
1139
|
-
const stepName = this.getStepNameByStepId(stepId)
|
1140
|
-
this.targetStepDefine = this.getSingleStepDefine(stepName).formJson
|
1141
|
-
},
|
1142
|
-
// 获取提交步骤的额外数据
|
1143
|
-
getApplyStepExtraData (stepId) {
|
1144
|
-
// 验证人员选择 - 只有在需要显示人员选择器的情况下才验证
|
1145
|
-
// 判断条件与模板中的 WorkflowPersonSelector 显示条件保持一致
|
1146
|
-
const shouldShowPersonSelector = !this.isBranchLastNode.isBranchNode || this.isBranchLastNode.isLastBranch
|
1147
|
-
|
1148
|
-
if (shouldShowPersonSelector && this.needSelectPerson) {
|
1149
|
-
if (this.needMultipleBranchSelection) {
|
1150
|
-
// 多分支情况:检查是否所有需要的分支都选择了人员
|
1151
|
-
const missingSelections = this.branchNodes.filter(node => !this.branchChargePersons[node.stepId])
|
1152
|
-
if (missingSelections.length > 0) {
|
1153
|
-
const missingNames = missingSelections.map(node => node.stepName).join('、')
|
1154
|
-
this.$message.error(`请设置以下节点的处理人:${missingNames}`)
|
1155
|
-
return false
|
1156
|
-
}
|
1157
|
-
} else {
|
1158
|
-
// 单分支情况:检查是否选择了处理人
|
1159
|
-
if (!this.checkedChargePerson) {
|
1160
|
-
this.$message.error('请设置下一环节处理人')
|
1161
|
-
return false
|
1162
|
-
}
|
1163
|
-
}
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
// 统一获取目标步骤IDs
|
1167
|
-
let stepIds = []
|
1168
|
-
if (this.needMultipleBranchSelection) {
|
1169
|
-
// 多分支选择:获取所有分支的目标stepId(包括不需要选择人员的)
|
1170
|
-
if (!this.currentBranchActions) {
|
1171
|
-
this.currentBranchActions = this.getBranchActions()
|
1172
|
-
}
|
1173
|
-
stepIds = this.currentBranchActions.allBranchActions.map(action => action.to)
|
1174
|
-
} else if (this.calculatedTargetNode) {
|
1175
|
-
// 条件判断节点:使用计算出的目标节点
|
1176
|
-
stepIds = [this.calculatedTargetNode]
|
1177
|
-
} else {
|
1178
|
-
// 普通节点:使用传入的stepId
|
1179
|
-
stepIds = [stepId]
|
1180
|
-
}
|
1181
|
-
// 处理bug 有的时候没带到 branchChargePersons 先循环在同一地方处理
|
1182
|
-
stepIds.forEach(stepItemId => {
|
1183
|
-
if (!this.branchChargePersons[stepItemId]) {
|
1184
|
-
const chargePerson = this.stepsForChild.find(item => item.id === stepItemId)?.properties?.chargePerson
|
1185
|
-
this.branchChargePersons[stepItemId] = this.normalizeChargePersonFormat(chargePerson)
|
1186
|
-
}
|
1187
|
-
})
|
1188
|
-
|
1189
|
-
return {
|
1190
|
-
workflowId: this.workflowId,
|
1191
|
-
activeStepId: this.activeStepId,
|
1192
|
-
stepId, // 当前步骤ID
|
1193
|
-
stepIds, // 目标步骤IDs数组(统一格式)
|
1194
|
-
name: this.getStepNameByStepId(stepId),
|
1195
|
-
handler: this.getStepHandler(),
|
1196
|
-
handlerId: this.checkedChargePerson,
|
1197
|
-
needSelectPerson: this.needSelectPerson,
|
1198
|
-
personList: this.chargePerson.personList,
|
1199
|
-
deadline: this.deadline,
|
1200
|
-
submitUser: this.currUser.name,
|
1201
|
-
submitUserId: this.currUser.id,
|
1202
|
-
branchChargePersons: this.branchChargePersons
|
1203
|
-
}
|
1204
|
-
},
|
1205
|
-
|
1206
|
-
// 获取当前选择的负责人
|
1207
|
-
getStepHandler () {
|
1208
|
-
let stepHandler
|
1209
|
-
|
1210
|
-
if (this.needMultipleBranchSelection) {
|
1211
|
-
// 多分支情况:返回所有分支的人员信息
|
1212
|
-
const selectedHandlers = []
|
1213
|
-
for (const node of this.branchNodes) {
|
1214
|
-
const branchData = this.branchChargePersons[node.stepId]
|
1215
|
-
|
1216
|
-
if (node.needSelectPerson && branchData) {
|
1217
|
-
// 需要选择人员的分支:显示选中的人员
|
1218
|
-
const personName = this.getBranchPersonName(node.stepId)
|
1219
|
-
selectedHandlers.push(`${node.stepName}:${personName}`)
|
1220
|
-
} else if (!node.needSelectPerson && branchData) {
|
1221
|
-
// 不需要选择人员的分支:显示角色/部门配置
|
1222
|
-
if (branchData.personList && branchData.personList.length > 0) {
|
1223
|
-
const personNames = branchData.personList.map(item => item.name).join(',')
|
1224
|
-
selectedHandlers.push(`${node.stepName}:${personNames}`)
|
1225
|
-
}
|
1226
|
-
}
|
1227
|
-
}
|
1228
|
-
stepHandler = selectedHandlers.join(';')
|
1229
|
-
} else {
|
1230
|
-
// 单分支情况:原有逻辑
|
1231
|
-
if (this.checkedChargePerson) {
|
1232
|
-
// 使用 value 找到对应的 label
|
1233
|
-
stepHandler = this.chargePersonOptions.find(item => item.value === this.checkedChargePerson)?.label
|
1234
|
-
} else if (this.chargePerson.personList && this.chargePerson.personList.length > 0) {
|
1235
|
-
stepHandler = this.chargePerson.personList.map(item => item.name).join(',')
|
1236
|
-
}
|
1237
|
-
}
|
1238
|
-
|
1239
|
-
return stepHandler
|
1240
|
-
},
|
1241
|
-
|
1242
|
-
// 获取分支节点选择的人员姓名
|
1243
|
-
getBranchPersonName (stepId) {
|
1244
|
-
const personId = this.branchChargePersons[stepId]
|
1245
|
-
if (!personId) return ''
|
1246
|
-
|
1247
|
-
const node = this.branchNodes.find(n => n.stepId === stepId)
|
1248
|
-
if (!node) return ''
|
1249
|
-
|
1250
|
-
const person = node.chargePersonOptions.find(p => p.value === personId)
|
1251
|
-
return person ? person.label : ''
|
1252
|
-
},
|
1253
|
-
// 生成工作流日志步骤变化描述
|
1254
|
-
generateStepChangeText (fromStepId, toStepId) {
|
1255
|
-
// 如果是多分支场景,toStepId可能是数组或字符串
|
1256
|
-
if (this.needMultipleBranchSelection && Array.isArray(toStepId)) {
|
1257
|
-
const targetSteps = toStepId.map(id => `第${id}步: ${this.getStepNameByStepId(id)}`).join('、')
|
1258
|
-
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${targetSteps}`
|
1259
|
-
} else if (this.needMultipleBranchSelection && typeof toStepId === 'string') {
|
1260
|
-
// 如果传入的是目标步骤名称字符串
|
1261
|
-
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${toStepId}`
|
1262
|
-
} else {
|
1263
|
-
// 单步骤场景
|
1264
|
-
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> 第${toStepId}步: ${this.getStepNameByStepId(toStepId)}`
|
1265
|
-
}
|
1266
|
-
},
|
1267
|
-
|
1268
|
-
// 生成多分支场景的步骤变化描述
|
1269
|
-
generateBranchStepChangeText (fromStepId) {
|
1270
|
-
if (!this.needMultipleBranchSelection) {
|
1271
|
-
return this.generateStepChangeText(fromStepId, this.nextBtnTo)
|
1272
|
-
}
|
1273
|
-
|
1274
|
-
// 使用所有分支节点生成描述
|
1275
|
-
const targetSteps = this.branchNodes.map(node => `第${node.stepId}步: ${node.stepName}`).join('、')
|
1276
|
-
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${targetSteps}`
|
1277
|
-
},
|
1278
|
-
|
1279
|
-
generateStepChange (fromStepId, toStepId) {
|
1280
|
-
// 获取目标步骤IDs数组
|
1281
|
-
let stepIds = []
|
1282
|
-
|
1283
|
-
if (this.needMultipleBranchSelection) {
|
1284
|
-
// 多分支选择:获取所有分支的目标stepId(包括不需要选择人员的)
|
1285
|
-
if (!this.currentBranchActions) {
|
1286
|
-
this.currentBranchActions = this.getBranchActions()
|
1287
|
-
}
|
1288
|
-
stepIds = this.currentBranchActions.allBranchActions.map(action => action.to)
|
1289
|
-
} else if (this.calculatedTargetNode) {
|
1290
|
-
// 条件判断节点:使用计算出的目标节点
|
1291
|
-
stepIds = [this.calculatedTargetNode]
|
1292
|
-
} else {
|
1293
|
-
// 普通节点:使用传入的stepId
|
1294
|
-
stepIds = [toStepId]
|
1295
|
-
}
|
1296
|
-
|
1297
|
-
return {
|
1298
|
-
formStepId: fromStepId,
|
1299
|
-
fromStepId,
|
1300
|
-
stepId: toStepId,
|
1301
|
-
stepIds: stepIds,
|
1302
|
-
formStep: this.getStepNameByStepId(fromStepId),
|
1303
|
-
fromStep: this.getStepNameByStepId(fromStepId),
|
1304
|
-
toStep: this.getStepNameByStepId(stepIds[0]),
|
1305
|
-
successStepId: this.stepsDefine[this.stepsDefine.length - 1].id,
|
1306
|
-
successStep: this.stepsDefine[this.stepsDefine.length - 1].name
|
1307
|
-
}
|
1308
|
-
},
|
1309
|
-
// 保存工作流日志
|
1310
|
-
saveWorkflowLog (operation, desc, extra) {
|
1311
|
-
postByServiceName(workFlowViewApi.saveWorkFlowLog, {
|
1312
|
-
workflowId: this.workflowId,
|
1313
|
-
operation,
|
1314
|
-
desc,
|
1315
|
-
operator: this.currUser.name,
|
1316
|
-
notes: '',
|
1317
|
-
setHandler: '',
|
1318
|
-
setDeadline: '',
|
1319
|
-
...extra
|
1320
|
-
})
|
1321
|
-
},
|
1322
|
-
// 获取默认截止时间
|
1323
|
-
getDefaultDeadline (day = 1) {
|
1324
|
-
const date = new Date()
|
1325
|
-
date.setDate(date.getDate() + day)
|
1326
|
-
date.setHours(date.getHours() + 2)
|
1327
|
-
return formatDate(date, 'yyyy-MM-dd hh:mm')
|
1328
|
-
},
|
1329
|
-
// 验证截止时间
|
1330
|
-
checkDeadline (alert) {
|
1331
|
-
const deadline = moment(this.deadline)
|
1332
|
-
if (deadline.isAfter(this.completeTime, 'day')) {
|
1333
|
-
this.deadlineValidateStatus = 'error'
|
1334
|
-
this.deadlineHelp = '不能超过任务限定完成时间'
|
1335
|
-
if (alert) {
|
1336
|
-
this.$message.error('下一环节截止时间不能超过任务限定完成时间,如需设置,请联系发起人修改任务完成时间', 5)
|
1337
|
-
}
|
1338
|
-
return false
|
1339
|
-
}
|
1340
|
-
if (deadline.diff(moment(), 'hours') < 1) {
|
1341
|
-
this.deadlineValidateStatus = 'error'
|
1342
|
-
this.deadlineHelp = '下一环节截止时间只能在1小时之后'
|
1343
|
-
return false
|
1344
|
-
}
|
1345
|
-
this.deadlineValidateStatus = 'success'
|
1346
|
-
this.deadlineHelp = ''
|
1347
|
-
return true
|
1348
|
-
},
|
1349
|
-
// 操作类型单选按钮改变时重新设置负责人选择框
|
1350
|
-
async handleOperationTypeChange (event) {
|
1351
|
-
this.checkedChargePerson = undefined
|
1352
|
-
this.branchChargePersons = {}
|
1353
|
-
// 重新分析分支节点
|
1354
|
-
await this.analyzeBranchNodes()
|
1355
|
-
},
|
1356
|
-
|
1357
|
-
// 处理动态按钮点击
|
1358
|
-
handleCustomButtonClick (button) {
|
1359
|
-
try {
|
1360
|
-
// 执行自定义函数
|
1361
|
-
if (button.func) {
|
1362
|
-
const result = executeStrFunctionByContext(this, button.func, [this.details, this.$refs.xAddForm.form, util, runLogic, getConfigByNameAsync])
|
1363
|
-
if (result) {
|
1364
|
-
// 如果返回true,执行对应的操作
|
1365
|
-
if (button.text === '提交') {
|
1366
|
-
this.nextClick()
|
1367
|
-
} else if (button.text === '取消') {
|
1368
|
-
this.$emit('cancel')
|
1369
|
-
}
|
1370
|
-
}
|
1371
|
-
}
|
1372
|
-
} catch (error) {
|
1373
|
-
console.error('执行自定义按钮函数失败:', error)
|
1374
|
-
this.$message.error('执行操作失败')
|
1375
|
-
}
|
1376
|
-
},
|
1377
|
-
// 表单项展示函数--用来渲染历史节点数据时和填写表单显示内容同步
|
1378
|
-
async showFormItemFunc (func, form) {
|
1379
|
-
try {
|
1380
|
-
if (func) {
|
1381
|
-
// 一般展示项函数中不应该存在setForm函数 先屏蔽this.setForm和this.attr的传递还有在this上下文指向不同可能存在异常 流程表单的展示项函数尽量功能单一。有异常默认进行展示(先兼容到这后续有问题进行调整)
|
1382
|
-
const obj = executeStrFunctionByContext(this, func, [form, null, null, util, '新增/修改'])
|
1383
|
-
// 判断是 bool 还是 obj 兼容
|
1384
|
-
if (typeof obj === 'boolean') {
|
1385
|
-
return obj
|
1386
|
-
} else if (obj && typeof obj === 'object') {
|
1387
|
-
// obj 是一个对象,并且不是数组
|
1388
|
-
return obj?.show
|
1389
|
-
}
|
1390
|
-
} else {
|
1391
|
-
return true
|
1392
|
-
}
|
1393
|
-
} catch (e) {
|
1394
|
-
return true
|
1395
|
-
}
|
1396
|
-
},
|
1397
|
-
// 检查按钮是否显示
|
1398
|
-
checkButtonVisible (button) {
|
1399
|
-
try {
|
1400
|
-
if (button.customFunction) {
|
1401
|
-
return executeStrFunctionByContext(this, button.customFunction, [this.details, this.$refs.xAddForm.form, util, runLogic, getConfigByNameAsync])
|
1402
|
-
}
|
1403
|
-
return true
|
1404
|
-
} catch (error) {
|
1405
|
-
console.error('执行按钮显示函数失败:', error)
|
1406
|
-
return false
|
1407
|
-
}
|
1408
|
-
},
|
1409
|
-
formItemEmitFunc (func, data, value) {
|
1410
|
-
this.$emit('x-form-item-emit-func', func, data, value)
|
1411
|
-
},
|
1412
|
-
// 检查条件表达式是否包含WF_RESULT
|
1413
|
-
checkIfContainsWfResult () {
|
1414
|
-
const conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1415
|
-
if (conditionalActions.length === 0) return false
|
1416
|
-
|
1417
|
-
return conditionalActions.some(action => {
|
1418
|
-
return action.expression && action.expression.includes('WF_RESULT')
|
1419
|
-
})
|
1420
|
-
},
|
1421
|
-
|
1422
|
-
// 分析分支节点并设置选择框
|
1423
|
-
async analyzeBranchNodes () {
|
1424
|
-
try {
|
1425
|
-
// 初始化状态
|
1426
|
-
this.resetBranchSelection()
|
1427
|
-
|
1428
|
-
// 获取所有类型的分支动作并缓存
|
1429
|
-
this.currentBranchActions = this.getBranchActions()
|
1430
|
-
|
1431
|
-
// 如果没有任何分支,处理普通流程
|
1432
|
-
if (!this.currentBranchActions.hasAnyBranch) {
|
1433
|
-
await this.handleNormalFlow()
|
1434
|
-
return
|
1435
|
-
}
|
1436
|
-
|
1437
|
-
// 判断是否需要多分支选择
|
1438
|
-
this.needMultipleBranchSelection = this.shouldUseMultipleBranchSelection(this.currentBranchActions)
|
1439
|
-
|
1440
|
-
if (this.needMultipleBranchSelection) {
|
1441
|
-
// 需要为多个分支预先选择人员
|
1442
|
-
await this.setupMultipleBranchSelection(this.currentBranchActions.allBranchActions)
|
1443
|
-
} else {
|
1444
|
-
// 可以前台实时计算的条件分支
|
1445
|
-
await this.calculateTargetNodeFromForm(this.currentBranchActions.conditionalActions)
|
1446
|
-
}
|
1447
|
-
} catch (error) {
|
1448
|
-
console.error('分析分支节点失败:', error)
|
1449
|
-
this.$message.error('工作流分支配置异常,请联系管理员')
|
1450
|
-
// 降级处理:使用普通流程
|
1451
|
-
await this.handleNormalFlow()
|
1452
|
-
}
|
1453
|
-
},
|
1454
|
-
|
1455
|
-
// 重置分支选择状态
|
1456
|
-
resetBranchSelection () {
|
1457
|
-
this.branchNodes = []
|
1458
|
-
this.branchChargePersons = {}
|
1459
|
-
this.needMultipleBranchSelection = false
|
1460
|
-
this.calculatedTargetNode = null
|
1461
|
-
this.currentBranchActions = null
|
1462
|
-
},
|
1463
|
-
|
1464
|
-
// 获取分支动作分类
|
1465
|
-
getBranchActions () {
|
1466
|
-
const conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1467
|
-
const parallelActions = this.currentDirections.filter(action => action.type === 'parallelBranch')
|
1468
|
-
const allBranchActions = [...conditionalActions, ...parallelActions]
|
1469
|
-
|
1470
|
-
return {
|
1471
|
-
conditionalActions,
|
1472
|
-
parallelActions,
|
1473
|
-
allBranchActions,
|
1474
|
-
hasAnyBranch: allBranchActions.length > 0
|
1475
|
-
}
|
1476
|
-
},
|
1477
|
-
|
1478
|
-
// 判断是否应该使用多分支选择模式
|
1479
|
-
shouldUseMultipleBranchSelection (branchActions) {
|
1480
|
-
// 情况1: 有并行分支
|
1481
|
-
if (branchActions.parallelActions.length > 0) {
|
1482
|
-
return true
|
1483
|
-
}
|
1484
|
-
|
1485
|
-
// 情况2: 条件分支包含WF_RESULT(后台结果决定)
|
1486
|
-
if (branchActions.conditionalActions.length > 0) {
|
1487
|
-
return this.checkIfContainsWfResult()
|
1488
|
-
}
|
1489
|
-
|
1490
|
-
return false
|
1491
|
-
},
|
1492
|
-
|
1493
|
-
// 根据表单数据计算目标节点
|
1494
|
-
async calculateTargetNodeFromForm (conditionalActions = null) {
|
1495
|
-
if (!conditionalActions) {
|
1496
|
-
conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1497
|
-
}
|
1498
|
-
|
1499
|
-
if (conditionalActions.length === 0) {
|
1500
|
-
// 如果当前节点不是在分支流程中,才清空人员选择
|
1501
|
-
// 避免在并行分支节点中误清除人员选择框
|
1502
|
-
const currentStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
1503
|
-
const isInBranch = currentStep?.properties?.branchPath
|
1504
|
-
|
1505
|
-
if (!isInBranch) {
|
1506
|
-
this.clearPersonSelection()
|
1507
|
-
}
|
1508
|
-
return
|
1509
|
-
}
|
1510
|
-
|
1511
|
-
try {
|
1512
|
-
const formData = this.$refs.xAddForm?.form || {}
|
1513
|
-
|
1514
|
-
// 遍历条件找到匹配的
|
1515
|
-
for (const action of conditionalActions) {
|
1516
|
-
if (action.expression) {
|
1517
|
-
const result = await this.evaluateExpression(action.expression, formData)
|
1518
|
-
if (result) {
|
1519
|
-
this.calculatedTargetNode = action.to
|
1520
|
-
await this.setupSingleTargetPersonSelection(action.to)
|
1521
|
-
return
|
1522
|
-
}
|
1523
|
-
}
|
1524
|
-
}
|
1525
|
-
console.log('this.calculatedTargetNode', this.calculatedTargetNode)
|
1526
|
-
// 如果没有匹配的条件,清空选择
|
1527
|
-
this.clearPersonSelection()
|
1528
|
-
} catch (error) {
|
1529
|
-
console.warn('计算目标节点失败:', error)
|
1530
|
-
this.clearPersonSelection()
|
1531
|
-
}
|
1532
|
-
},
|
1533
|
-
|
1534
|
-
// 清空人员选择
|
1535
|
-
clearPersonSelection () {
|
1536
|
-
this.calculatedTargetNode = null
|
1537
|
-
this.needSelectPerson = false
|
1538
|
-
this.chargePersonOptions = []
|
1539
|
-
this.checkedChargePerson = undefined
|
1540
|
-
},
|
1541
|
-
|
1542
|
-
// 设置单个目标节点的人员选择
|
1543
|
-
async setupSingleTargetPersonSelection (stepId) {
|
1544
|
-
const stepDefine = this.stepsDefine.find(step => step.id === stepId)
|
1545
|
-
|
1546
|
-
if (!stepDefine?.properties?.chargePerson?.needSelectPerson) {
|
1547
|
-
this.needSelectPerson = false
|
1548
|
-
this.chargePersonOptions = []
|
1549
|
-
return
|
1550
|
-
}
|
1551
|
-
|
1552
|
-
// 设置人员选择
|
1553
|
-
this.chargePerson = stepDefine.properties.chargePerson
|
1554
|
-
this.checkedChargePerson = undefined
|
1555
|
-
this.chargePersonOptions = await this.getChargePersonOptionsForStep(stepId)
|
1556
|
-
|
1557
|
-
// 如果只有一个选项,自动选中
|
1558
|
-
if (this.chargePersonOptions.length === 1) {
|
1559
|
-
this.checkedChargePerson = this.chargePersonOptions[0].value
|
1560
|
-
}
|
1561
|
-
|
1562
|
-
this.needSelectPerson = true
|
1563
|
-
},
|
1564
|
-
|
1565
|
-
// 表单数据变化处理函数(将通过provide传递给表单组件)
|
1566
|
-
async handleFormDataChange (formData) {
|
1567
|
-
// 只有在不是多分支选择模式且当前活动步骤有条件分支动作时才重新计算
|
1568
|
-
if (!this.needMultipleBranchSelection && this.currentDirections.some(action => action.type === 'conditionalBranch')) {
|
1569
|
-
await this.calculateTargetNodeFromForm()
|
1570
|
-
}
|
1571
|
-
},
|
1572
|
-
|
1573
|
-
// 表达式评估 - 使用 LogicRunner
|
1574
|
-
async evaluateExpression (expression, formData) {
|
1575
|
-
try {
|
1576
|
-
// 构建参数对象,传递当前表单数据
|
1577
|
-
const params = {
|
1578
|
-
WF_FORM: { ...formData }
|
1579
|
-
}
|
1580
|
-
|
1581
|
-
// 使用 LogicRunner 执行表达式
|
1582
|
-
const result = await LogicRunner.runExpression(expression, params)
|
1583
|
-
return result
|
1584
|
-
} catch (error) {
|
1585
|
-
console.warn('表达式评估失败:', expression, error)
|
1586
|
-
return false
|
1587
|
-
}
|
1588
|
-
},
|
1589
|
-
|
1590
|
-
// 获取指定步骤的人员选项
|
1591
|
-
async getChargePersonOptionsForStep (stepId) {
|
1592
|
-
const define = this.stepsDefine.find(item => item.id === stepId)
|
1593
|
-
if (!define?.properties?.chargePerson) return []
|
1594
|
-
|
1595
|
-
const chargePerson = define.properties.chargePerson
|
1596
|
-
this.chargePerson = this.normalizeChargePersonFormat(chargePerson)
|
1597
|
-
|
1598
|
-
if (!chargePerson.needSelectPerson || !chargePerson.personList) return []
|
1599
|
-
|
1600
|
-
// 获取所有用户信息
|
1601
|
-
const allUser = await postByServiceName(commonApi.getAllUserOptionList, {})
|
1602
|
-
|
1603
|
-
// 根据配置筛选用户
|
1604
|
-
const options = this.filterUsersByPersonConfig(chargePerson.personList, allUser)
|
1605
|
-
|
1606
|
-
// 去重处理
|
1607
|
-
return Array.from(new Map(options.map(item => [item.value, item])).values())
|
1608
|
-
},
|
1609
|
-
|
1610
|
-
// 标准化人员配置格式(兼容旧格式)
|
1611
|
-
normalizeChargePersonFormat (chargePerson) {
|
1612
|
-
if (chargePerson.role || chargePerson.department) {
|
1613
|
-
chargePerson.needSelectPerson = true
|
1614
|
-
chargePerson.personList = [{
|
1615
|
-
type: chargePerson.role ? 'role' : 'department',
|
1616
|
-
name: chargePerson.role || chargePerson.department
|
1617
|
-
}]
|
1618
|
-
}
|
1619
|
-
return chargePerson
|
1620
|
-
},
|
1621
|
-
|
1622
|
-
// 根据人员配置筛选用户
|
1623
|
-
filterUsersByPersonConfig (personList, allUsers) {
|
1624
|
-
return personList.reduce((acc, personItem) => {
|
1625
|
-
let filteredUsers = []
|
1626
|
-
|
1627
|
-
if (personItem.type === 'role') {
|
1628
|
-
filteredUsers = allUsers.filter(user =>
|
1629
|
-
user.rolestr && user.rolestr.split(',').includes(personItem.name)
|
1630
|
-
).map(user => ({
|
1631
|
-
label: user.label,
|
1632
|
-
value: user.value
|
1633
|
-
}))
|
1634
|
-
} else if (personItem.type === 'department') {
|
1635
|
-
filteredUsers = allUsers.filter(user =>
|
1636
|
-
user.depname === personItem.name
|
1637
|
-
).map(user => ({
|
1638
|
-
label: user.label,
|
1639
|
-
value: user.value
|
1640
|
-
}))
|
1641
|
-
}
|
1642
|
-
|
1643
|
-
return [...acc, ...filteredUsers]
|
1644
|
-
}, [])
|
1645
|
-
},
|
1646
|
-
|
1647
|
-
// 设置多分支人员选择
|
1648
|
-
async setupMultipleBranchSelection (branchActions) {
|
1649
|
-
this.branchNodes = []
|
1650
|
-
this.branchChargePersons = {}
|
1651
|
-
let hasPersonSelection = false
|
1652
|
-
|
1653
|
-
for (const action of branchActions) {
|
1654
|
-
const stepDefine = this.stepsDefine.find(step => step.id === action.to)
|
1655
|
-
const chargePerson = stepDefine?.properties?.chargePerson
|
1656
|
-
|
1657
|
-
// 所有分支节点都加入branchNodes,保持数据结构完整
|
1658
|
-
const nodeData = {
|
1659
|
-
stepId: action.to,
|
1660
|
-
stepName: this.getStepNameByStepId(action.to),
|
1661
|
-
chargePerson: chargePerson,
|
1662
|
-
needSelectPerson: chargePerson?.needSelectPerson || false,
|
1663
|
-
chargePersonOptions: []
|
1664
|
-
}
|
1665
|
-
|
1666
|
-
if (chargePerson?.needSelectPerson) {
|
1667
|
-
// 需要选择人员的分支
|
1668
|
-
const chargePersonOptions = await this.getChargePersonOptionsForStep(action.to)
|
1669
|
-
nodeData.chargePersonOptions = chargePersonOptions
|
1670
|
-
|
1671
|
-
// 初始化选择值
|
1672
|
-
this.branchChargePersons[action.to] = undefined
|
1673
|
-
hasPersonSelection = true
|
1674
|
-
} else {
|
1675
|
-
// 不需要选择人员的分支,直接存储配置
|
1676
|
-
this.branchChargePersons[action.to] = chargePerson
|
1677
|
-
}
|
1678
|
-
|
1679
|
-
this.branchNodes.push(nodeData)
|
1680
|
-
}
|
1681
|
-
|
1682
|
-
// 只有当存在需要选择人员的分支时才显示选择区域
|
1683
|
-
this.needSelectPerson = hasPersonSelection
|
1684
|
-
},
|
1685
|
-
|
1686
|
-
// 处理普通单线流程(没有分支的情况)
|
1687
|
-
async handleNormalFlow () {
|
1688
|
-
const targetStepId = this.operationType === 'skip' ? this.stepNextBtnTo : this.nextBtnTo
|
1689
|
-
|
1690
|
-
this.calculatedTargetNode = targetStepId
|
1691
|
-
const stepDefine = this.stepsDefine.find(step => step.id === targetStepId)
|
1692
|
-
|
1693
|
-
if (!stepDefine) {
|
1694
|
-
console.warn('未找到目标步骤定义:', targetStepId)
|
1695
|
-
this.clearPersonSelection()
|
1696
|
-
return
|
1697
|
-
}
|
1698
|
-
|
1699
|
-
const defineProperties = stepDefine.properties
|
1700
|
-
this.chargePerson = defineProperties?.chargePerson
|
1701
|
-
|
1702
|
-
// 兼容旧格式
|
1703
|
-
if (defineProperties.chargePerson) {
|
1704
|
-
defineProperties.chargePerson = this.normalizeChargePersonFormat(defineProperties.chargePerson)
|
1705
|
-
}
|
1706
|
-
|
1707
|
-
if (defineProperties?.chargePerson?.needSelectPerson) {
|
1708
|
-
await this.setupSingleTargetPersonSelection(targetStepId)
|
1709
|
-
// 确保 branchChargePersons 中有该节点的数据结构
|
1710
|
-
this.branchChargePersons[targetStepId] = {
|
1711
|
-
handler: '',
|
1712
|
-
handlerId: undefined,
|
1713
|
-
...defineProperties.chargePerson
|
1714
|
-
}
|
1715
|
-
} else {
|
1716
|
-
// 不需要选择人员的情况,直接存储配置
|
1717
|
-
this.branchChargePersons[targetStepId] = defineProperties?.chargePerson || {}
|
1718
|
-
this.needSelectPerson = false
|
1719
|
-
this.chargePersonOptions = []
|
1720
|
-
}
|
1721
|
-
}
|
1722
|
-
},
|
1723
|
-
watch: {}
|
1724
|
-
}
|
1725
|
-
</script>
|
1726
|
-
<style lang="less" scoped>
|
1727
|
-
.complete-data-title {
|
1728
|
-
margin-top: 8px;
|
1729
|
-
margin-bottom: 8px;
|
1730
|
-
}
|
1731
|
-
|
1732
|
-
:deep(.ant-result) {
|
1733
|
-
padding: 0;
|
1734
|
-
}
|
1735
|
-
|
1736
|
-
.descriptionPreviewItem {
|
1737
|
-
margin-bottom: 22px;
|
1738
|
-
|
1739
|
-
:deep(.ant-descriptions-view) {
|
1740
|
-
overflow: visible;
|
1741
|
-
}
|
1742
|
-
}
|
1743
|
-
|
1744
|
-
.allWidth {
|
1745
|
-
:deep(.ant-descriptions-item-content) {
|
1746
|
-
width: 100%;
|
1747
|
-
}
|
1748
|
-
}
|
1749
|
-
|
1750
|
-
.descriptionTitle {
|
1751
|
-
position: relative;
|
1752
|
-
padding-left: 12px;
|
1753
|
-
|
1754
|
-
&::before {
|
1755
|
-
content: '';
|
1756
|
-
position: absolute;
|
1757
|
-
left: 0;
|
1758
|
-
top: 50%;
|
1759
|
-
transform: translateY(-50%);
|
1760
|
-
width: 4px;
|
1761
|
-
height: 16px;
|
1762
|
-
background-color: @primary-color;
|
1763
|
-
border-radius: 2px;
|
1764
|
-
}
|
1765
|
-
}
|
1766
|
-
</style>
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<!-- 上方流程显示 -->
|
4
|
+
<a-card :bordered="false" :loading="loading">
|
5
|
+
<!-- 项目进度流程 -->
|
6
|
+
<work-flow-timeline
|
7
|
+
:current-step-id="currentStepId"
|
8
|
+
:active-step-id="activeStepId"
|
9
|
+
:workflow-id="workflowId"
|
10
|
+
:steps="stepsForChild"
|
11
|
+
:state="workflowState"
|
12
|
+
change-able
|
13
|
+
@activeStep="activeStep"/>
|
14
|
+
</a-card>
|
15
|
+
<!-- 无权访问的提示 -->
|
16
|
+
<a-result v-show="!canSubmit" status="403" title="无权操作" sub-title="您没有访问该步骤的权限.">
|
17
|
+
</a-result>
|
18
|
+
<div v-show="canSubmit">
|
19
|
+
<!-- 流程被退回的提示 -->
|
20
|
+
<a-alert v-if="currentStep && currentStep.back && !(beforeStepActive || workflowState)" type="info" show-icon style="margin-bottom: 14px">
|
21
|
+
<div slot="message">
|
22
|
+
<span style="font-weight: bold">流程被退回</span>
|
23
|
+
<span style="margin-left: 14px; font-size: 14px; color: rgba(0, 0, 0, 0.65)">请重新填写信息发起提交</span>
|
24
|
+
</div>
|
25
|
+
<div slot="description">
|
26
|
+
<div>操作人:{{
|
27
|
+
currentStep.back.f_operator
|
28
|
+
}} 操作时间:{{ currentStep.back.f_date }}
|
29
|
+
</div>
|
30
|
+
<div>原因:{{ currentStep.back.f_notes }}</div>
|
31
|
+
</div>
|
32
|
+
</a-alert>
|
33
|
+
<!-- 步骤内容主体 -->
|
34
|
+
<a-tabs default-active-key="1" @change="note = ''" type="card">
|
35
|
+
<a-tab-pane key="0" tab="步骤详情" v-if="beforeStepActive || workflowState">
|
36
|
+
<a-card :bordered="false" :loading="loadingHistory" :body-style="{ paddingTop: 0 }">
|
37
|
+
<!-- 当前步骤历史记录 -->
|
38
|
+
<template v-if="showTab">
|
39
|
+
<x-tab
|
40
|
+
:compProp="{ buttonState: { add: false, edit: false, delete: false, import: false, extra: false }, disableAction: true }"
|
41
|
+
:local-config="tabDesigner"
|
42
|
+
:body-style="{ padding: 0 }"
|
43
|
+
:tabBarGutter="24"
|
44
|
+
:extra-data="{ workflowId: workflowId }"
|
45
|
+
default-active-key="workFlowTab">
|
46
|
+
<a-tab-pane
|
47
|
+
:forceRender="true"
|
48
|
+
v-if="formCompletedDataPreview"
|
49
|
+
slot="extraBeforeTabs"
|
50
|
+
key="workFlowTab"
|
51
|
+
tab="表单"
|
52
|
+
>
|
53
|
+
<work-flow-preview :form-completed-data-preview="formCompletedDataPreview"/>
|
54
|
+
</a-tab-pane>
|
55
|
+
</x-tab>
|
56
|
+
</template>
|
57
|
+
<template v-else-if="formCompletedDataPreview">
|
58
|
+
<work-flow-preview :form-completed-data-preview="formCompletedDataPreview"/>
|
59
|
+
</template>
|
60
|
+
<template v-else>
|
61
|
+
<a-result status="404" title="暂无数据" sub-title="该步骤暂无数据。">
|
62
|
+
</a-result>
|
63
|
+
</template>
|
64
|
+
</a-card>
|
65
|
+
</a-tab-pane>
|
66
|
+
<a-tab-pane key="1" tab="业务操作" v-else v-show="renderCurrentNode">
|
67
|
+
<a-card :bordered="false" :loading="loadingHistory" :body-style="{ paddingTop: 0 }">
|
68
|
+
<x-tab
|
69
|
+
v-if="showTab"
|
70
|
+
:compProp="{ buttonState: { extra: true }, disableAction: false }"
|
71
|
+
:local-config="tabDesigner"
|
72
|
+
:extra-data="{ workflowId:workflowId }"
|
73
|
+
:body-style="{ padding: 0 }"
|
74
|
+
:tabBarGutter="24"
|
75
|
+
default-active-key="workFlowTab">
|
76
|
+
<a-tab-pane
|
77
|
+
:forceRender="true"
|
78
|
+
v-if="showForm"
|
79
|
+
slot="extraBeforeTabs"
|
80
|
+
key="workFlowTab"
|
81
|
+
tab="表单"
|
82
|
+
>
|
83
|
+
<x-add-native-form
|
84
|
+
ref="xAddForm"
|
85
|
+
@x-form-item-emit-func="formItemEmitFunc"
|
86
|
+
@onSubmit="submitForm"/>
|
87
|
+
</a-tab-pane>
|
88
|
+
</x-tab>
|
89
|
+
<x-add-native-form
|
90
|
+
v-else
|
91
|
+
ref="xAddForm"
|
92
|
+
@x-form-item-emit-func="formItemEmitFunc"
|
93
|
+
@onSubmit="submitForm"/>
|
94
|
+
<a-divider/>
|
95
|
+
|
96
|
+
<!-- 分支节点状态提示 -->
|
97
|
+
<a-alert
|
98
|
+
v-if="isBranchLastNode.isBranchNode && !isBranchLastNode.isLastBranch"
|
99
|
+
type="info"
|
100
|
+
show-icon
|
101
|
+
style="margin-bottom: 16px"
|
102
|
+
>
|
103
|
+
<template slot="message">
|
104
|
+
<span style="font-weight: bold;">分支节点等待中</span>
|
105
|
+
</template>
|
106
|
+
<template slot="description">
|
107
|
+
<div>当前为分支节点,其他分支仍在进行中。完成当前分支后将等待其他分支完成,然后自动汇合到下一环节。</div>
|
108
|
+
<div style="margin-top: 8px; color: #666; font-size: 12px;">
|
109
|
+
<a-icon type="info-circle" style="margin-right: 4px;" />
|
110
|
+
提示:此操作无需选择下一环节负责人,系统将自动处理流程流转。
|
111
|
+
</div>
|
112
|
+
</template>
|
113
|
+
</a-alert>
|
114
|
+
|
115
|
+
<a-alert
|
116
|
+
v-if="isBranchLastNode.isBranchNode && isBranchLastNode.isLastBranch"
|
117
|
+
type="success"
|
118
|
+
show-icon
|
119
|
+
style="margin-bottom: 16px"
|
120
|
+
>
|
121
|
+
<template slot="message">
|
122
|
+
<span style="font-weight: bold;">分支汇合节点</span>
|
123
|
+
</template>
|
124
|
+
<template slot="description">
|
125
|
+
<div>您正在处理最后一个未完成的分支节点,完成后将触发分支汇合并进入下一环节。</div>
|
126
|
+
</template>
|
127
|
+
</a-alert>
|
128
|
+
|
129
|
+
<a-form v-show="!lastStep" label-align="left" :label-col="{ span: 3 }" :wrapper-col="{ span: 13 }">
|
130
|
+
<a-form-item v-if="showStepNextBtn" label="操作类型" required>
|
131
|
+
<a-radio-group v-model="operationType" @change="handleOperationTypeChange">
|
132
|
+
<a-radio value="submit">到下一步</a-radio>
|
133
|
+
<a-radio value="skip">{{ stepNextBtnTitle }}</a-radio>
|
134
|
+
</a-radio-group>
|
135
|
+
</a-form-item>
|
136
|
+
|
137
|
+
<!-- 智能分支人员选择组件 - 只有非分支节点或最后一个分支才显示 -->
|
138
|
+
<WorkflowPersonSelector
|
139
|
+
v-if="!isBranchLastNode.isBranchNode || isBranchLastNode.isLastBranch"
|
140
|
+
ref="personSelector"/>
|
141
|
+
|
142
|
+
<a-form-item
|
143
|
+
v-if="!isBranchLastNode.isBranchNode || isBranchLastNode.isLastBranch"
|
144
|
+
label="下一环节截止时间"
|
145
|
+
:validate-status="deadlineValidateStatus"
|
146
|
+
:help="deadlineHelp"
|
147
|
+
required>
|
148
|
+
<a-date-picker
|
149
|
+
:getCalendarContainer="(triggerNode) => triggerNode.parentNode"
|
150
|
+
v-model="deadline"
|
151
|
+
value-format="YYYY-MM-DD HH:mm"
|
152
|
+
format="YYYY-MM-DD HH:mm"
|
153
|
+
:allow-clear="false"
|
154
|
+
:show-today="false"
|
155
|
+
show-time
|
156
|
+
placeholder="请选择"/>
|
157
|
+
</a-form-item>
|
158
|
+
</a-form>
|
159
|
+
<a-divider/>
|
160
|
+
<!-- 备注信息 -->
|
161
|
+
<a-textarea
|
162
|
+
v-model="note"
|
163
|
+
:auto-size="{ minRows: 3, maxRows: 5 }"
|
164
|
+
placeholder="填写本环节备注事项"
|
165
|
+
/>
|
166
|
+
<!-- 当前步骤完成后,控制流程按钮 -->
|
167
|
+
<div style="text-align: center">
|
168
|
+
<a-radio-group style="margin-top: 20px">
|
169
|
+
<a-space>
|
170
|
+
<!-- 动态按钮渲染 -->
|
171
|
+
<template v-if="buttonGroup && buttonGroup.actionArr">
|
172
|
+
<a-button
|
173
|
+
v-for="(button, index) in buttonGroup.actionArr"
|
174
|
+
:key="index"
|
175
|
+
v-show="checkButtonVisible(button)"
|
176
|
+
:type="button.type ? button.type : 'default'"
|
177
|
+
@click="handleCustomButtonClick(button)"
|
178
|
+
>
|
179
|
+
{{ button.text }}
|
180
|
+
</a-button>
|
181
|
+
</template>
|
182
|
+
<!-- 原有的按钮逻辑 -->
|
183
|
+
<template>
|
184
|
+
<a-popover v-if="operationType === 'submit'">
|
185
|
+
<template slot="content">
|
186
|
+
<p v-if="isBranchLastNode.isBranchNode && !isBranchLastNode.isLastBranch">
|
187
|
+
完成当前分支,等待其他分支完成后自动汇合
|
188
|
+
</p>
|
189
|
+
<p v-else-if="isBranchLastNode.isBranchNode && isBranchLastNode.isLastBranch">
|
190
|
+
完成最后一个分支并触发汇合到下一环节
|
191
|
+
</p>
|
192
|
+
<p v-else>{{ nextBtnTitle }}</p>
|
193
|
+
</template>
|
194
|
+
<a-button
|
195
|
+
v-if="!lastStep"
|
196
|
+
:disabled="!showNextBtn && !stepDone"
|
197
|
+
type="primary"
|
198
|
+
@click="nextClick"
|
199
|
+
>
|
200
|
+
完成提交
|
201
|
+
<a-icon type="right"/>
|
202
|
+
</a-button>
|
203
|
+
</a-popover>
|
204
|
+
<a-popover v-else :title="stepNextBtnTitle">
|
205
|
+
<template slot="content">
|
206
|
+
<p v-for="(item,index) in stepNextBtnText" :key="index">{{ item }}</p>
|
207
|
+
</template>
|
208
|
+
<a-button
|
209
|
+
v-if="showStepNextBtn && !lastStep"
|
210
|
+
type="primary"
|
211
|
+
@click="stepNextClick"
|
212
|
+
>
|
213
|
+
跳过
|
214
|
+
</a-button>
|
215
|
+
</a-popover>
|
216
|
+
<a-button
|
217
|
+
v-if="lastStep"
|
218
|
+
type="primary"
|
219
|
+
@click="lastStepNextClick"
|
220
|
+
>
|
221
|
+
确认完成
|
222
|
+
</a-button>
|
223
|
+
</template>
|
224
|
+
</a-space>
|
225
|
+
</a-radio-group>
|
226
|
+
</div>
|
227
|
+
</a-card>
|
228
|
+
</a-tab-pane>
|
229
|
+
<!-- 退回 -->
|
230
|
+
<a-tab-pane v-if="canSubmit && !beforeStepActive && showPrevBtn && !workflowState" key="2" tab="退回">
|
231
|
+
<a-form layout="vertical">
|
232
|
+
<a-form-item label="退回原因" :wrapper-col="{ span: 24 }" required>
|
233
|
+
<a-textarea
|
234
|
+
v-model="backNote"
|
235
|
+
:auto-size="{ minRows: 4, maxRows: 10 }"
|
236
|
+
placeholder="请填写退回原因 / 备注"
|
237
|
+
/>
|
238
|
+
</a-form-item>
|
239
|
+
<a-form-item :wrapper-col="{ offset: 11 }">
|
240
|
+
<a-popover :title="preBtnTitle">
|
241
|
+
<template slot="content">
|
242
|
+
<p v-for="(item,index) in preBtnText" :key="index">{{ item }}</p>
|
243
|
+
</template>
|
244
|
+
<a-button
|
245
|
+
type="danger"
|
246
|
+
@click="preClick"
|
247
|
+
>
|
248
|
+
<a-icon type="left"/>
|
249
|
+
退回
|
250
|
+
</a-button>
|
251
|
+
</a-popover>
|
252
|
+
</a-form-item>
|
253
|
+
</a-form>
|
254
|
+
</a-tab-pane>
|
255
|
+
<!-- <a-tab-pane v-if="canSubmit && !beforeStepActive && showPrevBtn && !workflowState" key="3" tab="工单拆分">
|
256
|
+
<!– 分配工单 –>
|
257
|
+
<workflow-list-resolution :workflow-project-id="workflowId" :details="details"></workflow-list-resolution>
|
258
|
+
</a-tab-pane>-->
|
259
|
+
</a-tabs>
|
260
|
+
</div>
|
261
|
+
</div>
|
262
|
+
</template>
|
263
|
+
|
264
|
+
<script>
|
265
|
+
import XAddNativeForm from '@vue2-client/base-client/components/common/XAddNativeForm'
|
266
|
+
import XFormTable from '@vue2-client/base-client/components/common/XFormTable/XFormTable'
|
267
|
+
import XAddForm from '@vue2-client/base-client/components/common/XAddForm/XAddForm'
|
268
|
+
import { postByServiceName } from '@vue2-client/services/api/restTools'
|
269
|
+
import { workFlowViewApi } from '@vue2-client/services/api/workFlow'
|
270
|
+
import { commonApi } from '@vue2-client/services/api'
|
271
|
+
import { formatDate } from '@vue2-client/utils/util'
|
272
|
+
import { mapState } from 'vuex'
|
273
|
+
import moment from 'moment'
|
274
|
+
import FilePreview from '@vue2-client/components/FilePreview'
|
275
|
+
import WorkFlowTimeline from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowTimeline.vue'
|
276
|
+
import { FileItem, ImageItem } from '@vue2-client/components/FileImageItem'
|
277
|
+
import WorkflowListResolution from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkflowListResolution'
|
278
|
+
import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
|
279
|
+
import * as util from '@vue2-client/utils/util'
|
280
|
+
import { getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
|
281
|
+
import LogicRunner from '@vue2-client/logic/LogicRunner'
|
282
|
+
import XTab from '@vue2-client/base-client/components/common/XTab/XTab.vue'
|
283
|
+
import WorkFlowPreview from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowPreview'
|
284
|
+
import WorkflowPersonSelector from '@vue2-client/pages/WorkflowDetail/WorkflowPageDetail/components/WorkflowPersonSelector.vue'
|
285
|
+
|
286
|
+
export default {
|
287
|
+
name: 'WorkFlowHandle',
|
288
|
+
provide () {
|
289
|
+
return {
|
290
|
+
formDataChange: this.handleFormDataChange,
|
291
|
+
workflowHandleWrap: this.workflowHandleWrap
|
292
|
+
}
|
293
|
+
},
|
294
|
+
components: {
|
295
|
+
XTab,
|
296
|
+
WorkflowListResolution,
|
297
|
+
XAddNativeForm,
|
298
|
+
WorkFlowTimeline,
|
299
|
+
XFormTable,
|
300
|
+
XAddForm,
|
301
|
+
FilePreview,
|
302
|
+
FileItem,
|
303
|
+
ImageItem,
|
304
|
+
WorkFlowPreview,
|
305
|
+
WorkflowPersonSelector
|
306
|
+
},
|
307
|
+
computed: {
|
308
|
+
workflowHandleWrap () {
|
309
|
+
return this
|
310
|
+
},
|
311
|
+
...mapState('account', { currUser: 'user' }),
|
312
|
+
// 判断当前节点的分支状态
|
313
|
+
isBranchLastNode () {
|
314
|
+
// 默认返回值
|
315
|
+
const defaultResult = {
|
316
|
+
isBranchNode: false, // 是否为分支流程中的节点
|
317
|
+
isLastBranch: false // 是否为最后一个未完成的分支(需要选择下一环节人员)
|
318
|
+
}
|
319
|
+
|
320
|
+
// 如果是最后一步或没有下一步或者不能提交,则不是分支节点
|
321
|
+
if (this.lastStep || !this.nextBtnTo || !this.canSubmit) {
|
322
|
+
return defaultResult
|
323
|
+
}
|
324
|
+
|
325
|
+
// 检查下一个节点是否为分支退出节点
|
326
|
+
const nextStep = this.stepsDefine.find(step => step.id === this.nextBtnTo)
|
327
|
+
|
328
|
+
// 如果下一个节点的flowRole不是branchExit,说明不是分支的最后一个节点
|
329
|
+
if (!nextStep || nextStep.properties?.flowRole !== 'branchExit') {
|
330
|
+
return defaultResult
|
331
|
+
}
|
332
|
+
|
333
|
+
// 获取分支退出节点等待的所有分支步骤ID
|
334
|
+
const waitStepIds = nextStep.properties.waitStepIds || []
|
335
|
+
if (waitStepIds.length === 0) {
|
336
|
+
return {
|
337
|
+
isBranchNode: true,
|
338
|
+
isLastBranch: true // 如果没有等待步骤配置,默认认为是最后一个
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
// 当前步骤必须在等待列表中才算是分支节点
|
343
|
+
if (!waitStepIds.includes(this.activeStepId)) {
|
344
|
+
return defaultResult
|
345
|
+
}
|
346
|
+
|
347
|
+
// 检查除当前步骤外的其他分支步骤状态
|
348
|
+
const otherBranchSteps = waitStepIds.filter(stepId => stepId !== this.activeStepId)
|
349
|
+
|
350
|
+
// 判断其他所有分支步骤是否都已完成(状态为2)
|
351
|
+
const allOtherBranchesCompleted = otherBranchSteps.every(stepId => {
|
352
|
+
const step = this.stepsForChild.find(s => s.id === stepId)
|
353
|
+
return step && step.status === 2 // 已处理
|
354
|
+
})
|
355
|
+
|
356
|
+
return {
|
357
|
+
isBranchNode: true, // 当前节点是分支流程中的节点
|
358
|
+
isLastBranch: allOtherBranchesCompleted // 只有当其他所有分支都已完成时,当前分支才是最后一个
|
359
|
+
}
|
360
|
+
},
|
361
|
+
canSubmit () {
|
362
|
+
// 对于超级管理员直接认为可以提交
|
363
|
+
if (this.currUser.rolesnames.indexOf('超级管理员') > -1) {
|
364
|
+
return true
|
365
|
+
}
|
366
|
+
// currentStepId可能还没初始化,此处拿不到先返回false
|
367
|
+
if (!this.currentStepId) {
|
368
|
+
return false
|
369
|
+
}
|
370
|
+
const activeStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
371
|
+
// 如果当前选中节点不是正在进行的节点,则判断viewers权限
|
372
|
+
if (this.activeStepId !== this.currentStepId && activeStep != null && activeStep.status !== 1) {
|
373
|
+
// 历史节点为当前登录人操作则不做查看数据权限校验
|
374
|
+
if (activeStep.handler === this.currUser.name) {
|
375
|
+
return true
|
376
|
+
}
|
377
|
+
const viewers = activeStep?.properties?.otherProperty?.viewers ?? []
|
378
|
+
if (viewers.length > 0) {
|
379
|
+
// 使用some方法判断当前人员是否满足任一条件
|
380
|
+
return viewers.some(item => {
|
381
|
+
if (item.type === 'role') {
|
382
|
+
// 检查rolestr是否存在并包含指定角色
|
383
|
+
return this.currUser.rolestr && this.currUser.rolestr.split(',').includes(item.name)
|
384
|
+
}
|
385
|
+
if (item.type === 'department') {
|
386
|
+
// 检查depname是否存在并包含指定部门
|
387
|
+
return this.currUser.deps && this.currUser.deps.includes(item.name)
|
388
|
+
}
|
389
|
+
return false
|
390
|
+
})
|
391
|
+
} else {
|
392
|
+
return true
|
393
|
+
}
|
394
|
+
} else {
|
395
|
+
// 当前进行节点的数据
|
396
|
+
const step = this.stepsForChild.find(item => item.id === this.activeStepId)
|
397
|
+
// 检查角色和部门权限
|
398
|
+
if (step && step.properties && step.properties.chargePerson) {
|
399
|
+
// 如果当前节点的负责人选项中有设置选择人员 当前节点就只能由上一步设置的负责人操作
|
400
|
+
if (step.properties.chargePerson.needSelectPerson) {
|
401
|
+
return step.handler === this.currUser.name
|
402
|
+
}
|
403
|
+
if (step.properties.chargePerson.personList && step.properties.chargePerson.personList.length > 0) {
|
404
|
+
// 使用some方法判断当前人员是否满足任一条件
|
405
|
+
return step.properties.chargePerson.personList.some(item => {
|
406
|
+
if (item.type === 'role') {
|
407
|
+
// 检查rolestr是否存在并包含指定角色
|
408
|
+
return this.currUser.rolestr && this.currUser.rolestr.split(',').includes(item.name)
|
409
|
+
}
|
410
|
+
if (item.type === 'department') {
|
411
|
+
// 检查parentname是否存在并包含指定部门
|
412
|
+
return this.currUser.parentname && this.currUser.parentname.includes(item.name)
|
413
|
+
}
|
414
|
+
return false
|
415
|
+
})
|
416
|
+
}
|
417
|
+
}
|
418
|
+
|
419
|
+
// 检查handler是否包含当前用户
|
420
|
+
if (step && step.handler) {
|
421
|
+
return step.handler.includes(this.currUser.name)
|
422
|
+
}
|
423
|
+
}
|
424
|
+
return false
|
425
|
+
},
|
426
|
+
formPreviewNoFileData () {
|
427
|
+
return this.formCompletedDataPreview.data.filter(item => item.label !== '附件上传')
|
428
|
+
}
|
429
|
+
},
|
430
|
+
data () {
|
431
|
+
return {
|
432
|
+
// 显示供用户填写的当前步骤表单
|
433
|
+
showForm: false,
|
434
|
+
// 显示步骤的tab页
|
435
|
+
showTab: false,
|
436
|
+
// tab页的配置
|
437
|
+
tabDesigner: undefined,
|
438
|
+
// 当前步骤表单标题
|
439
|
+
formTitle: '',
|
440
|
+
// 当前步骤表单定义Json
|
441
|
+
stepDefine: [],
|
442
|
+
// 当前步骤
|
443
|
+
currentStep: undefined,
|
444
|
+
// 当前步骤完成状态
|
445
|
+
stepDone: false,
|
446
|
+
// 所有节点连通数据
|
447
|
+
directions: [],
|
448
|
+
// 所有流程定义数据
|
449
|
+
stepsDefine: [],
|
450
|
+
// 当前步骤能通向的节点
|
451
|
+
currentDirections: [],
|
452
|
+
// 当前节点id
|
453
|
+
currentStepId: undefined,
|
454
|
+
// 当前活动节点 id
|
455
|
+
activeStepId: 1,
|
456
|
+
// 下一步按钮显示
|
457
|
+
showNextBtn: false,
|
458
|
+
// 回退按钮显示
|
459
|
+
showPrevBtn: false,
|
460
|
+
// 跳过按钮显示
|
461
|
+
showStepNextBtn: false,
|
462
|
+
// 定义三个按钮气泡提示内容
|
463
|
+
preBtnTitle: '',
|
464
|
+
preBtnText: [],
|
465
|
+
nextBtnTitle: '',
|
466
|
+
stepNextBtnTitle: '',
|
467
|
+
stepNextBtnText: [],
|
468
|
+
// 控制三个按钮跳转目标
|
469
|
+
preBtnTo: undefined,
|
470
|
+
nextBtnTo: undefined,
|
471
|
+
stepNextBtnTo: undefined,
|
472
|
+
// 控制当前标签页显示
|
473
|
+
activeKey: '1',
|
474
|
+
// 之前的节点是否激活
|
475
|
+
beforeStepActive: false,
|
476
|
+
// 之前节点中的数据
|
477
|
+
beforeStepData: [],
|
478
|
+
// 用于将已有数据,填回x-add表单中
|
479
|
+
formCompletedData: {},
|
480
|
+
// 用于展示提交的数据
|
481
|
+
formCompletedDataPreview: null,
|
482
|
+
// 切换至目标流程时,目标流程定义
|
483
|
+
targetStepDefine: [],
|
484
|
+
// 控制历史记录加载
|
485
|
+
loadingHistory: true,
|
486
|
+
// 控制表单校验
|
487
|
+
formValid: false,
|
488
|
+
// 备忘
|
489
|
+
note: '',
|
490
|
+
backNote: '', // 新增退回原因专用变量
|
491
|
+
// 是否是最后一步
|
492
|
+
lastStep: false,
|
493
|
+
// 存储每一步骤填表人和时间数据
|
494
|
+
stepsExtraInfo: [],
|
495
|
+
// 控制基础信息页流程展示加载
|
496
|
+
loading: true,
|
497
|
+
createQueryVisible: false,
|
498
|
+
// 激活的步骤名
|
499
|
+
activeStepName: '',
|
500
|
+
stepsParse: undefined,
|
501
|
+
// 下一步处理人选择框数据
|
502
|
+
chargePersonOptions: [],
|
503
|
+
// 已选择下一步处理人
|
504
|
+
checkedChargePerson: undefined,
|
505
|
+
// 下一步截止时间
|
506
|
+
deadline: this.getDefaultDeadline(),
|
507
|
+
deadlineValidateStatus: '',
|
508
|
+
deadlineHelp: '',
|
509
|
+
// 当前任务是否延期
|
510
|
+
// taskIsOverdue: moment().isAfter(this.completeTime, 'day'),
|
511
|
+
// 操作类型,提交到下一步或跳过
|
512
|
+
operationType: 'submit',
|
513
|
+
// 获取微信推送是否成功信息
|
514
|
+
information: [],
|
515
|
+
// 是否需要选择人员
|
516
|
+
needSelectPerson: true,
|
517
|
+
// 下一环节人员信息
|
518
|
+
chargePerson: {},
|
519
|
+
// 动态按钮配置
|
520
|
+
buttonGroup: null,
|
521
|
+
// 分支节点相关数据
|
522
|
+
branchNodes: [], // 需要选择人员的分支节点列表
|
523
|
+
branchChargePersons: {}, // 分支节点人员选择 格式:{stepId: personId}
|
524
|
+
needMultipleBranchSelection: false, // 是否需要为多个分支节点预先选择人员(包含WF_RESULT的条件分支或并行分支)
|
525
|
+
calculatedTargetNode: null, // 前台计算出的目标节点
|
526
|
+
currentBranchActions: null // 缓存当前的分支动作,避免重复调用
|
527
|
+
}
|
528
|
+
},
|
529
|
+
async mounted () {
|
530
|
+
await this.init()
|
531
|
+
// this.checkDeadline()
|
532
|
+
},
|
533
|
+
props: {
|
534
|
+
workflowId: {
|
535
|
+
type: [String, Number],
|
536
|
+
required: true
|
537
|
+
},
|
538
|
+
visible: {
|
539
|
+
type: Boolean,
|
540
|
+
default: false
|
541
|
+
},
|
542
|
+
stepsForChild: {
|
543
|
+
type: Array,
|
544
|
+
required: true
|
545
|
+
},
|
546
|
+
workflowState: {
|
547
|
+
type: [Boolean, Number],
|
548
|
+
required: true
|
549
|
+
},
|
550
|
+
completeTime: {
|
551
|
+
type: String,
|
552
|
+
required: true
|
553
|
+
},
|
554
|
+
taskName: {
|
555
|
+
type: String,
|
556
|
+
required: true
|
557
|
+
},
|
558
|
+
details: {
|
559
|
+
type: Object,
|
560
|
+
required: true
|
561
|
+
},
|
562
|
+
// 展开详情初始化的节点
|
563
|
+
// 适用于不让第一个节点默认展示的情况
|
564
|
+
initStepId: {
|
565
|
+
type: [String, Number],
|
566
|
+
required: false,
|
567
|
+
default: null
|
568
|
+
},
|
569
|
+
renderCurrentNode: {
|
570
|
+
type: Boolean,
|
571
|
+
default: true
|
572
|
+
}
|
573
|
+
},
|
574
|
+
methods: {
|
575
|
+
init () {
|
576
|
+
this.getCurrentStep()
|
577
|
+
},
|
578
|
+
onClose () {
|
579
|
+
this.activeStepId = this.currentStepId
|
580
|
+
this.checkedChargePerson = undefined
|
581
|
+
this.loadingHistory = true
|
582
|
+
this.currentStepId = undefined
|
583
|
+
this.directions = []
|
584
|
+
this.currentDirections = []
|
585
|
+
this.preBtnText = []
|
586
|
+
this.stepNextBtnText = []
|
587
|
+
this.stepsExtraInfo = []
|
588
|
+
this.loading = true
|
589
|
+
this.showNextBtn = false
|
590
|
+
this.showStepNextBtn = false
|
591
|
+
this.showPrevBtn = false
|
592
|
+
this.stepDone = false
|
593
|
+
this.formCompletedData = {}
|
594
|
+
this.formCompletedDataPreview = null
|
595
|
+
this.operationType = 'submit'
|
596
|
+
|
597
|
+
// 清理分支节点相关数据
|
598
|
+
this.branchNodes = []
|
599
|
+
this.branchChargePersons = {}
|
600
|
+
this.needMultipleBranchSelection = false
|
601
|
+
this.calculatedTargetNode = null
|
602
|
+
this.currentBranchActions = null
|
603
|
+
},
|
604
|
+
async showQueryFormItemFunc () {
|
605
|
+
if (this.attr.showQueryFormItemFunc) {
|
606
|
+
const obj = executeStrFunctionByContext(this, this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
|
607
|
+
// 判断是 bool 还是 obj 兼容
|
608
|
+
if (typeof obj === 'boolean') {
|
609
|
+
this.show = obj
|
610
|
+
} else if (obj && typeof obj === 'object') {
|
611
|
+
// obj 是一个对象,并且不是数组
|
612
|
+
this.show = obj?.show
|
613
|
+
this.readOnly = obj?.readOnly
|
614
|
+
}
|
615
|
+
} else {
|
616
|
+
this.show = true
|
617
|
+
}
|
618
|
+
},
|
619
|
+
// 获取单个步骤的定义
|
620
|
+
getSingleStepDefine (name) {
|
621
|
+
for (const step of this.stepsDefine) {
|
622
|
+
if (name === step.name) {
|
623
|
+
return step.properties.form
|
624
|
+
}
|
625
|
+
}
|
626
|
+
},
|
627
|
+
// 日期格式化
|
628
|
+
format (date, format) {
|
629
|
+
return formatDate(date, format)
|
630
|
+
},
|
631
|
+
// 获取当前步骤
|
632
|
+
getCurrentStep () {
|
633
|
+
return postByServiceName(workFlowViewApi.getWorkFlowCurrentSubState, {
|
634
|
+
workflowId: this.workflowId
|
635
|
+
})
|
636
|
+
.then(res => {
|
637
|
+
// 优先级:主动传入的 > 获取到的
|
638
|
+
this.currentStepId = this.initStepId || res.id
|
639
|
+
|
640
|
+
// 如果指定了具体节点,同时设置activeStepId
|
641
|
+
if (this.initStepId) {
|
642
|
+
this.activeStepId = this.initStepId
|
643
|
+
}
|
644
|
+
|
645
|
+
const currentStep = this.stepsForChild.find(item => item.id === res.id)
|
646
|
+
res.state = currentStep.name
|
647
|
+
// 获取到当前步骤后复制下一步时间
|
648
|
+
this.deadline = this.getDefaultDeadline(currentStep.properties?.otherProperty?.nextNodeInterval)
|
649
|
+
this.currentStep = res
|
650
|
+
this.getDirection()
|
651
|
+
}, err => {
|
652
|
+
console.log(err)
|
653
|
+
})
|
654
|
+
},
|
655
|
+
// 完工按钮
|
656
|
+
async lastStepNextClick () {
|
657
|
+
this.$refs.xAddForm.asyncSubmit().then((res) => {
|
658
|
+
this.submitForm(res).then(_ => {
|
659
|
+
postByServiceName(workFlowViewApi.afterWorkFlowFinalStepSubmit, {
|
660
|
+
workflowId: this.workflowId,
|
661
|
+
stepId: this.currentStepId,
|
662
|
+
submitUser: this.currUser.name,
|
663
|
+
submitUserId: this.currUser.id
|
664
|
+
}).then(_res => {
|
665
|
+
this.saveWorkflowLog('确认完工', '最后一步: ' + this.getStepNameByStepId(this.currentStepId), { notes: this.note.trim() })
|
666
|
+
this.$message.success('已完工!')
|
667
|
+
this.loading = true
|
668
|
+
this.loadingHistory = true
|
669
|
+
this.onClose()
|
670
|
+
this.$emit('success', { note: this.note.trim(), form: res.realForm, workflowId: this.workflowId })
|
671
|
+
},
|
672
|
+
() => {
|
673
|
+
this.$message.error('提交失败!')
|
674
|
+
}
|
675
|
+
)
|
676
|
+
})
|
677
|
+
}).catch(err => {
|
678
|
+
if (err && err.message === 'Form validation failed') {
|
679
|
+
this.$message.error('请检查表单必填项!')
|
680
|
+
} else {
|
681
|
+
// 对于其他错误,继续向上抛出
|
682
|
+
throw err
|
683
|
+
}
|
684
|
+
})
|
685
|
+
},
|
686
|
+
// 三个按钮点击后逻辑
|
687
|
+
async nextClick () {
|
688
|
+
// 检查是否为非最后分支节点
|
689
|
+
const branchStatus = this.isBranchLastNode
|
690
|
+
const isWaitingBranch = branchStatus.isBranchNode && !branchStatus.isLastBranch
|
691
|
+
|
692
|
+
const extraData = this.getApplyStepExtraData(this.nextBtnTo)
|
693
|
+
if (!extraData) {
|
694
|
+
return
|
695
|
+
}
|
696
|
+
|
697
|
+
// 确认对话框
|
698
|
+
const confirmContent = isWaitingBranch
|
699
|
+
? '确定完成当前分支么?完成后将等待其他分支,不会立即流转到下一环节。'
|
700
|
+
: '确定提交么?提交之后数据不可更改!'
|
701
|
+
|
702
|
+
await new Promise(resolve => {
|
703
|
+
this.$confirm({
|
704
|
+
title: '提交确认',
|
705
|
+
content: confirmContent,
|
706
|
+
onOk () {
|
707
|
+
resolve()
|
708
|
+
return Promise.resolve()
|
709
|
+
}
|
710
|
+
})
|
711
|
+
})
|
712
|
+
|
713
|
+
this.$refs.xAddForm.asyncSubmit().then(res => {
|
714
|
+
this.submitForm(res).then(_ => {
|
715
|
+
extraData.form = res.realForm
|
716
|
+
postByServiceName(workFlowViewApi.submitToNextStep, extraData)
|
717
|
+
.then(
|
718
|
+
() => {
|
719
|
+
let successMessage = '提交成功'
|
720
|
+
|
721
|
+
// 只有非等待分支节点才保存工作流日志
|
722
|
+
if (!isWaitingBranch) {
|
723
|
+
const branchStatus = this.isBranchLastNode
|
724
|
+
const operation = branchStatus.isBranchNode && branchStatus.isLastBranch ? '分支汇合' : '提交'
|
725
|
+
|
726
|
+
const extra = {
|
727
|
+
setHandler: this.getStepHandler(),
|
728
|
+
setDeadline: this.deadline,
|
729
|
+
notes: this.note.trim()
|
730
|
+
}
|
731
|
+
this.saveWorkflowLog(operation, this.generateBranchStepChangeText(this.currentStepId), extra)
|
732
|
+
} else {
|
733
|
+
successMessage = '分支完成,等待其他分支完成后自动汇合'
|
734
|
+
}
|
735
|
+
|
736
|
+
this.$message.success(successMessage)
|
737
|
+
this.loading = true
|
738
|
+
this.loadingHistory = true
|
739
|
+
this.$emit('nextClick', {
|
740
|
+
note: this.note.trim(),
|
741
|
+
form: res.realForm,
|
742
|
+
workflowId: this.workflowId,
|
743
|
+
isBranchWaiting: isWaitingBranch, // 标记是否为分支等待状态
|
744
|
+
...this.generateStepChange(this.currentStepId, this.nextBtnTo)
|
745
|
+
})
|
746
|
+
this.$emit('refresh')
|
747
|
+
this.onClose()
|
748
|
+
this.init()
|
749
|
+
},
|
750
|
+
err => {
|
751
|
+
this.$message.error('提交失败!')
|
752
|
+
console.log(err)
|
753
|
+
}
|
754
|
+
)
|
755
|
+
})
|
756
|
+
}).catch((err) => {
|
757
|
+
if (err && err.message === 'Form validation failed') {
|
758
|
+
this.$message.error('请检查表单必填项!')
|
759
|
+
} else {
|
760
|
+
// 对于其他错误,继续向上抛出
|
761
|
+
throw err
|
762
|
+
}
|
763
|
+
})
|
764
|
+
},
|
765
|
+
async preClick () {
|
766
|
+
const notes = this.backNote.trim()
|
767
|
+
if (!notes) {
|
768
|
+
this.$message.error('退回请在备注中填写理由')
|
769
|
+
return
|
770
|
+
}
|
771
|
+
return postByServiceName(workFlowViewApi.updateWorkFlowState, {
|
772
|
+
stepId: this.preBtnTo,
|
773
|
+
workflowId: this.workflowId,
|
774
|
+
type: 'back'
|
775
|
+
})
|
776
|
+
.then(
|
777
|
+
res => {
|
778
|
+
this.saveWorkflowLog('退回', this.generateStepChangeText(this.currentStepId, this.preBtnTo), { notes })
|
779
|
+
this.$message.success('退回成功')
|
780
|
+
this.backNote = '' // 退回成功后清空退回原因
|
781
|
+
this.loading = true
|
782
|
+
this.loadingHistory = true
|
783
|
+
this.currentStepId = this.preBtnTo
|
784
|
+
this.activeStepId = this.preBtnTo
|
785
|
+
|
786
|
+
// 新增:重置按钮状态
|
787
|
+
this.stepDone = false
|
788
|
+
this.beforeStepActive = false
|
789
|
+
this.operationType = 'submit'
|
790
|
+
|
791
|
+
this.$emit('refresh')
|
792
|
+
this.onClose()
|
793
|
+
this.init()
|
794
|
+
},
|
795
|
+
err => {
|
796
|
+
this.$message.error('退回失败!')
|
797
|
+
console.log(err)
|
798
|
+
}
|
799
|
+
)
|
800
|
+
},
|
801
|
+
async stepNextClick () {
|
802
|
+
const extraData = this.getApplyStepExtraData(this.stepNextBtnTo)
|
803
|
+
if (!extraData) {
|
804
|
+
return
|
805
|
+
}
|
806
|
+
this.$refs.xAddForm.asyncSubmit().then(res => {
|
807
|
+
this.submitForm(res).then(_ => {
|
808
|
+
extraData.form = res.realForm
|
809
|
+
postByServiceName(workFlowViewApi.submitToNextStep, extraData)
|
810
|
+
.then(
|
811
|
+
() => {
|
812
|
+
const extra = {
|
813
|
+
setHandler: this.getStepHandler(),
|
814
|
+
setDeadline: this.deadline,
|
815
|
+
notes: this.note.trim()
|
816
|
+
}
|
817
|
+
this.saveWorkflowLog('跳过', this.generateBranchStepChangeText(this.currentStepId), extra)
|
818
|
+
this.$message.success('提交成功')
|
819
|
+
this.$emit('nextClick', {
|
820
|
+
note: this.note.trim(),
|
821
|
+
form: res.realForm,
|
822
|
+
workflowId: this.workflowId,
|
823
|
+
...this.generateStepChange(this.currentStepId, this.stepNextBtnTo)
|
824
|
+
})
|
825
|
+
this.loading = true
|
826
|
+
this.loadingHistory = true
|
827
|
+
this.$emit('refresh')
|
828
|
+
this.onClose()
|
829
|
+
this.init()
|
830
|
+
},
|
831
|
+
err => {
|
832
|
+
this.$message.error('提交失败!')
|
833
|
+
console.log(err)
|
834
|
+
}
|
835
|
+
)
|
836
|
+
})
|
837
|
+
}).catch(err => {
|
838
|
+
if (err && err.message === 'Form validation failed') {
|
839
|
+
this.$message.error('请检查表单必填项!')
|
840
|
+
} else {
|
841
|
+
// 对于其他错误,继续向上抛出
|
842
|
+
throw err
|
843
|
+
}
|
844
|
+
})
|
845
|
+
},
|
846
|
+
// 获取当前步骤节点,连通的节点
|
847
|
+
async getDirection () {
|
848
|
+
// 获取流程定义
|
849
|
+
return postByServiceName(workFlowViewApi.getWorkFlowDefine, {
|
850
|
+
id: this.workflowId
|
851
|
+
})
|
852
|
+
.then(async res => {
|
853
|
+
this.directions = []
|
854
|
+
this.stepsDefine = res.steps
|
855
|
+
await this.resolveDirections()
|
856
|
+
this.resolveStep()
|
857
|
+
}, err => {
|
858
|
+
console.log(err)
|
859
|
+
})
|
860
|
+
},
|
861
|
+
// 分析当前节点,能通向的节点
|
862
|
+
async resolveDirections () {
|
863
|
+
const currentStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
864
|
+
if (currentStep?.properties?.actions) {
|
865
|
+
this.currentDirections = currentStep.properties.actions
|
866
|
+
}
|
867
|
+
// 判断是否是最后ige节点
|
868
|
+
this.lastStep = (currentStep?.properties?.actions || []).filter(item => {
|
869
|
+
return item.type !== 'back'
|
870
|
+
}).length === 0
|
871
|
+
|
872
|
+
// 处理跳转按钮
|
873
|
+
this.workflowControl()
|
874
|
+
|
875
|
+
if (!this.lastStep) {
|
876
|
+
// 分析分支节点并设置智能人员选择
|
877
|
+
await this.analyzeBranchNodes()
|
878
|
+
}
|
879
|
+
},
|
880
|
+
// 根据步骤id获取步骤名称
|
881
|
+
getStepNameByStepId (stepId) {
|
882
|
+
return this.stepsDefine.find(item => item.id === stepId)?.name
|
883
|
+
},
|
884
|
+
// 根据步骤id获取步骤状态
|
885
|
+
getStepStatusByStepId (stepId) {
|
886
|
+
return this.stepsForChild.find(item => item.id === stepId)?.status
|
887
|
+
},
|
888
|
+
// 表单提交的回调
|
889
|
+
submitForm (obj) {
|
890
|
+
this.formValid = true
|
891
|
+
const formData = obj.realForm
|
892
|
+
const time = this.format(new Date(), 'yyyy-MM-dd hh:mm:ss')
|
893
|
+
return postByServiceName(workFlowViewApi.saveWorkFlowStepFormData, {
|
894
|
+
workflowId: this.workflowId,
|
895
|
+
stepId: this.activeStepId,
|
896
|
+
form: formData,
|
897
|
+
data: time,
|
898
|
+
handler: this.currUser.name,
|
899
|
+
note: this.note.trim()
|
900
|
+
})
|
901
|
+
.then(
|
902
|
+
res => {
|
903
|
+
console.log('表单提交成功')
|
904
|
+
this.note = ''
|
905
|
+
this.showForm = false
|
906
|
+
this.stepDone = true
|
907
|
+
},
|
908
|
+
err => {
|
909
|
+
this.$message.error('保存失败,请检查后重试')
|
910
|
+
console.log(err)
|
911
|
+
}
|
912
|
+
)
|
913
|
+
},
|
914
|
+
// 获取当前步骤定义内容,构建组件
|
915
|
+
async buildComp (stepId) {
|
916
|
+
const properties = this.stepsDefine.find(item => item.id === stepId).properties
|
917
|
+
// 表单的渲染
|
918
|
+
if (properties.form && properties.form.formJson) {
|
919
|
+
this.stepDefine = properties.form.formJson
|
920
|
+
this.showForm = true
|
921
|
+
this.$nextTick(() => {
|
922
|
+
this.$refs.xAddForm && this.$refs.xAddForm.init({
|
923
|
+
...properties.form,
|
924
|
+
businessType: '修改',
|
925
|
+
formItems: this.stepDefine,
|
926
|
+
layout: properties.form.xAddFormLayout,
|
927
|
+
showSubmitBtn: false
|
928
|
+
})
|
929
|
+
// 初始化的数据渲染(流程第一步)
|
930
|
+
console.log('导入的原始数据-json', this.stepsForChild[0].f_data)
|
931
|
+
console.log('转换后的数据-对象', JSON.parse(this.stepsForChild[0].f_data))
|
932
|
+
if (stepId === 1) {
|
933
|
+
this.$refs.xAddForm.setForm(JSON.parse(this.stepsForChild[0].f_data))
|
934
|
+
}
|
935
|
+
})
|
936
|
+
} else {
|
937
|
+
this.showForm = false
|
938
|
+
}
|
939
|
+
// Tab的渲染
|
940
|
+
this.tabDesigner = properties.tabDesigner
|
941
|
+
this.showTab = !!this.tabDesigner
|
942
|
+
// 以当前激活节点分析节点
|
943
|
+
await this.resolveDirections()
|
944
|
+
this.resolveStep()
|
945
|
+
},
|
946
|
+
// 根据当前节点,判断之后流程,以及按钮的显示
|
947
|
+
workflowControl () {
|
948
|
+
// 重置所有控制数据为默认值,避免之前状态的影响
|
949
|
+
this.showNextBtn = false
|
950
|
+
this.nextBtnTo = undefined
|
951
|
+
this.nextBtnTitle = ''
|
952
|
+
this.showStepNextBtn = false
|
953
|
+
this.stepNextBtnTo = undefined
|
954
|
+
this.stepNextBtnTitle = ''
|
955
|
+
this.stepNextBtnText = []
|
956
|
+
this.showPrevBtn = false
|
957
|
+
this.preBtnTo = undefined
|
958
|
+
this.preBtnTitle = ''
|
959
|
+
this.preBtnText = []
|
960
|
+
|
961
|
+
// 分类收集不同类型的actions
|
962
|
+
const submitActions = this.currentDirections.filter(item => item.type === 'submit')
|
963
|
+
const conditionalActions = this.currentDirections.filter(item => item.type === 'conditionalBranch')
|
964
|
+
const parallelActions = this.currentDirections.filter(item => item.type === 'parallelBranch')
|
965
|
+
const skipActions = this.currentDirections.filter(item => item.type === 'skip')
|
966
|
+
const backActions = this.currentDirections.filter(item => item.type === 'back')
|
967
|
+
|
968
|
+
// 处理提交按钮 - 优先级:submit > conditionalBranch > parallelBranch
|
969
|
+
if (submitActions.length > 0) {
|
970
|
+
this.showNextBtn = true
|
971
|
+
this.nextBtnTo = submitActions[0].to // 如果有多个submit,取第一个作为主要跳转目标
|
972
|
+
if (submitActions.length === 1) {
|
973
|
+
this.nextBtnTitle = '进行下一环节:' + this.getStepNameByStepId(submitActions[0].to)
|
974
|
+
} else {
|
975
|
+
this.nextBtnTitle = '将进入以下环节:' + submitActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
976
|
+
}
|
977
|
+
} else if (conditionalActions.length > 0) {
|
978
|
+
this.showNextBtn = true
|
979
|
+
this.nextBtnTo = conditionalActions[0].to // 条件分支的第一个作为主要跳转目标
|
980
|
+
const targetSteps = conditionalActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
981
|
+
this.nextBtnTitle = '后台判断后跳转到:' + targetSteps
|
982
|
+
} else if (parallelActions.length > 0) {
|
983
|
+
this.showNextBtn = true
|
984
|
+
this.nextBtnTo = parallelActions[0].to // 并行分支的第一个作为主要跳转目标
|
985
|
+
const targetSteps = parallelActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
986
|
+
this.nextBtnTitle = '将并行进入以下分支:' + targetSteps
|
987
|
+
}
|
988
|
+
|
989
|
+
// 处理跳过按钮
|
990
|
+
if (skipActions.length > 0) {
|
991
|
+
this.showStepNextBtn = true
|
992
|
+
this.stepNextBtnTo = skipActions[0].to
|
993
|
+
if (skipActions.length === 1) {
|
994
|
+
this.stepNextBtnTitle = '跳至:' + this.getStepNameByStepId(skipActions[0].to) + '环节'
|
995
|
+
this.stepNextBtnText.push('将跳过以下环节:')
|
996
|
+
for (let i = this.currentStepId; i < skipActions[0].to - 1; i++) {
|
997
|
+
this.stepNextBtnText.push(this.stepsDefine[i].name)
|
998
|
+
}
|
999
|
+
} else {
|
1000
|
+
const targetSteps = skipActions.map(item => this.getStepNameByStepId(item.to)).join(' , ')
|
1001
|
+
this.stepNextBtnTitle = '跳至:' + targetSteps
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
// 处理退回按钮
|
1006
|
+
if (backActions.length > 0) {
|
1007
|
+
const backAction = backActions[0] // 通常只有一个back action
|
1008
|
+
for (let i = this.currentStepId - 1; i > 0; i--) {
|
1009
|
+
if (backAction.to >= i && this.stepsForChild.find(item => item.id === i)?.handler) {
|
1010
|
+
this.preBtnTo = i
|
1011
|
+
this.preBtnTitle = '回退至:' + this.getStepNameByStepId(i) + '环节'
|
1012
|
+
this.showPrevBtn = true
|
1013
|
+
break
|
1014
|
+
} else {
|
1015
|
+
this.preBtnText.push(this.getStepNameByStepId(i))
|
1016
|
+
}
|
1017
|
+
}
|
1018
|
+
if (this.preBtnText.length) {
|
1019
|
+
this.preBtnText.unshift('将跳过以下环节:')
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
},
|
1023
|
+
// 获取表单字段实际值
|
1024
|
+
getRealKey (key, isHandleFormKey) {
|
1025
|
+
if (key === 'selected_id') return key
|
1026
|
+
if (isHandleFormKey) {
|
1027
|
+
return key.substring(key.indexOf('_') + 1)
|
1028
|
+
} else {
|
1029
|
+
return key
|
1030
|
+
}
|
1031
|
+
},
|
1032
|
+
// 加载完成
|
1033
|
+
resolveStep () {
|
1034
|
+
// 获取当前步骤的按钮组配置
|
1035
|
+
const currentStep = this.stepsDefine.find(item => item.id === this.activeStepId)
|
1036
|
+
if (currentStep && currentStep.properties && currentStep.properties.buttonGroup) {
|
1037
|
+
this.buttonGroup = currentStep.properties.buttonGroup
|
1038
|
+
} else {
|
1039
|
+
this.buttonGroup = null
|
1040
|
+
}
|
1041
|
+
this.loading = false
|
1042
|
+
},
|
1043
|
+
// 流程图组件给当前组件传值用,stepNo为用户点击的非当前步骤
|
1044
|
+
async activeStep (stepId) {
|
1045
|
+
// 开启加载
|
1046
|
+
this.loadingHistory = true
|
1047
|
+
this.activeStepId = stepId
|
1048
|
+
// 获取激活节点的步骤名
|
1049
|
+
this.activeStepName = this.getStepNameByStepId(stepId)
|
1050
|
+
const status = this.getStepStatusByStepId(stepId)
|
1051
|
+
// 清空回显数据
|
1052
|
+
this.formCompletedData = {}
|
1053
|
+
let formCompletedDataPreview = null
|
1054
|
+
this.getStepDefine(stepId)
|
1055
|
+
// 判断激活的节点,是不是待完成节点 (当前节点或者 当前节点状态是1的)
|
1056
|
+
if ((this.activeStepName !== this.currentStep.state && status !== 1) || this.workflowState) {
|
1057
|
+
// 获取激活节点历史数据,和字段定义
|
1058
|
+
await this.getCompletedFormData(stepId)
|
1059
|
+
// 将回显数据拷贝,避免引用传递
|
1060
|
+
formCompletedDataPreview = JSON.parse(JSON.stringify(this.formCompletedData))
|
1061
|
+
// 使用字段定义中内容,将回显数据的列名,替换为定义的中文名
|
1062
|
+
// 调整逻辑:formData中只显示流程配置表单中定义过的显示列,多余冗余的存储列不进行页面展示
|
1063
|
+
const formDataArr = []
|
1064
|
+
const dataObj = formCompletedDataPreview.data || {}
|
1065
|
+
const currentStepDefine = this.stepsDefine.find(item => item.id === stepId)
|
1066
|
+
const isKeyHandle = currentStepDefine?.properties?.form?.isKeyHandle || false
|
1067
|
+
for (let i = 0; i < this.targetStepDefine.length; i++) {
|
1068
|
+
const stepDefine = this.targetStepDefine[i]
|
1069
|
+
const key = this.getRealKey(stepDefine.model, isKeyHandle)
|
1070
|
+
if (Object.prototype.hasOwnProperty.call(dataObj, key)) {
|
1071
|
+
// 历史表单内容根据流程中配置的表单项顺序进行渲染,需要兼容表单项展示函数
|
1072
|
+
if (stepDefine.showFormItemFunc && !(await this.showFormItemFunc(stepDefine.showFormItemFunc, dataObj))) {
|
1073
|
+
continue
|
1074
|
+
}
|
1075
|
+
let value = dataObj[key]
|
1076
|
+
// 字典值处理
|
1077
|
+
if (stepDefine.formType === 'select' && stepDefine.selectType === 'key') {
|
1078
|
+
const dictList = this.$appdata.getDictionaryList(stepDefine.selectKey)
|
1079
|
+
const dictItem = dictList.find(item => item.value === value)
|
1080
|
+
value = dictItem ? dictItem.label : value
|
1081
|
+
}
|
1082
|
+
formDataArr.push({ label: stepDefine.name, value })
|
1083
|
+
}
|
1084
|
+
}
|
1085
|
+
// 如果一个都没匹配上,兼容旧逻辑:把原对象转成数组
|
1086
|
+
if (formDataArr.length === 0 && dataObj && typeof dataObj === 'object') {
|
1087
|
+
for (const key in dataObj) {
|
1088
|
+
if (Object.prototype.hasOwnProperty.call(dataObj, key)) {
|
1089
|
+
formDataArr.push({ label: key, value: dataObj[key] })
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
}
|
1093
|
+
formCompletedDataPreview.data = formDataArr.length > 0 ? formDataArr : null
|
1094
|
+
if (!formCompletedDataPreview.data) {
|
1095
|
+
formCompletedDataPreview.data = null
|
1096
|
+
}
|
1097
|
+
// 备注
|
1098
|
+
formCompletedDataPreview.note = this.stepsForChild.find(item => item.id === stepId)?.note
|
1099
|
+
if (!formCompletedDataPreview.data && !formCompletedDataPreview.files.length && !formCompletedDataPreview.images.length && !formCompletedDataPreview.note) {
|
1100
|
+
formCompletedDataPreview = {}
|
1101
|
+
}
|
1102
|
+
this.formCompletedDataPreview = formCompletedDataPreview
|
1103
|
+
// 渲染已完成步骤的Tab
|
1104
|
+
const properties = this.stepsDefine.find(item => item.id === stepId).properties
|
1105
|
+
this.tabDesigner = properties.tabDesigner
|
1106
|
+
this.showTab = !!this.tabDesigner
|
1107
|
+
// 完成
|
1108
|
+
this.loadingHistory = false
|
1109
|
+
this.beforeStepActive = this.activeStepName !== this.currentStep.state
|
1110
|
+
} else {
|
1111
|
+
this.loadingHistory = false
|
1112
|
+
this.beforeStepActive = false
|
1113
|
+
if (!this.renderCurrentNode) {
|
1114
|
+
this.formCompletedDataPreview = null
|
1115
|
+
this.showTab = false
|
1116
|
+
this.beforeStepActive = true
|
1117
|
+
return
|
1118
|
+
}
|
1119
|
+
await this.buildComp(this.activeStepId)
|
1120
|
+
}
|
1121
|
+
},
|
1122
|
+
// 获取已经完成步骤的数据
|
1123
|
+
getCompletedFormData (stepId) {
|
1124
|
+
return postByServiceName(workFlowViewApi.getWorkFlowCompletedStepData, {
|
1125
|
+
workflowId: this.workflowId,
|
1126
|
+
stepId: stepId
|
1127
|
+
})
|
1128
|
+
.then(
|
1129
|
+
res => {
|
1130
|
+
this.formCompletedData = res
|
1131
|
+
},
|
1132
|
+
err => {
|
1133
|
+
console.log(err)
|
1134
|
+
}
|
1135
|
+
)
|
1136
|
+
},
|
1137
|
+
// 获取步骤定义表中,当前步骤定义
|
1138
|
+
getStepDefine (stepId) {
|
1139
|
+
const stepName = this.getStepNameByStepId(stepId)
|
1140
|
+
this.targetStepDefine = this.getSingleStepDefine(stepName).formJson
|
1141
|
+
},
|
1142
|
+
// 获取提交步骤的额外数据
|
1143
|
+
getApplyStepExtraData (stepId) {
|
1144
|
+
// 验证人员选择 - 只有在需要显示人员选择器的情况下才验证
|
1145
|
+
// 判断条件与模板中的 WorkflowPersonSelector 显示条件保持一致
|
1146
|
+
const shouldShowPersonSelector = !this.isBranchLastNode.isBranchNode || this.isBranchLastNode.isLastBranch
|
1147
|
+
|
1148
|
+
if (shouldShowPersonSelector && this.needSelectPerson) {
|
1149
|
+
if (this.needMultipleBranchSelection) {
|
1150
|
+
// 多分支情况:检查是否所有需要的分支都选择了人员
|
1151
|
+
const missingSelections = this.branchNodes.filter(node => !this.branchChargePersons[node.stepId])
|
1152
|
+
if (missingSelections.length > 0) {
|
1153
|
+
const missingNames = missingSelections.map(node => node.stepName).join('、')
|
1154
|
+
this.$message.error(`请设置以下节点的处理人:${missingNames}`)
|
1155
|
+
return false
|
1156
|
+
}
|
1157
|
+
} else {
|
1158
|
+
// 单分支情况:检查是否选择了处理人
|
1159
|
+
if (!this.checkedChargePerson) {
|
1160
|
+
this.$message.error('请设置下一环节处理人')
|
1161
|
+
return false
|
1162
|
+
}
|
1163
|
+
}
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
// 统一获取目标步骤IDs
|
1167
|
+
let stepIds = []
|
1168
|
+
if (this.needMultipleBranchSelection) {
|
1169
|
+
// 多分支选择:获取所有分支的目标stepId(包括不需要选择人员的)
|
1170
|
+
if (!this.currentBranchActions) {
|
1171
|
+
this.currentBranchActions = this.getBranchActions()
|
1172
|
+
}
|
1173
|
+
stepIds = this.currentBranchActions.allBranchActions.map(action => action.to)
|
1174
|
+
} else if (this.calculatedTargetNode) {
|
1175
|
+
// 条件判断节点:使用计算出的目标节点
|
1176
|
+
stepIds = [this.calculatedTargetNode]
|
1177
|
+
} else {
|
1178
|
+
// 普通节点:使用传入的stepId
|
1179
|
+
stepIds = [stepId]
|
1180
|
+
}
|
1181
|
+
// 处理bug 有的时候没带到 branchChargePersons 先循环在同一地方处理
|
1182
|
+
stepIds.forEach(stepItemId => {
|
1183
|
+
if (!this.branchChargePersons[stepItemId]) {
|
1184
|
+
const chargePerson = this.stepsForChild.find(item => item.id === stepItemId)?.properties?.chargePerson
|
1185
|
+
this.branchChargePersons[stepItemId] = this.normalizeChargePersonFormat(chargePerson)
|
1186
|
+
}
|
1187
|
+
})
|
1188
|
+
|
1189
|
+
return {
|
1190
|
+
workflowId: this.workflowId,
|
1191
|
+
activeStepId: this.activeStepId,
|
1192
|
+
stepId, // 当前步骤ID
|
1193
|
+
stepIds, // 目标步骤IDs数组(统一格式)
|
1194
|
+
name: this.getStepNameByStepId(stepId),
|
1195
|
+
handler: this.getStepHandler(),
|
1196
|
+
handlerId: this.checkedChargePerson,
|
1197
|
+
needSelectPerson: this.needSelectPerson,
|
1198
|
+
personList: this.chargePerson.personList,
|
1199
|
+
deadline: this.deadline,
|
1200
|
+
submitUser: this.currUser.name,
|
1201
|
+
submitUserId: this.currUser.id,
|
1202
|
+
branchChargePersons: this.branchChargePersons
|
1203
|
+
}
|
1204
|
+
},
|
1205
|
+
|
1206
|
+
// 获取当前选择的负责人
|
1207
|
+
getStepHandler () {
|
1208
|
+
let stepHandler
|
1209
|
+
|
1210
|
+
if (this.needMultipleBranchSelection) {
|
1211
|
+
// 多分支情况:返回所有分支的人员信息
|
1212
|
+
const selectedHandlers = []
|
1213
|
+
for (const node of this.branchNodes) {
|
1214
|
+
const branchData = this.branchChargePersons[node.stepId]
|
1215
|
+
|
1216
|
+
if (node.needSelectPerson && branchData) {
|
1217
|
+
// 需要选择人员的分支:显示选中的人员
|
1218
|
+
const personName = this.getBranchPersonName(node.stepId)
|
1219
|
+
selectedHandlers.push(`${node.stepName}:${personName}`)
|
1220
|
+
} else if (!node.needSelectPerson && branchData) {
|
1221
|
+
// 不需要选择人员的分支:显示角色/部门配置
|
1222
|
+
if (branchData.personList && branchData.personList.length > 0) {
|
1223
|
+
const personNames = branchData.personList.map(item => item.name).join(',')
|
1224
|
+
selectedHandlers.push(`${node.stepName}:${personNames}`)
|
1225
|
+
}
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
stepHandler = selectedHandlers.join(';')
|
1229
|
+
} else {
|
1230
|
+
// 单分支情况:原有逻辑
|
1231
|
+
if (this.checkedChargePerson) {
|
1232
|
+
// 使用 value 找到对应的 label
|
1233
|
+
stepHandler = this.chargePersonOptions.find(item => item.value === this.checkedChargePerson)?.label
|
1234
|
+
} else if (this.chargePerson.personList && this.chargePerson.personList.length > 0) {
|
1235
|
+
stepHandler = this.chargePerson.personList.map(item => item.name).join(',')
|
1236
|
+
}
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
return stepHandler
|
1240
|
+
},
|
1241
|
+
|
1242
|
+
// 获取分支节点选择的人员姓名
|
1243
|
+
getBranchPersonName (stepId) {
|
1244
|
+
const personId = this.branchChargePersons[stepId]
|
1245
|
+
if (!personId) return ''
|
1246
|
+
|
1247
|
+
const node = this.branchNodes.find(n => n.stepId === stepId)
|
1248
|
+
if (!node) return ''
|
1249
|
+
|
1250
|
+
const person = node.chargePersonOptions.find(p => p.value === personId)
|
1251
|
+
return person ? person.label : ''
|
1252
|
+
},
|
1253
|
+
// 生成工作流日志步骤变化描述
|
1254
|
+
generateStepChangeText (fromStepId, toStepId) {
|
1255
|
+
// 如果是多分支场景,toStepId可能是数组或字符串
|
1256
|
+
if (this.needMultipleBranchSelection && Array.isArray(toStepId)) {
|
1257
|
+
const targetSteps = toStepId.map(id => `第${id}步: ${this.getStepNameByStepId(id)}`).join('、')
|
1258
|
+
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${targetSteps}`
|
1259
|
+
} else if (this.needMultipleBranchSelection && typeof toStepId === 'string') {
|
1260
|
+
// 如果传入的是目标步骤名称字符串
|
1261
|
+
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${toStepId}`
|
1262
|
+
} else {
|
1263
|
+
// 单步骤场景
|
1264
|
+
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> 第${toStepId}步: ${this.getStepNameByStepId(toStepId)}`
|
1265
|
+
}
|
1266
|
+
},
|
1267
|
+
|
1268
|
+
// 生成多分支场景的步骤变化描述
|
1269
|
+
generateBranchStepChangeText (fromStepId) {
|
1270
|
+
if (!this.needMultipleBranchSelection) {
|
1271
|
+
return this.generateStepChangeText(fromStepId, this.nextBtnTo)
|
1272
|
+
}
|
1273
|
+
|
1274
|
+
// 使用所有分支节点生成描述
|
1275
|
+
const targetSteps = this.branchNodes.map(node => `第${node.stepId}步: ${node.stepName}`).join('、')
|
1276
|
+
return `第${fromStepId}步: ${this.getStepNameByStepId(fromStepId)} --> ${targetSteps}`
|
1277
|
+
},
|
1278
|
+
|
1279
|
+
generateStepChange (fromStepId, toStepId) {
|
1280
|
+
// 获取目标步骤IDs数组
|
1281
|
+
let stepIds = []
|
1282
|
+
|
1283
|
+
if (this.needMultipleBranchSelection) {
|
1284
|
+
// 多分支选择:获取所有分支的目标stepId(包括不需要选择人员的)
|
1285
|
+
if (!this.currentBranchActions) {
|
1286
|
+
this.currentBranchActions = this.getBranchActions()
|
1287
|
+
}
|
1288
|
+
stepIds = this.currentBranchActions.allBranchActions.map(action => action.to)
|
1289
|
+
} else if (this.calculatedTargetNode) {
|
1290
|
+
// 条件判断节点:使用计算出的目标节点
|
1291
|
+
stepIds = [this.calculatedTargetNode]
|
1292
|
+
} else {
|
1293
|
+
// 普通节点:使用传入的stepId
|
1294
|
+
stepIds = [toStepId]
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
return {
|
1298
|
+
formStepId: fromStepId,
|
1299
|
+
fromStepId,
|
1300
|
+
stepId: toStepId,
|
1301
|
+
stepIds: stepIds,
|
1302
|
+
formStep: this.getStepNameByStepId(fromStepId),
|
1303
|
+
fromStep: this.getStepNameByStepId(fromStepId),
|
1304
|
+
toStep: this.getStepNameByStepId(stepIds[0]),
|
1305
|
+
successStepId: this.stepsDefine[this.stepsDefine.length - 1].id,
|
1306
|
+
successStep: this.stepsDefine[this.stepsDefine.length - 1].name
|
1307
|
+
}
|
1308
|
+
},
|
1309
|
+
// 保存工作流日志
|
1310
|
+
saveWorkflowLog (operation, desc, extra) {
|
1311
|
+
postByServiceName(workFlowViewApi.saveWorkFlowLog, {
|
1312
|
+
workflowId: this.workflowId,
|
1313
|
+
operation,
|
1314
|
+
desc,
|
1315
|
+
operator: this.currUser.name,
|
1316
|
+
notes: '',
|
1317
|
+
setHandler: '',
|
1318
|
+
setDeadline: '',
|
1319
|
+
...extra
|
1320
|
+
})
|
1321
|
+
},
|
1322
|
+
// 获取默认截止时间
|
1323
|
+
getDefaultDeadline (day = 1) {
|
1324
|
+
const date = new Date()
|
1325
|
+
date.setDate(date.getDate() + day)
|
1326
|
+
date.setHours(date.getHours() + 2)
|
1327
|
+
return formatDate(date, 'yyyy-MM-dd hh:mm')
|
1328
|
+
},
|
1329
|
+
// 验证截止时间
|
1330
|
+
checkDeadline (alert) {
|
1331
|
+
const deadline = moment(this.deadline)
|
1332
|
+
if (deadline.isAfter(this.completeTime, 'day')) {
|
1333
|
+
this.deadlineValidateStatus = 'error'
|
1334
|
+
this.deadlineHelp = '不能超过任务限定完成时间'
|
1335
|
+
if (alert) {
|
1336
|
+
this.$message.error('下一环节截止时间不能超过任务限定完成时间,如需设置,请联系发起人修改任务完成时间', 5)
|
1337
|
+
}
|
1338
|
+
return false
|
1339
|
+
}
|
1340
|
+
if (deadline.diff(moment(), 'hours') < 1) {
|
1341
|
+
this.deadlineValidateStatus = 'error'
|
1342
|
+
this.deadlineHelp = '下一环节截止时间只能在1小时之后'
|
1343
|
+
return false
|
1344
|
+
}
|
1345
|
+
this.deadlineValidateStatus = 'success'
|
1346
|
+
this.deadlineHelp = ''
|
1347
|
+
return true
|
1348
|
+
},
|
1349
|
+
// 操作类型单选按钮改变时重新设置负责人选择框
|
1350
|
+
async handleOperationTypeChange (event) {
|
1351
|
+
this.checkedChargePerson = undefined
|
1352
|
+
this.branchChargePersons = {}
|
1353
|
+
// 重新分析分支节点
|
1354
|
+
await this.analyzeBranchNodes()
|
1355
|
+
},
|
1356
|
+
|
1357
|
+
// 处理动态按钮点击
|
1358
|
+
handleCustomButtonClick (button) {
|
1359
|
+
try {
|
1360
|
+
// 执行自定义函数
|
1361
|
+
if (button.func) {
|
1362
|
+
const result = executeStrFunctionByContext(this, button.func, [this.details, this.$refs.xAddForm.form, util, runLogic, getConfigByNameAsync])
|
1363
|
+
if (result) {
|
1364
|
+
// 如果返回true,执行对应的操作
|
1365
|
+
if (button.text === '提交') {
|
1366
|
+
this.nextClick()
|
1367
|
+
} else if (button.text === '取消') {
|
1368
|
+
this.$emit('cancel')
|
1369
|
+
}
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
} catch (error) {
|
1373
|
+
console.error('执行自定义按钮函数失败:', error)
|
1374
|
+
this.$message.error('执行操作失败')
|
1375
|
+
}
|
1376
|
+
},
|
1377
|
+
// 表单项展示函数--用来渲染历史节点数据时和填写表单显示内容同步
|
1378
|
+
async showFormItemFunc (func, form) {
|
1379
|
+
try {
|
1380
|
+
if (func) {
|
1381
|
+
// 一般展示项函数中不应该存在setForm函数 先屏蔽this.setForm和this.attr的传递还有在this上下文指向不同可能存在异常 流程表单的展示项函数尽量功能单一。有异常默认进行展示(先兼容到这后续有问题进行调整)
|
1382
|
+
const obj = executeStrFunctionByContext(this, func, [form, null, null, util, '新增/修改'])
|
1383
|
+
// 判断是 bool 还是 obj 兼容
|
1384
|
+
if (typeof obj === 'boolean') {
|
1385
|
+
return obj
|
1386
|
+
} else if (obj && typeof obj === 'object') {
|
1387
|
+
// obj 是一个对象,并且不是数组
|
1388
|
+
return obj?.show
|
1389
|
+
}
|
1390
|
+
} else {
|
1391
|
+
return true
|
1392
|
+
}
|
1393
|
+
} catch (e) {
|
1394
|
+
return true
|
1395
|
+
}
|
1396
|
+
},
|
1397
|
+
// 检查按钮是否显示
|
1398
|
+
checkButtonVisible (button) {
|
1399
|
+
try {
|
1400
|
+
if (button.customFunction) {
|
1401
|
+
return executeStrFunctionByContext(this, button.customFunction, [this.details, this.$refs.xAddForm.form, util, runLogic, getConfigByNameAsync])
|
1402
|
+
}
|
1403
|
+
return true
|
1404
|
+
} catch (error) {
|
1405
|
+
console.error('执行按钮显示函数失败:', error)
|
1406
|
+
return false
|
1407
|
+
}
|
1408
|
+
},
|
1409
|
+
formItemEmitFunc (func, data, value) {
|
1410
|
+
this.$emit('x-form-item-emit-func', func, data, value)
|
1411
|
+
},
|
1412
|
+
// 检查条件表达式是否包含WF_RESULT
|
1413
|
+
checkIfContainsWfResult () {
|
1414
|
+
const conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1415
|
+
if (conditionalActions.length === 0) return false
|
1416
|
+
|
1417
|
+
return conditionalActions.some(action => {
|
1418
|
+
return action.expression && action.expression.includes('WF_RESULT')
|
1419
|
+
})
|
1420
|
+
},
|
1421
|
+
|
1422
|
+
// 分析分支节点并设置选择框
|
1423
|
+
async analyzeBranchNodes () {
|
1424
|
+
try {
|
1425
|
+
// 初始化状态
|
1426
|
+
this.resetBranchSelection()
|
1427
|
+
|
1428
|
+
// 获取所有类型的分支动作并缓存
|
1429
|
+
this.currentBranchActions = this.getBranchActions()
|
1430
|
+
|
1431
|
+
// 如果没有任何分支,处理普通流程
|
1432
|
+
if (!this.currentBranchActions.hasAnyBranch) {
|
1433
|
+
await this.handleNormalFlow()
|
1434
|
+
return
|
1435
|
+
}
|
1436
|
+
|
1437
|
+
// 判断是否需要多分支选择
|
1438
|
+
this.needMultipleBranchSelection = this.shouldUseMultipleBranchSelection(this.currentBranchActions)
|
1439
|
+
|
1440
|
+
if (this.needMultipleBranchSelection) {
|
1441
|
+
// 需要为多个分支预先选择人员
|
1442
|
+
await this.setupMultipleBranchSelection(this.currentBranchActions.allBranchActions)
|
1443
|
+
} else {
|
1444
|
+
// 可以前台实时计算的条件分支
|
1445
|
+
await this.calculateTargetNodeFromForm(this.currentBranchActions.conditionalActions)
|
1446
|
+
}
|
1447
|
+
} catch (error) {
|
1448
|
+
console.error('分析分支节点失败:', error)
|
1449
|
+
this.$message.error('工作流分支配置异常,请联系管理员')
|
1450
|
+
// 降级处理:使用普通流程
|
1451
|
+
await this.handleNormalFlow()
|
1452
|
+
}
|
1453
|
+
},
|
1454
|
+
|
1455
|
+
// 重置分支选择状态
|
1456
|
+
resetBranchSelection () {
|
1457
|
+
this.branchNodes = []
|
1458
|
+
this.branchChargePersons = {}
|
1459
|
+
this.needMultipleBranchSelection = false
|
1460
|
+
this.calculatedTargetNode = null
|
1461
|
+
this.currentBranchActions = null
|
1462
|
+
},
|
1463
|
+
|
1464
|
+
// 获取分支动作分类
|
1465
|
+
getBranchActions () {
|
1466
|
+
const conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1467
|
+
const parallelActions = this.currentDirections.filter(action => action.type === 'parallelBranch')
|
1468
|
+
const allBranchActions = [...conditionalActions, ...parallelActions]
|
1469
|
+
|
1470
|
+
return {
|
1471
|
+
conditionalActions,
|
1472
|
+
parallelActions,
|
1473
|
+
allBranchActions,
|
1474
|
+
hasAnyBranch: allBranchActions.length > 0
|
1475
|
+
}
|
1476
|
+
},
|
1477
|
+
|
1478
|
+
// 判断是否应该使用多分支选择模式
|
1479
|
+
shouldUseMultipleBranchSelection (branchActions) {
|
1480
|
+
// 情况1: 有并行分支
|
1481
|
+
if (branchActions.parallelActions.length > 0) {
|
1482
|
+
return true
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
// 情况2: 条件分支包含WF_RESULT(后台结果决定)
|
1486
|
+
if (branchActions.conditionalActions.length > 0) {
|
1487
|
+
return this.checkIfContainsWfResult()
|
1488
|
+
}
|
1489
|
+
|
1490
|
+
return false
|
1491
|
+
},
|
1492
|
+
|
1493
|
+
// 根据表单数据计算目标节点
|
1494
|
+
async calculateTargetNodeFromForm (conditionalActions = null) {
|
1495
|
+
if (!conditionalActions) {
|
1496
|
+
conditionalActions = this.currentDirections.filter(action => action.type === 'conditionalBranch')
|
1497
|
+
}
|
1498
|
+
|
1499
|
+
if (conditionalActions.length === 0) {
|
1500
|
+
// 如果当前节点不是在分支流程中,才清空人员选择
|
1501
|
+
// 避免在并行分支节点中误清除人员选择框
|
1502
|
+
const currentStep = this.stepsForChild.find(item => item.id === this.activeStepId)
|
1503
|
+
const isInBranch = currentStep?.properties?.branchPath
|
1504
|
+
|
1505
|
+
if (!isInBranch) {
|
1506
|
+
this.clearPersonSelection()
|
1507
|
+
}
|
1508
|
+
return
|
1509
|
+
}
|
1510
|
+
|
1511
|
+
try {
|
1512
|
+
const formData = this.$refs.xAddForm?.form || {}
|
1513
|
+
|
1514
|
+
// 遍历条件找到匹配的
|
1515
|
+
for (const action of conditionalActions) {
|
1516
|
+
if (action.expression) {
|
1517
|
+
const result = await this.evaluateExpression(action.expression, formData)
|
1518
|
+
if (result) {
|
1519
|
+
this.calculatedTargetNode = action.to
|
1520
|
+
await this.setupSingleTargetPersonSelection(action.to)
|
1521
|
+
return
|
1522
|
+
}
|
1523
|
+
}
|
1524
|
+
}
|
1525
|
+
console.log('this.calculatedTargetNode', this.calculatedTargetNode)
|
1526
|
+
// 如果没有匹配的条件,清空选择
|
1527
|
+
this.clearPersonSelection()
|
1528
|
+
} catch (error) {
|
1529
|
+
console.warn('计算目标节点失败:', error)
|
1530
|
+
this.clearPersonSelection()
|
1531
|
+
}
|
1532
|
+
},
|
1533
|
+
|
1534
|
+
// 清空人员选择
|
1535
|
+
clearPersonSelection () {
|
1536
|
+
this.calculatedTargetNode = null
|
1537
|
+
this.needSelectPerson = false
|
1538
|
+
this.chargePersonOptions = []
|
1539
|
+
this.checkedChargePerson = undefined
|
1540
|
+
},
|
1541
|
+
|
1542
|
+
// 设置单个目标节点的人员选择
|
1543
|
+
async setupSingleTargetPersonSelection (stepId) {
|
1544
|
+
const stepDefine = this.stepsDefine.find(step => step.id === stepId)
|
1545
|
+
|
1546
|
+
if (!stepDefine?.properties?.chargePerson?.needSelectPerson) {
|
1547
|
+
this.needSelectPerson = false
|
1548
|
+
this.chargePersonOptions = []
|
1549
|
+
return
|
1550
|
+
}
|
1551
|
+
|
1552
|
+
// 设置人员选择
|
1553
|
+
this.chargePerson = stepDefine.properties.chargePerson
|
1554
|
+
this.checkedChargePerson = undefined
|
1555
|
+
this.chargePersonOptions = await this.getChargePersonOptionsForStep(stepId)
|
1556
|
+
|
1557
|
+
// 如果只有一个选项,自动选中
|
1558
|
+
if (this.chargePersonOptions.length === 1) {
|
1559
|
+
this.checkedChargePerson = this.chargePersonOptions[0].value
|
1560
|
+
}
|
1561
|
+
|
1562
|
+
this.needSelectPerson = true
|
1563
|
+
},
|
1564
|
+
|
1565
|
+
// 表单数据变化处理函数(将通过provide传递给表单组件)
|
1566
|
+
async handleFormDataChange (formData) {
|
1567
|
+
// 只有在不是多分支选择模式且当前活动步骤有条件分支动作时才重新计算
|
1568
|
+
if (!this.needMultipleBranchSelection && this.currentDirections.some(action => action.type === 'conditionalBranch')) {
|
1569
|
+
await this.calculateTargetNodeFromForm()
|
1570
|
+
}
|
1571
|
+
},
|
1572
|
+
|
1573
|
+
// 表达式评估 - 使用 LogicRunner
|
1574
|
+
async evaluateExpression (expression, formData) {
|
1575
|
+
try {
|
1576
|
+
// 构建参数对象,传递当前表单数据
|
1577
|
+
const params = {
|
1578
|
+
WF_FORM: { ...formData }
|
1579
|
+
}
|
1580
|
+
|
1581
|
+
// 使用 LogicRunner 执行表达式
|
1582
|
+
const result = await LogicRunner.runExpression(expression, params)
|
1583
|
+
return result
|
1584
|
+
} catch (error) {
|
1585
|
+
console.warn('表达式评估失败:', expression, error)
|
1586
|
+
return false
|
1587
|
+
}
|
1588
|
+
},
|
1589
|
+
|
1590
|
+
// 获取指定步骤的人员选项
|
1591
|
+
async getChargePersonOptionsForStep (stepId) {
|
1592
|
+
const define = this.stepsDefine.find(item => item.id === stepId)
|
1593
|
+
if (!define?.properties?.chargePerson) return []
|
1594
|
+
|
1595
|
+
const chargePerson = define.properties.chargePerson
|
1596
|
+
this.chargePerson = this.normalizeChargePersonFormat(chargePerson)
|
1597
|
+
|
1598
|
+
if (!chargePerson.needSelectPerson || !chargePerson.personList) return []
|
1599
|
+
|
1600
|
+
// 获取所有用户信息
|
1601
|
+
const allUser = await postByServiceName(commonApi.getAllUserOptionList, {})
|
1602
|
+
|
1603
|
+
// 根据配置筛选用户
|
1604
|
+
const options = this.filterUsersByPersonConfig(chargePerson.personList, allUser)
|
1605
|
+
|
1606
|
+
// 去重处理
|
1607
|
+
return Array.from(new Map(options.map(item => [item.value, item])).values())
|
1608
|
+
},
|
1609
|
+
|
1610
|
+
// 标准化人员配置格式(兼容旧格式)
|
1611
|
+
normalizeChargePersonFormat (chargePerson) {
|
1612
|
+
if (chargePerson.role || chargePerson.department) {
|
1613
|
+
chargePerson.needSelectPerson = true
|
1614
|
+
chargePerson.personList = [{
|
1615
|
+
type: chargePerson.role ? 'role' : 'department',
|
1616
|
+
name: chargePerson.role || chargePerson.department
|
1617
|
+
}]
|
1618
|
+
}
|
1619
|
+
return chargePerson
|
1620
|
+
},
|
1621
|
+
|
1622
|
+
// 根据人员配置筛选用户
|
1623
|
+
filterUsersByPersonConfig (personList, allUsers) {
|
1624
|
+
return personList.reduce((acc, personItem) => {
|
1625
|
+
let filteredUsers = []
|
1626
|
+
|
1627
|
+
if (personItem.type === 'role') {
|
1628
|
+
filteredUsers = allUsers.filter(user =>
|
1629
|
+
user.rolestr && user.rolestr.split(',').includes(personItem.name)
|
1630
|
+
).map(user => ({
|
1631
|
+
label: user.label,
|
1632
|
+
value: user.value
|
1633
|
+
}))
|
1634
|
+
} else if (personItem.type === 'department') {
|
1635
|
+
filteredUsers = allUsers.filter(user =>
|
1636
|
+
user.depname === personItem.name
|
1637
|
+
).map(user => ({
|
1638
|
+
label: user.label,
|
1639
|
+
value: user.value
|
1640
|
+
}))
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
return [...acc, ...filteredUsers]
|
1644
|
+
}, [])
|
1645
|
+
},
|
1646
|
+
|
1647
|
+
// 设置多分支人员选择
|
1648
|
+
async setupMultipleBranchSelection (branchActions) {
|
1649
|
+
this.branchNodes = []
|
1650
|
+
this.branchChargePersons = {}
|
1651
|
+
let hasPersonSelection = false
|
1652
|
+
|
1653
|
+
for (const action of branchActions) {
|
1654
|
+
const stepDefine = this.stepsDefine.find(step => step.id === action.to)
|
1655
|
+
const chargePerson = stepDefine?.properties?.chargePerson
|
1656
|
+
|
1657
|
+
// 所有分支节点都加入branchNodes,保持数据结构完整
|
1658
|
+
const nodeData = {
|
1659
|
+
stepId: action.to,
|
1660
|
+
stepName: this.getStepNameByStepId(action.to),
|
1661
|
+
chargePerson: chargePerson,
|
1662
|
+
needSelectPerson: chargePerson?.needSelectPerson || false,
|
1663
|
+
chargePersonOptions: []
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
if (chargePerson?.needSelectPerson) {
|
1667
|
+
// 需要选择人员的分支
|
1668
|
+
const chargePersonOptions = await this.getChargePersonOptionsForStep(action.to)
|
1669
|
+
nodeData.chargePersonOptions = chargePersonOptions
|
1670
|
+
|
1671
|
+
// 初始化选择值
|
1672
|
+
this.branchChargePersons[action.to] = undefined
|
1673
|
+
hasPersonSelection = true
|
1674
|
+
} else {
|
1675
|
+
// 不需要选择人员的分支,直接存储配置
|
1676
|
+
this.branchChargePersons[action.to] = chargePerson
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
this.branchNodes.push(nodeData)
|
1680
|
+
}
|
1681
|
+
|
1682
|
+
// 只有当存在需要选择人员的分支时才显示选择区域
|
1683
|
+
this.needSelectPerson = hasPersonSelection
|
1684
|
+
},
|
1685
|
+
|
1686
|
+
// 处理普通单线流程(没有分支的情况)
|
1687
|
+
async handleNormalFlow () {
|
1688
|
+
const targetStepId = this.operationType === 'skip' ? this.stepNextBtnTo : this.nextBtnTo
|
1689
|
+
|
1690
|
+
this.calculatedTargetNode = targetStepId
|
1691
|
+
const stepDefine = this.stepsDefine.find(step => step.id === targetStepId)
|
1692
|
+
|
1693
|
+
if (!stepDefine) {
|
1694
|
+
console.warn('未找到目标步骤定义:', targetStepId)
|
1695
|
+
this.clearPersonSelection()
|
1696
|
+
return
|
1697
|
+
}
|
1698
|
+
|
1699
|
+
const defineProperties = stepDefine.properties
|
1700
|
+
this.chargePerson = defineProperties?.chargePerson
|
1701
|
+
|
1702
|
+
// 兼容旧格式
|
1703
|
+
if (defineProperties.chargePerson) {
|
1704
|
+
defineProperties.chargePerson = this.normalizeChargePersonFormat(defineProperties.chargePerson)
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
if (defineProperties?.chargePerson?.needSelectPerson) {
|
1708
|
+
await this.setupSingleTargetPersonSelection(targetStepId)
|
1709
|
+
// 确保 branchChargePersons 中有该节点的数据结构
|
1710
|
+
this.branchChargePersons[targetStepId] = {
|
1711
|
+
handler: '',
|
1712
|
+
handlerId: undefined,
|
1713
|
+
...defineProperties.chargePerson
|
1714
|
+
}
|
1715
|
+
} else {
|
1716
|
+
// 不需要选择人员的情况,直接存储配置
|
1717
|
+
this.branchChargePersons[targetStepId] = defineProperties?.chargePerson || {}
|
1718
|
+
this.needSelectPerson = false
|
1719
|
+
this.chargePersonOptions = []
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
},
|
1723
|
+
watch: {}
|
1724
|
+
}
|
1725
|
+
</script>
|
1726
|
+
<style lang="less" scoped>
|
1727
|
+
.complete-data-title {
|
1728
|
+
margin-top: 8px;
|
1729
|
+
margin-bottom: 8px;
|
1730
|
+
}
|
1731
|
+
|
1732
|
+
:deep(.ant-result) {
|
1733
|
+
padding: 0;
|
1734
|
+
}
|
1735
|
+
|
1736
|
+
.descriptionPreviewItem {
|
1737
|
+
margin-bottom: 22px;
|
1738
|
+
|
1739
|
+
:deep(.ant-descriptions-view) {
|
1740
|
+
overflow: visible;
|
1741
|
+
}
|
1742
|
+
}
|
1743
|
+
|
1744
|
+
.allWidth {
|
1745
|
+
:deep(.ant-descriptions-item-content) {
|
1746
|
+
width: 100%;
|
1747
|
+
}
|
1748
|
+
}
|
1749
|
+
|
1750
|
+
.descriptionTitle {
|
1751
|
+
position: relative;
|
1752
|
+
padding-left: 12px;
|
1753
|
+
|
1754
|
+
&::before {
|
1755
|
+
content: '';
|
1756
|
+
position: absolute;
|
1757
|
+
left: 0;
|
1758
|
+
top: 50%;
|
1759
|
+
transform: translateY(-50%);
|
1760
|
+
width: 4px;
|
1761
|
+
height: 16px;
|
1762
|
+
background-color: @primary-color;
|
1763
|
+
border-radius: 2px;
|
1764
|
+
}
|
1765
|
+
}
|
1766
|
+
</style>
|