cloud-web-corejs 1.0.280 → 1.1.0-dev.10

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.
Files changed (193) hide show
  1. package/package.json +6 -2
  2. package/src/components/VabUpload/image-viewer.vue +442 -442
  3. package/src/components/VabUpload/index.vue +45 -3
  4. package/src/components/VabUpload/mixins.js +174 -34
  5. package/src/components/VabUpload/previewGroup.js +128 -0
  6. package/src/components/VabUpload/view.vue +248 -209
  7. package/src/components/baseTabs/mixins.js +181 -181
  8. package/src/components/bizTab/BizBillActions.vue +129 -0
  9. package/src/components/bizTab/BizTabListPage.vue +391 -0
  10. package/src/components/bizTab/README.md +378 -0
  11. package/src/components/bizTab/billTableUtil.js +48 -0
  12. package/src/components/bizTab/billValidators.js +136 -0
  13. package/src/components/bizTab/bizBillDetailMixin.js +705 -0
  14. package/src/components/bizTab/index.js +24 -0
  15. package/src/components/excelExport/exportFieldDialog.vue +23 -12
  16. package/src/components/excelExport/exportItemConfigUtil.js +30 -0
  17. package/src/components/excelExport/mixins.js +3 -3
  18. package/src/components/excelImport/index.vue +156 -156
  19. package/src/components/jsonImport/index.vue +1 -1
  20. package/src/components/langImport/index.vue +1 -1
  21. package/src/components/mobile/statusTag/mixins.js +1 -61
  22. package/src/components/mobile/wf/addTaskUserdialog.vue +23 -3
  23. package/src/components/mobile/wf/content.vue +1705 -1556
  24. package/src/components/mobile/wf/deleteTaskUserDialog.vue +22 -3
  25. package/src/components/mobile/wf/mixins/wfModifyDialogMixin.js +8 -6
  26. package/src/components/mobile/wf/selectUserDialog.vue +122 -0
  27. package/src/components/mobile/wf/setCandidateDialog.vue +25 -4
  28. package/src/components/mobile/wf/urgingDialog.vue +26 -3
  29. package/src/components/mobile/wf/wfModifyDialog.vue +4 -0
  30. package/src/components/obsUpload/index.vue +1 -1
  31. package/src/components/table/config.js +78 -78
  32. package/src/components/table/index.js +1276 -1276
  33. package/src/components/table/plugins/cell-area/index.js +1055 -0
  34. package/src/components/table/plugins/cell-area/index.scss +77 -0
  35. package/src/components/table/plugins/cell-area/util.js +224 -0
  36. package/src/components/table/tableForm.vue +330 -330
  37. package/src/components/table/tableFormMixin.js +318 -318
  38. package/src/components/table/vxeFilter/index.js +163 -163
  39. package/src/components/table/vxeFilter/mixin.js +316 -316
  40. package/src/components/wf/content.vue +1188 -1188
  41. package/src/components/wf/wf.js +40 -20
  42. package/src/components/wf/wfActionDropdown.vue +1 -1
  43. package/src/components/wf/wfActionItems.js +1 -1
  44. package/src/components/xform/docs/2026-08 xform H5 P0 /345/256/236/347/216/260/350/247/204/346/240/274.md" +528 -0
  45. package/src/components/xform/docs/2026-08 xform H5 P1 /345/256/236/347/216/260/350/247/204/346/240/274.md" +412 -0
  46. package/src/components/xform/docs/2026-08 xform H5 P2 /345/256/236/347/216/260/350/247/204/346/240/274.md" +287 -0
  47. package/src/components/xform/docs/2026-08 xform /347/247/273/345/212/250/347/253/257/345/270/203/345/261/200/345/257/271/351/275/220 bill_setting /346/226/271/346/241/210.md" +400 -0
  48. package/src/components/xform/form-designer/designer.js +51 -52
  49. package/src/components/xform/form-designer/form-widget/container-widget/data-table-widget.vue +269 -269
  50. package/src/components/xform/form-designer/form-widget/container-widget/detail-h5-widget.vue +18 -2
  51. package/src/components/xform/form-designer/form-widget/container-widget/detail-temp-widget.vue +132 -0
  52. package/src/components/xform/form-designer/form-widget/container-widget/detail-widget.vue +250 -250
  53. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-pane-widget.vue +23 -2
  54. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-widget.vue +30 -1
  55. package/src/components/xform/form-designer/form-widget/dialog/fileReferenceDialog.vue +319 -320
  56. package/src/components/xform/form-designer/form-widget/dialog/formDialog.vue +365 -365
  57. package/src/components/xform/form-designer/form-widget/dialog/importDialog.vue +185 -185
  58. package/src/components/xform/form-designer/form-widget/dialog/searchFormDialog.vue +554 -555
  59. package/src/components/xform/form-designer/form-widget/dialog/vabSearchDialog.vue +409 -409
  60. package/src/components/xform/form-designer/form-widget/field-widget/a-link-widget.vue +150 -132
  61. package/src/components/xform/form-designer/form-widget/field-widget/date-range-widget.vue +114 -114
  62. package/src/components/xform/form-designer/form-widget/field-widget/date-widget.vue +154 -154
  63. package/src/components/xform/form-designer/form-widget/field-widget/form-item-wrapper.vue +47 -1
  64. package/src/components/xform/form-designer/form-widget/field-widget/mixins/date-limit-mixin.js +178 -178
  65. package/src/components/xform/form-designer/form-widget/field-widget/mixins/time-limit-mixin.js +77 -77
  66. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +6 -0
  67. package/src/components/xform/form-designer/form-widget/field-widget/select-widget.vue +139 -139
  68. package/src/components/xform/form-designer/form-widget/field-widget/singleUpload-widget.vue +1 -1
  69. package/src/components/xform/form-designer/form-widget/field-widget/time-range-widget.vue +106 -106
  70. package/src/components/xform/form-designer/form-widget/field-widget/time-widget.vue +134 -134
  71. package/src/components/xform/form-designer/form-widget/field-widget/vabUpload-widget.vue +3 -2
  72. package/src/components/xform/form-designer/indexMixin.js +35 -1
  73. package/src/components/xform/form-designer/setting-panel/form-setting.vue +39 -39
  74. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/data-table-editor.vue +10 -10
  75. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/exportItemColumns-dialog.vue +438 -432
  76. package/src/components/xform/form-designer/setting-panel/property-editor/container-data-table/table-column-dialog.vue +2103 -2103
  77. package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-temp-edito.vue +90 -0
  78. package/src/components/xform/form-designer/setting-panel/property-editor/container-grid/gutter-editor.vue +82 -82
  79. package/src/components/xform/form-designer/setting-panel/property-editor/container-list-h5/list-h5-editor.vue +833 -846
  80. package/src/components/xform/form-designer/setting-panel/property-editor/container-table/table-dynamicField-editor.vue +8 -8
  81. package/src/components/xform/form-designer/setting-panel/property-editor/dropdownFlag-editor.vue +137 -137
  82. package/src/components/xform/form-designer/setting-panel/property-editor/field-button/search-dialog-event-editor.vue +237 -237
  83. package/src/components/xform/form-designer/setting-panel/property-editor/field-date/date-defaultValue-editor.vue +43 -43
  84. package/src/components/xform/form-designer/setting-panel/property-editor/field-date-range/date-range-defaultValue-editor.vue +43 -43
  85. package/src/components/xform/form-designer/setting-panel/property-editor/field-import-button/import2-button-editor.vue +96 -96
  86. package/src/components/xform/form-designer/setting-panel/property-editor/field-table-export-button/select-export-item-button-editor.vue +51 -0
  87. package/src/components/xform/form-designer/setting-panel/property-editor/field-time/time-defaultValue-editor.vue +42 -42
  88. package/src/components/xform/form-designer/setting-panel/property-editor/field-time-range/time-range-defaultValue-editor.vue +43 -43
  89. package/src/components/xform/form-designer/setting-panel/property-editor/formScriptEnabled-editor.vue +158 -158
  90. package/src/components/xform/form-designer/setting-panel/property-editor/h5Span-editor.vue +51 -0
  91. package/src/components/xform/form-designer/setting-panel/property-editor/itemStyle-editor.vue +39 -0
  92. package/src/components/xform/form-designer/setting-panel/property-editor/name-editor.vue +188 -188
  93. package/src/components/xform/form-designer/setting-panel/property-editor/styleTempClass-editor.vue +51 -0
  94. package/src/components/xform/form-designer/setting-panel/property-editor/textFlag-editor.vue +347 -347
  95. package/src/components/xform/form-designer/setting-panel/propertyRegister.js +12 -0
  96. package/src/components/xform/form-designer/toolbar-panel/index.vue +884 -874
  97. package/src/components/xform/form-designer/toolbar-panel/indexMixin.js +14 -0
  98. package/src/components/xform/form-designer/widget-panel/index.vue +11 -7
  99. package/src/components/xform/form-designer/widget-panel/indexMixin.js +30 -6
  100. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +112 -4
  101. package/src/components/xform/form-render/container-item/data-table-mixin.js +151 -93
  102. package/src/components/xform/form-render/container-item/detail-h5-item.vue +204 -34
  103. package/src/components/xform/form-render/container-item/detail-temp-item.vue +110 -0
  104. package/src/components/xform/form-render/container-item/h5-card-pane-item.vue +160 -140
  105. package/src/components/xform/form-render/container-item/list-h5-item.vue +1913 -1699
  106. package/src/components/xform/form-render/index.vue +153 -147
  107. package/src/components/xform/form-render/indexMixin.js +35 -3
  108. package/src/components/xform/lang/en-US.js +14 -0
  109. package/src/components/xform/lang/zh-CN.js +17 -0
  110. package/src/components/xform/mixins/defaultHandle.js +707 -707
  111. package/src/components/xform/styles/h5.scss +2238 -0
  112. package/src/components/xform/utils/textMaskUtil.js +182 -179
  113. package/src/components/xform/utils/treeTableUtil.js +1292 -1265
  114. package/src/components/xform/utils/util.js +56 -11
  115. package/src/directive/append-to-body/index.js +48 -0
  116. package/src/index.js +13 -4
  117. package/src/layout/components/Sidebar/default.vue +1655 -1655
  118. package/src/layout/components/extractedCode/viewDialog.vue +7 -7
  119. package/src/router/index.js +48 -27
  120. package/src/router/modules/customer.js +71 -14
  121. package/src/store/modules/permission.js +17 -18
  122. package/src/utils/assetUrl.js +19 -0
  123. package/src/utils/pdfUtil.js +429 -429
  124. package/src/utils/resolveViewComponent.js +142 -16
  125. package/src/utils/vab.js +1283 -1279
  126. package/src/views/bd/project/branch/bd_branch/edit.vue +145 -0
  127. package/src/views/bd/project/branch/bd_branch/list.vue +72 -0
  128. package/src/views/bd/project/branch/bd_branch/menuKindDialog.vue +106 -0
  129. package/src/views/bd/project/branch/bd_branch/mixins/edit.js +189 -0
  130. package/src/views/bd/project/branch/bd_branch/mixins/list.js +124 -0
  131. package/src/views/bd/project/branch/bd_branch/mixins/menuKindDialog.js +85 -0
  132. package/src/views/bd/project/branch/form_script/list.vue +31 -0
  133. package/src/views/bd/project/branch/form_template/list.vue +30 -0
  134. package/src/views/bd/project/branch/menu_kind/list.vue +31 -0
  135. package/src/views/bd/project/common/form_script/list.vue +16 -0
  136. package/src/views/bd/project/common/form_template/list.vue +15 -0
  137. package/src/views/bd/project/common/menu_kind/list.vue +15 -0
  138. package/src/views/bd/project/core/branchContext.js +100 -0
  139. package/src/views/bd/project/core/branchPage.js +78 -0
  140. package/src/views/bd/project/core/branchPageWrap.vue +225 -0
  141. package/src/views/bd/project/core/branchScope.js +44 -0
  142. package/src/views/bd/project/core/branchSearchPage.js +285 -0
  143. package/src/views/bd/project/core/branchSelect.vue +85 -0
  144. package/src/views/bd/project/core/branchTreeBar.vue +81 -0
  145. package/src/views/bd/project/core/httpBranchPatch.js +58 -0
  146. package/src/views/bd/project/datatable/menu_kind/list.vue +15 -0
  147. package/src/views/bd/project/datatable/table_model/list.vue +15 -0
  148. package/src/views/bd/setting/bd_company_env/dialog.vue +174 -174
  149. package/src/views/bd/setting/form_template/edit.vue +378 -356
  150. package/src/views/bd/setting/form_template/formDesignerDialog.vue +6 -0
  151. package/src/views/bd/setting/form_template/formTemplateType.js +43 -0
  152. package/src/views/bd/setting/form_template/list.vue +304 -303
  153. package/src/views/bd/setting/form_template/mixins/edit.js +344 -280
  154. package/src/views/bd/setting/form_template/mixins/list.js +748 -721
  155. package/src/views/bd/setting/table_model/edit.vue +1066 -1066
  156. package/src/views/bd/setting/table_model/mixins/edit.js +1455 -1455
  157. package/src/views/bd/setting/table_model/mixins/zdDialog.js +148 -148
  158. package/src/views/demo/bizTab/bill/billConfig.js +41 -0
  159. package/src/views/demo/bizTab/bill/detail.vue +436 -0
  160. package/src/views/demo/bizTab/bill/list.vue +288 -0
  161. package/src/views/demo/bizTab/bill/productDialog.vue +176 -0
  162. package/src/views/demo/bizTab/simple/billApi.js +123 -0
  163. package/src/views/demo/bizTab/simple/detail.vue +407 -0
  164. package/src/views/demo/bizTab/simple/list.vue +217 -0
  165. package/src/views/demo/bizTab/standalone/index.vue +121 -0
  166. package/src/views/demo/bizTab/wf/billConfig.js +44 -0
  167. package/src/views/demo/bizTab/wf/detail.vue +661 -0
  168. package/src/views/demo/bizTab/wf/list.vue +242 -0
  169. package/src/views/support/form-dialog-demo/demoPickerDialog.vue +72 -0
  170. package/src/views/support/form-dialog-demo/index.vue +537 -0
  171. package/src/views/user/file_view_ins/list.vue +970 -970
  172. package/src/views/user/form/vform/designer.vue +823 -821
  173. package/src/views/user/home/default.vue +1117 -1117
  174. package/src/views/user/home/default2.vue +1 -1
  175. package/src/views/user/home/index.vue +103 -101
  176. package/src/views/user/home/wjl/content.vue +1569 -0
  177. package/src/views/user/notify_message/dialog.vue +139 -137
  178. package/src/views/user/outLink/cc_form_view.vue +188 -0
  179. package/src/views/user/outLink/form_view.vue +202 -202
  180. package/src/views/user/outLink/index.vue +110 -110
  181. package/src/views/user/outLink/view.vue +3 -3
  182. package/src/views/user/role/edit.vue +632 -632
  183. package/src/views/user/role/list.vue +260 -260
  184. package/src/views/user/wf/iframe/index.vue +51 -51
  185. package/src/views/user/wf/iframe/index2.vue +64 -64
  186. package/src/views/user/wf/wf_manage/list.vue +1112 -1116
  187. package/src/views/user/wf/wf_manage/list2.vue +871 -875
  188. package/src/views/user/wf/wf_manage/wfContentDialog.vue +134 -131
  189. package/src/views/user/wf/wf_obj_config/importItemDialog.vue +1 -1
  190. package/src/components/xform/form-designer/form-widget/field-widget/dropdown-menu-widget.vue +0 -106
  191. package/src/components/xform/form-designer/form-widget/field-widget/tableexportbuttonwidget.vue +0 -99
  192. package/src/components/xform/form-render/container-item/list-h5-item2.vue +0 -1340
  193. package/src/utils/wf.js +0 -766
@@ -0,0 +1,661 @@
1
+ <template>
2
+ <div class="detail-wrap">
3
+ <!-- el-form 必须包住 baseTabs(流程面板挂 .el-form .d-cont、导航挂 .slide-wrap)。
4
+ :disabled="billDisabled" 一绑,表单里的字段就整片自动禁用,不用逐个绑。 -->
5
+ <el-form ref="editForm" :model="billModel" :disabled="billDisabled">
6
+ <!-- 这层空 el-form 是用来隔断 disabled 注入的(element 的 Form 是 provide elForm: this,
7
+ 嵌套一层就把外层的 disabled 挡在外面),头部按钮不会被单据只读态带禁。 -->
8
+ <el-form>
9
+ <div class="d-header clearfix">
10
+ <div class="fl">
11
+ <i class="el-icon-info" />
12
+ {{ isAdd ? $t1("新增阶梯价") : $t1("阶梯价") + " " + (billModel.sn || "") }}
13
+ </div>
14
+ <!-- 业务自己的按钮放默认插槽,会排在「提交流程」之后、「重置/保存」之前 -->
15
+ <biz-bill-actions :detail="_self">
16
+ <el-button
17
+ v-if="canInvalid"
18
+ type="danger"
19
+ class="button-sty"
20
+ icon="el-icon-document-delete"
21
+ :disabled="billSaving || billSubmitting"
22
+ @click="invalidBill"
23
+ >{{ $t1("作废") }}</el-button
24
+ >
25
+ </biz-bill-actions>
26
+ </div>
27
+ </el-form>
28
+
29
+ <baseTabs>
30
+ <baseTabPane :label="$t1('基本信息')">
31
+ <template #default>
32
+ <table class="table-detail">
33
+ <tbody>
34
+ <tr>
35
+ <th>{{ $t1("单号") }}</th>
36
+ <td>{{ billModel.sn || $t1("保存后自动生成") }}</td>
37
+ <th><em class="f-red">*</em>{{ $t1("阶梯价名称") }}</th>
38
+ <td>
39
+ <el-form-item
40
+ prop="ladderName"
41
+ :rules="[
42
+ {
43
+ required: true,
44
+ message: $t1('阶梯价名称不能为空'),
45
+ trigger: 'blur',
46
+ },
47
+ ]"
48
+ >
49
+ <el-input
50
+ v-model="billModel.ladderName"
51
+ clearable
52
+ />
53
+ </el-form-item>
54
+ </td>
55
+ <th>{{ $t1("单据状态") }}</th>
56
+ <td>
57
+ <div :class="statusInfo.cls">{{ statusInfo.label }}</div>
58
+ </td>
59
+ </tr>
60
+ <tr>
61
+ <th><em class="f-red">*</em>{{ $t1("开始时间") }}</th>
62
+ <td>
63
+ <el-form-item
64
+ prop="startDate"
65
+ :rules="[
66
+ {
67
+ required: true,
68
+ message: $t1('请选择开始时间'),
69
+ trigger: ['blur', 'change'],
70
+ },
71
+ ]"
72
+ >
73
+ <el-date-picker
74
+ size="small"
75
+ v-model="billModel.startDate"
76
+ type="date"
77
+ :placeholder="$t1('选择日期')"
78
+ value-format="yyyy-MM-dd"
79
+ :picker-options="$baseStartPickerOptions(billModel.endDate)"
80
+ clearable
81
+ />
82
+ </el-form-item>
83
+ </td>
84
+ <th><em class="f-red">*</em>{{ $t1("结束时间") }}</th>
85
+ <td>
86
+ <el-form-item
87
+ prop="endDate"
88
+ :rules="[
89
+ {
90
+ required: true,
91
+ message: $t1('请选择结束时间'),
92
+ trigger: ['blur', 'change'],
93
+ },
94
+ ]"
95
+ >
96
+ <el-date-picker
97
+ size="small"
98
+ v-model="billModel.endDate"
99
+ type="date"
100
+ :placeholder="$t1('选择日期')"
101
+ value-format="yyyy-MM-dd"
102
+ :picker-options="$baseEndPickerOptions(billModel.startDate)"
103
+ clearable
104
+ />
105
+ </el-form-item>
106
+ </td>
107
+ <th>{{ $t1("备注") }}</th>
108
+ <td>
109
+ <!-- 「流程中也能改的字段」示例:外层 el-form 整片禁用后,单个字段传
110
+ :disabled="false" 是压不回来的(element 的 inputDisabled 是 OR),
111
+ 必须套一层 el-form 隔断注入,再用 fieldDisabled 决定它自己禁不禁。
112
+ 放开哪些字段配在 billOptions.wfEditableFields 里。
113
+ ref="extraForm" + :model 一定要带上:el-form-item 只向最近的 form 注册,
114
+ 外层 editForm 不认识这个字段,mixin 的 validateBill() 靠 extraForm
115
+ 把它一起校验,否则这里写的 rules 是空转的。 -->
116
+ <el-form ref="extraForm" :model="billModel">
117
+ <el-form-item prop="memo">
118
+ <el-input
119
+ v-model="billModel.memo"
120
+ :disabled="fieldDisabled('memo')"
121
+ clearable
122
+ />
123
+ </el-form-item>
124
+ </el-form>
125
+ </td>
126
+ </tr>
127
+ </tbody>
128
+ </table>
129
+ </template>
130
+ </baseTabPane>
131
+
132
+ <baseTabPane :label="$t1('机构明细')">
133
+ <template #button>
134
+ <el-button
135
+ v-if="!billDisabled"
136
+ class="button-sty"
137
+ icon="el-icon-search"
138
+ @click="showSaleOrgDialog = true"
139
+ >{{ $t1("选择机构") }}</el-button
140
+ >
141
+ </template>
142
+ <template #default>
143
+ <vxe-grid
144
+ ref="saleOrgGrid"
145
+ :data="billModel.saleOrgItemDTOs"
146
+ v-bind="saleOrgOption"
147
+ @resizable-change="$vxeTableUtil.onColumnWitchChange"
148
+ @custom="$vxeTableUtil.customHandle"
149
+ ></vxe-grid>
150
+ </template>
151
+ </baseTabPane>
152
+
153
+ <baseTabPane :label="$t1('产品明细')">
154
+ <template #button>
155
+ <!-- 这张表流程中也放开,所以按钮的显隐跟着 fieldDisabled 而不是整片只读 -->
156
+ <el-button
157
+ v-if="!fieldDisabled('productItemDTOs')"
158
+ class="button-sty"
159
+ icon="el-icon-plus"
160
+ @click="addProductRow"
161
+ >{{ $t1("增行") }}</el-button
162
+ >
163
+ </template>
164
+ <template #default>
165
+ <!-- 「流程中放开整张子表」的写法:把 grid 整个包进内层 el-form,
166
+ 外层的整片 disabled 就进不来了(Form 是 provide elForm: this)。
167
+ 代价是这张表的行内 form-item 全部注册到内层 form,外层 editForm 不再认识它们,
168
+ 所以 ref 必须以 extraForm 开头 —— mixin 的 getExtraForms() 按前缀收集,
169
+ validateBill() 会把它一起校验(同名 ref 会互相覆盖,所以这里叫 extraFormProduct)。
170
+ 单元格自己用 fieldDisabled('productItemDTOs') 决定禁不禁。 -->
171
+ <el-form ref="extraFormProduct" :model="billModel">
172
+ <vxe-grid
173
+ ref="productGrid"
174
+ :data="billModel.productItemDTOs"
175
+ v-bind="productOption"
176
+ @resizable-change="$vxeTableUtil.onColumnWitchChange"
177
+ @custom="$vxeTableUtil.customHandle"
178
+ ></vxe-grid>
179
+ </el-form>
180
+ </template>
181
+ </baseTabPane>
182
+
183
+ <baseTabPane :label="$t1('附件')">
184
+ <template #default>
185
+ <table class="table-detail">
186
+ <tbody>
187
+ <tr>
188
+ <th><em class="f-red">*</em>{{ $t1("阶梯价凭证") }}</th>
189
+ <td colspan="7">
190
+ <!-- 附件必填校不出来是常见坑:async-validator 的 required 对空数组放行,
191
+ 所以在 validateBillData() 里用 checkBillRequired 的 attachment 类型兜 -->
192
+ <baseUpload
193
+ accept="file"
194
+ multi="true"
195
+ :file.sync="billModel.attachmentDTOs"
196
+ ></baseUpload>
197
+ </td>
198
+ </tr>
199
+ </tbody>
200
+ </table>
201
+ </template>
202
+ </baseTabPane>
203
+
204
+ <baseTabPane :label="$t1('操作日志')">
205
+ <template #default>
206
+ <oplogTable ref="oplogTable" :parent-target="_self"></oplogTable>
207
+ </template>
208
+ </baseTabPane>
209
+ </baseTabs>
210
+ </el-form>
211
+
212
+ <sale-org-dialog
213
+ v-if="showSaleOrgDialog"
214
+ :visiable.sync="showSaleOrgDialog"
215
+ multi="true"
216
+ @confirm="confirmInsertSaleOrg"
217
+ />
218
+ </div>
219
+ </template>
220
+
221
+ <script>
222
+ /**
223
+ * demo C 单据详情:自定义控制器 + 流程,写法对齐 views/pmd/price/ladderPrice/edit.vue
224
+ * (也就是 std 项目里那些手写页面的标准写法)。
225
+ *
226
+ * 与 demo B 的差别只在这三个钩子里的请求:
227
+ * buildLoadRequest → /ladderPrice/get
228
+ * saveBill → /ladderPrice/save 或 /update(整个模型直接当 body)
229
+ * 子表 → /ladderPrice/findLadderPriceProductItems 等独立接口
230
+ * 流程、页签、翻单的用法与 demo B 一模一样。
231
+ */
232
+ import { bizBillDetailMixin } from "@base/components/bizTab";
233
+ import { requiredHeader } from "@base/components/bizTab/billTableUtil";
234
+ import BizBillActions from "@base/components/bizTab/BizBillActions.vue";
235
+ import saleOrgDialog from "@base/views/user/sale_org/dialog.vue";
236
+ import { BILL, STATUS_MAP } from "./billConfig";
237
+
238
+ export default {
239
+ name: "demoBizTabWfDetail",
240
+ components: { BizBillActions, saleOrgDialog },
241
+ mixins: [bizBillDetailMixin],
242
+ data() {
243
+ return {
244
+ billModel: this.getDefaultModel(),
245
+ saleOrgOption: {},
246
+ productOption: {},
247
+ showSaleOrgDialog: false,
248
+ };
249
+ },
250
+ computed: {
251
+ billOptions() {
252
+ return {
253
+ prefix: BILL.prefix, // 流程服务名从这里推导(/pmd → pmd)
254
+ wfCode: BILL.wfCode,
255
+ titleField: BILL.titleField,
256
+ wfEnabled: true,
257
+ saveSubmitEnabled: true,
258
+ wfStartBindSave: true,
259
+ wfAgreeBindSave: true,
260
+ // 流程中(节点不允许改单据时)仍放开「备注」和整张「产品明细」;按节点区分就写成
261
+ // { "2": ["memo", "amount"], "*": ["memo"] },key 是 wfInfo.taskStep
262
+ wfEditableFields: ["memo", "productItemDTOs"],
263
+ };
264
+ },
265
+ statusInfo() {
266
+ return STATUS_MAP[this.billModel.status] || { label: "-", cls: "" };
267
+ },
268
+ canInvalid() {
269
+ return (
270
+ !this.isAdd
271
+ && (this.billModel.status === 0 || this.billModel.status === 2)
272
+ );
273
+ },
274
+ },
275
+ mounted() {
276
+ this.loadBill();
277
+ this.initSaleOrgTable();
278
+ this.initProductTable();
279
+ },
280
+ methods: {
281
+ getDefaultModel() {
282
+ return {
283
+ id: null,
284
+ sn: null,
285
+ status: 0,
286
+ ladderName: null,
287
+ startDate: null,
288
+ endDate: null,
289
+ memo: null,
290
+ saleOrgItemDTOs: [],
291
+ customerItemDTOs: [], // demo 不维护,但要原样带回,避免整单保存把它清掉
292
+ productItemDTOs: [],
293
+ attachmentDTOs: [],
294
+ };
295
+ },
296
+
297
+ // ===== bizBillDetailMixin 要求实现的业务钩子 =====
298
+ buildLoadRequest(dataId) {
299
+ return {
300
+ url: BILL.urls.get,
301
+ method: "post",
302
+ data: { id: dataId },
303
+ };
304
+ },
305
+ applyBillData(objx) {
306
+ if (!objx) {
307
+ this.billModel = this.getDefaultModel();
308
+ return;
309
+ }
310
+ // 主表接口不回子表,子表各有自己的接口;先占位再异步填
311
+ this.billModel = Object.assign(this.getDefaultModel(), objx, {
312
+ saleOrgItemDTOs: [],
313
+ productItemDTOs: [],
314
+ });
315
+ this.loadSubTables();
316
+ this.initOplog();
317
+ },
318
+ saveBill(options) {
319
+ let opts = options || {};
320
+ return new Promise((resolve) => {
321
+ let done = () => this.postSave(opts, resolve);
322
+ if (opts.confirm === false) {
323
+ done();
324
+ return;
325
+ }
326
+ this.$baseConfirm(this.$t1("您确定要保存吗?")).then(done, () =>
327
+ resolve(null)
328
+ );
329
+ });
330
+ },
331
+ /**
332
+ * 数据级校验:子表必填只靠行内 el-form-item 是不够的——表格是 scrollY gt:20 的虚拟滚动,
333
+ * 屏幕外的行没渲染、form-item 不存在,外层 form 校验不到。所以这里按数据再兜一遍。
334
+ * 返回错误文案即中止保存/提交。
335
+ */
336
+ validateBillData() {
337
+ return (
338
+ // 表头:附件必填(集合型字段,el-form-item 的 required 对空数组是放行的)
339
+ this.checkBillRequired([
340
+ { field: "attachmentDTOs", label: this.$t1("阶梯价凭证"), type: "attachment" },
341
+ ])
342
+ // 子表:至少一行 + 逐行必填(fullData,不受虚拟滚动影响)
343
+ || this.checkRowsRequired({
344
+ label: this.$t1("机构明细"),
345
+ rows: this.getGridRows("saleOrgGrid", "saleOrgItemDTOs"),
346
+ })
347
+ || this.checkRowsRequired({
348
+ label: this.$t1("产品明细"),
349
+ rows: this.getGridRows("productGrid", "productItemDTOs"),
350
+ fields: [
351
+ { field: "productVonderCode", label: this.$t1("产品编码") },
352
+ { field: "ladderPrice", label: this.$t1("阶梯价") },
353
+ { field: "minQuantity", label: this.$t1("起始数量") },
354
+ { field: "maxQuantity", label: this.$t1("截止数量") },
355
+ // 自定义规则用 check,返回文案即不通过(前缀"第 N 行"会自动带上)
356
+ {
357
+ field: "maxQuantity",
358
+ check: (val, row) =>
359
+ Number(row.minQuantity) > Number(val)
360
+ ? this.$t1("「起始数量」不能大于「截止数量」")
361
+ : null,
362
+ },
363
+ ],
364
+ })
365
+ );
366
+ },
367
+ // 覆盖默认判据,叠加单据状态:mixin 默认只看流程(没启动就能改)。
368
+ // billDisabled(字段自动禁用)和「重置/保存」的显隐都以它为准。
369
+ canEditBill() {
370
+ if (this.hasWf) return !!(this.wfInfo && this.wfInfo.toModify);
371
+ return this.isAdd || this.billModel.status === 0;
372
+ },
373
+ // 已作废/审核中的单据不许再提交流程
374
+ canStartWf() {
375
+ return this.billModel.status === 0 || this.billModel.status == null;
376
+ },
377
+
378
+ // ===== 业务内部 =====
379
+ postSave(opts, resolve) {
380
+ let isEdit = !this.isAdd;
381
+ // 行内编辑过的子表以表格数据为准(vxe 行对象与模型同引用,这里只是保险)
382
+ let data = {
383
+ ...this.billModel,
384
+ saleOrgItemDTOs: this.getGridRows("saleOrgGrid", "saleOrgItemDTOs"),
385
+ productItemDTOs: this.getGridRows("productGrid", "productItemDTOs"),
386
+ };
387
+ this.$http({
388
+ url: isEdit ? BILL.urls.update : BILL.urls.save,
389
+ method: "post",
390
+ data: data,
391
+ isLoading: true,
392
+ success: (res) => {
393
+ // 新增返回新单号;更新时后台不一定回 objx,退回当前单号
394
+ let dataId = res && res.objx ? res.objx : this.dataId;
395
+ if (opts.successMsg !== false) {
396
+ this.$message({
397
+ message: res.content,
398
+ type: "success",
399
+ duration: 500,
400
+ });
401
+ }
402
+ resolve(dataId);
403
+ },
404
+ fail: () => resolve(null),
405
+ error: () => resolve(null),
406
+ });
407
+ },
408
+ getGridRows(ref, field) {
409
+ let grid = this.$refs[ref];
410
+ return grid ? grid.getTableData().fullData : this.billModel[field];
411
+ },
412
+ loadSubTables() {
413
+ let dataId = this.dataId;
414
+ if (!dataId) return;
415
+ this.$http({
416
+ url: BILL.urls.saleOrgItems,
417
+ method: "post",
418
+ data: { id: dataId },
419
+ modalStrictly: true,
420
+ success: (res) => {
421
+ this.billModel.saleOrgItemDTOs = (res && res.objx) || [];
422
+ },
423
+ });
424
+ this.$http({
425
+ url: BILL.urls.productItems,
426
+ method: "post",
427
+ data: { id: dataId },
428
+ modalStrictly: true,
429
+ success: (res) => {
430
+ this.billModel.productItemDTOs = (res && res.objx) || [];
431
+ },
432
+ });
433
+ this.$http({
434
+ url: BILL.urls.attachments,
435
+ method: "post",
436
+ data: { id: dataId },
437
+ modalStrictly: true,
438
+ success: (res) => {
439
+ this.billModel.attachmentDTOs = (res && res.objx) || [];
440
+ },
441
+ });
442
+ },
443
+ initOplog() {
444
+ let sn = this.billModel.sn;
445
+ let oplog = this.$refs.oplogTable;
446
+ if (!oplog || !sn) return;
447
+ oplog.initData({
448
+ url: BILL.urls.userLog,
449
+ param() {
450
+ return { businessCode: sn };
451
+ },
452
+ });
453
+ },
454
+ invalidBill() {
455
+ this.$baseConfirm(this.$t1("您确定要作废吗?")).then(() => {
456
+ this.$http({
457
+ url: BILL.urls.updateStatus,
458
+ method: "post",
459
+ data: { id: this.dataId, status: 3 },
460
+ isLoading: true,
461
+ success: (res) => {
462
+ this.$message({
463
+ message: res.content,
464
+ type: "success",
465
+ duration: 500,
466
+ onClose: () => this.reloadDetail(),
467
+ });
468
+ },
469
+ });
470
+ });
471
+ },
472
+ confirmInsertSaleOrg(rows) {
473
+ if (!rows || !rows.length) return;
474
+ let list = this.billModel.saleOrgItemDTOs || [];
475
+ let exists = {};
476
+ list.forEach((item) => {
477
+ exists[item.saleOrgId] = true;
478
+ });
479
+ let adds = [];
480
+ rows.forEach((row) => {
481
+ if (exists[row.id]) return;
482
+ adds.push({ saleOrgId: row.id, saleOrgName: row.name, status: 0 });
483
+ });
484
+ if (!adds.length) {
485
+ this.$message.warning(this.$t1("所选机构都已在明细中"));
486
+ return;
487
+ }
488
+ this.billModel.saleOrgItemDTOs = list.concat(adds);
489
+ },
490
+ addProductRow() {
491
+ this.billModel.productItemDTOs.push({
492
+ productVonderCode: null,
493
+ productName: null,
494
+ standardPrice: null,
495
+ ladderPrice: null,
496
+ minQuantity: 1,
497
+ maxQuantity: 99999999,
498
+ });
499
+ },
500
+ initSaleOrgTable() {
501
+ this.$vxeTableUtil
502
+ .initVxeTable({
503
+ vue: this,
504
+ tableRef: "saleOrgGrid",
505
+ tableName: "demo-bizTab-wf-saleOrg",
506
+ columns: [
507
+ { type: "checkbox", fixed: "left", width: 48, resizable: false },
508
+ { title: this.$t1("机构名称"), field: "saleOrgName", minWidth: 200 },
509
+ {
510
+ width: 47,
511
+ fixed: "right",
512
+ title: "",
513
+ sortable: false,
514
+ slots: {
515
+ default: ({ rowIndex }) => {
516
+ if (this.billDisabled) return [];
517
+ return [this.renderDeleteLink("saleOrgItemDTOs", rowIndex)];
518
+ },
519
+ },
520
+ },
521
+ ],
522
+ })
523
+ .then((opts) => {
524
+ this.saleOrgOption = opts;
525
+ });
526
+ },
527
+ initProductTable() {
528
+ // 这张表整个包在内层 el-form(extraFormProduct) 里,行内 form-item 注册的是内层 form;
529
+ // 禁用判据也不能用 billDisabled(整片只读),要用 fieldDisabled——流程中它在白名单里就还能改。
530
+ let editCell = (row, field, index, required) => {
531
+ if (this.fieldDisabled("productItemDTOs")) return [row[field]];
532
+ // 字段名是变量,所以不用 JSX 的 v-model 语法糖,直接写它展开后的样子。
533
+ // baseInputNumber 是 el-input-number 的透传壳(v-bind $attrs / v-on $listeners)
534
+ let input = (
535
+ <base-input-number
536
+ value={row[field]}
537
+ onInput={(val) => {
538
+ row[field] = val;
539
+ }}
540
+ />
541
+ );
542
+ if (!required) return [input];
543
+ return [
544
+ <el-form-item
545
+ prop={"productItemDTOs." + index + "." + field}
546
+ rules={[{ required: true, trigger: ["blur", "change"] }]}
547
+ >
548
+ {input}
549
+ </el-form-item>,
550
+ ];
551
+ };
552
+ this.$vxeTableUtil
553
+ .initVxeTable({
554
+ vue: this,
555
+ tableRef: "productGrid",
556
+ tableName: "demo-bizTab-wf-product",
557
+ columns: [
558
+ { type: "checkbox", fixed: "left", width: 48, resizable: false },
559
+ {
560
+ title: this.$t1("产品编码"),
561
+ field: "productVonderCode",
562
+ width: 160,
563
+ slots: {
564
+ header: requiredHeader(this.$t1("产品编码")),
565
+ default: ({ row, rowIndex }) => {
566
+ if (this.fieldDisabled("productItemDTOs")) return [row.productVonderCode];
567
+ return [
568
+ <el-form-item
569
+ prop={"productItemDTOs." + rowIndex + ".productVonderCode"}
570
+ rules={[{ required: true, trigger: ["blur", "change"] }]}
571
+ >
572
+ <el-input v-model={row.productVonderCode} size="small" clearable />
573
+ </el-form-item>,
574
+ ];
575
+ },
576
+ },
577
+ },
578
+ {
579
+ title: this.$t1("产品名称"),
580
+ field: "productName",
581
+ minWidth: 180,
582
+ slots: {
583
+ default: ({ row }) => {
584
+ if (this.fieldDisabled("productItemDTOs")) return [row.productName];
585
+ return [<el-input v-model={row.productName} size="small" clearable />];
586
+ },
587
+ },
588
+ },
589
+ {
590
+ title: this.$t1("阶梯价"),
591
+ field: "ladderPrice",
592
+ width: 140,
593
+ slots: {
594
+ header: requiredHeader(this.$t1("阶梯价")),
595
+ default: ({ row, rowIndex }) =>
596
+ editCell(row, "ladderPrice", rowIndex, true),
597
+ },
598
+ },
599
+ {
600
+ title: this.$t1("起始数量"),
601
+ field: "minQuantity",
602
+ width: 140,
603
+ slots: {
604
+ header: requiredHeader(this.$t1("起始数量")),
605
+ default: ({ row, rowIndex }) =>
606
+ editCell(row, "minQuantity", rowIndex, true),
607
+ },
608
+ },
609
+ {
610
+ title: this.$t1("截止数量"),
611
+ field: "maxQuantity",
612
+ width: 140,
613
+ slots: {
614
+ header: requiredHeader(this.$t1("截止数量")),
615
+ default: ({ row, rowIndex }) =>
616
+ editCell(row, "maxQuantity", rowIndex, true),
617
+ },
618
+ },
619
+ {
620
+ width: 47,
621
+ fixed: "right",
622
+ title: "",
623
+ sortable: false,
624
+ slots: {
625
+ default: ({ rowIndex }) => {
626
+ if (this.fieldDisabled("productItemDTOs")) return [];
627
+ return [this.renderDeleteLink("productItemDTOs", rowIndex)];
628
+ },
629
+ },
630
+ },
631
+ ],
632
+ })
633
+ .then((opts) => {
634
+ this.productOption = opts;
635
+ });
636
+ },
637
+ renderDeleteLink(field, rowIndex) {
638
+ return (
639
+ <a
640
+ href="javascript:void(0);"
641
+ class="a-link"
642
+ onclick={(e) => {
643
+ e.stopPropagation();
644
+ this.billModel[field].splice(rowIndex, 1);
645
+ }}
646
+ >
647
+ <el-tooltip
648
+ enterable={false}
649
+ effect="dark"
650
+ content={this.$t1("删除")}
651
+ placement="top"
652
+ popper-class="tooltip-skin"
653
+ >
654
+ <i class="el-icon-delete" />
655
+ </el-tooltip>
656
+ </a>
657
+ );
658
+ },
659
+ },
660
+ };
661
+ </script>