cloud-web-corejs 1.1.0-dev.29 → 1.1.0-dev.31

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 (168) hide show
  1. package/package.json +11 -4
  2. package/src/app-bootstrap.js +523 -0
  3. package/src/boot-assets.legacy.js +7 -0
  4. package/src/boot-assets.next.js +7 -0
  5. package/src/components/xform/form-designer/designer.js +52 -6
  6. package/src/components/xform/form-designer/form-widget/field-widget/row-col-select-widget.vue +64 -0
  7. package/src/components/xform/form-designer/setting-panel/property-editor/container-detail/detail-temp-edito.vue +13 -1
  8. package/src/components/xform/form-designer/widget-panel/widgetsConfig.js +2 -0
  9. package/src/core-resources/css/h5.scss +548 -0
  10. package/src/core-resources/css/iconfont.css +1447 -0
  11. package/src/core-resources/font/iconfont.ttf +0 -0
  12. package/src/core-resources/font/iconfont.woff +0 -0
  13. package/src/core-resources/font/iconfont.woff2 +0 -0
  14. package/src/core-resources/images/default-header.png +0 -0
  15. package/src/core-resources/images/ico-default_wenjian.svg +1 -0
  16. package/src/core-resources/images/ico-excel.svg +1 -0
  17. package/src/core-resources/images/ico-ftl.svg +7 -0
  18. package/src/core-resources/images/ico-html.svg +1 -0
  19. package/src/core-resources/images/ico-java.svg +1 -0
  20. package/src/core-resources/images/ico-music.svg +1 -0
  21. package/src/core-resources/images/ico-pdf.svg +1 -0
  22. package/src/core-resources/images/ico-photo.svg +1 -0
  23. package/src/core-resources/images/ico-ppt.svg +1 -0
  24. package/src/core-resources/images/ico-psd.svg +1 -0
  25. package/src/core-resources/images/ico-service.png +0 -0
  26. package/src/core-resources/images/ico-txt.svg +1 -0
  27. package/src/core-resources/images/ico-video.svg +1 -0
  28. package/src/core-resources/images/ico-vue.svg +8 -0
  29. package/src/core-resources/images/ico-wenjianjia.svg +1 -0
  30. package/src/core-resources/images/ico-wrod.svg +1 -0
  31. package/src/core-resources/images/ico-xml.svg +1 -0
  32. package/src/core-resources/images/ico-yasuobao.svg +1 -0
  33. package/src/core-resources/images/icon-error.png +0 -0
  34. package/src/core-resources/images/icon-tips.png +0 -0
  35. package/src/core-resources/images/nodata.png +0 -0
  36. package/src/core-resources/images/nodata2.png +0 -0
  37. package/src/core-resources/js/base/common.js +110 -0
  38. package/src/icons/index.js +9 -0
  39. package/src/icons/svg/404.svg +1 -0
  40. package/src/icons/svg/alert.svg +1 -0
  41. package/src/icons/svg/bug.svg +1 -0
  42. package/src/icons/svg/button.svg +1 -0
  43. package/src/icons/svg/card.svg +1 -0
  44. package/src/icons/svg/cascader-field.svg +1 -0
  45. package/src/icons/svg/census.svg +1 -0
  46. package/src/icons/svg/chart.svg +1 -0
  47. package/src/icons/svg/checkbox-field.svg +1 -0
  48. package/src/icons/svg/clipboard.svg +1 -0
  49. package/src/icons/svg/color-field.svg +1 -0
  50. package/src/icons/svg/component.svg +1 -0
  51. package/src/icons/svg/custom-component.svg +1 -0
  52. package/src/icons/svg/dashboard.svg +1 -0
  53. package/src/icons/svg/data-table.svg +1 -0
  54. package/src/icons/svg/date-field.svg +1 -0
  55. package/src/icons/svg/date-range-field.svg +1 -0
  56. package/src/icons/svg/descriptions.svg +1 -0
  57. package/src/icons/svg/divider.svg +1 -0
  58. package/src/icons/svg/document.svg +1 -0
  59. package/src/icons/svg/documentation.svg +1 -0
  60. package/src/icons/svg/drag.svg +1 -0
  61. package/src/icons/svg/echart-category.svg +1 -0
  62. package/src/icons/svg/echart-pie.svg +1 -0
  63. package/src/icons/svg/echart.svg +1 -0
  64. package/src/icons/svg/edit.svg +1 -0
  65. package/src/icons/svg/education.svg +1 -0
  66. package/src/icons/svg/email.svg +1 -0
  67. package/src/icons/svg/example.svg +1 -0
  68. package/src/icons/svg/excel.svg +1 -0
  69. package/src/icons/svg/exit-fullscreen.svg +1 -0
  70. package/src/icons/svg/eye-open.svg +1 -0
  71. package/src/icons/svg/eye.svg +1 -0
  72. package/src/icons/svg/file-upload-field.svg +1 -0
  73. package/src/icons/svg/form.svg +1 -0
  74. package/src/icons/svg/fullscreen.svg +1 -0
  75. package/src/icons/svg/github.svg +1 -0
  76. package/src/icons/svg/grid.svg +1 -0
  77. package/src/icons/svg/guide.svg +1 -0
  78. package/src/icons/svg/html-text.svg +1 -0
  79. package/src/icons/svg/ico-more.svg +1 -0
  80. package/src/icons/svg/ico-wenjianjia.svg +1 -0
  81. package/src/icons/svg/icon.svg +1 -0
  82. package/src/icons/svg/input-batch.svg +1 -0
  83. package/src/icons/svg/international.svg +1 -0
  84. package/src/icons/svg/language.svg +1 -0
  85. package/src/icons/svg/link.svg +1 -0
  86. package/src/icons/svg/list-export.svg +1 -0
  87. package/src/icons/svg/list.svg +1 -0
  88. package/src/icons/svg/lock.svg +1 -0
  89. package/src/icons/svg/message.svg +1 -0
  90. package/src/icons/svg/money.svg +1 -0
  91. package/src/icons/svg/nested.svg +1 -0
  92. package/src/icons/svg/news-list.svg +1 -0
  93. package/src/icons/svg/node-tree.svg +1 -0
  94. package/src/icons/svg/number-field.svg +1 -0
  95. package/src/icons/svg/password.svg +1 -0
  96. package/src/icons/svg/pdf.svg +1 -0
  97. package/src/icons/svg/people.svg +1 -0
  98. package/src/icons/svg/peoples.svg +1 -0
  99. package/src/icons/svg/picture-upload-field.svg +1 -0
  100. package/src/icons/svg/qq.svg +1 -0
  101. package/src/icons/svg/query.svg +1 -0
  102. package/src/icons/svg/radio-field.svg +1 -0
  103. package/src/icons/svg/rate-field.svg +1 -0
  104. package/src/icons/svg/redo.svg +1 -0
  105. package/src/icons/svg/rich-editor-field.svg +1 -0
  106. package/src/icons/svg/search.svg +1 -0
  107. package/src/icons/svg/searchbox.svg +1 -0
  108. package/src/icons/svg/section.svg +1 -0
  109. package/src/icons/svg/select-field.svg +1 -0
  110. package/src/icons/svg/shopping.svg +1 -0
  111. package/src/icons/svg/size.svg +1 -0
  112. package/src/icons/svg/skill.svg +1 -0
  113. package/src/icons/svg/slider-field.svg +1 -0
  114. package/src/icons/svg/slot-component.svg +1 -0
  115. package/src/icons/svg/slot-field.svg +1 -0
  116. package/src/icons/svg/star.svg +1 -0
  117. package/src/icons/svg/static-text.svg +1 -0
  118. package/src/icons/svg/status.svg +1 -0
  119. package/src/icons/svg/sub-form.svg +1 -0
  120. package/src/icons/svg/switch-field.svg +1 -0
  121. package/src/icons/svg/tab.svg +1 -0
  122. package/src/icons/svg/table.svg +1 -0
  123. package/src/icons/svg/text-field.svg +1 -0
  124. package/src/icons/svg/text.svg +1 -0
  125. package/src/icons/svg/textarea-field.svg +1 -0
  126. package/src/icons/svg/theme.svg +1 -0
  127. package/src/icons/svg/time-field.svg +1 -0
  128. package/src/icons/svg/time-range-field.svg +1 -0
  129. package/src/icons/svg/tips-text.svg +1 -0
  130. package/src/icons/svg/title-head.svg +1 -0
  131. package/src/icons/svg/tree-pane.svg +1 -0
  132. package/src/icons/svg/tree-table.svg +1 -0
  133. package/src/icons/svg/tree.svg +1 -0
  134. package/src/icons/svg/undo.svg +1 -0
  135. package/src/icons/svg/uploadbox.svg +1 -0
  136. package/src/icons/svg/user.svg +1 -0
  137. package/src/icons/svg/vf-box.svg +1 -0
  138. package/src/icons/svg/vf-dialog.svg +1 -0
  139. package/src/icons/svg/vf-drawer.svg +1 -0
  140. package/src/icons/svg/vue-sfc.svg +1 -0
  141. package/src/icons/svg/wechat.svg +1 -0
  142. package/src/icons/svg/zip.svg +1 -0
  143. package/src/index.next.js +5 -0
  144. package/src/styles/btn.scss +104 -0
  145. package/src/styles/element-ui.scss +155 -0
  146. package/src/styles/element-variables.scss +31 -0
  147. package/src/styles/global.scss +115 -0
  148. package/src/styles/index.scss +200 -0
  149. package/src/styles/menu-icons.scss +75 -0
  150. package/src/styles/mixin.scss +72 -0
  151. package/src/styles/nprogress.scss +14 -0
  152. package/src/styles/sidebar.scss +281 -0
  153. package/src/styles/split-handle.scss +52 -0
  154. package/src/styles/theme-variables.scss +7 -0
  155. package/src/styles/transition.scss +48 -0
  156. package/src/styles/utilities.scss +137 -0
  157. package/src/styles/variables.scss +44 -0
  158. package/src/views/demo/bizTab/bill/billConfig.js +0 -41
  159. package/src/views/demo/bizTab/bill/detail.vue +0 -436
  160. package/src/views/demo/bizTab/bill/list.vue +0 -288
  161. package/src/views/demo/bizTab/bill/productDialog.vue +0 -176
  162. package/src/views/demo/bizTab/simple/billApi.js +0 -123
  163. package/src/views/demo/bizTab/simple/detail.vue +0 -407
  164. package/src/views/demo/bizTab/simple/list.vue +0 -217
  165. package/src/views/demo/bizTab/standalone/index.vue +0 -121
  166. package/src/views/demo/bizTab/wf/billConfig.js +0 -44
  167. package/src/views/demo/bizTab/wf/detail.vue +0 -661
  168. package/src/views/demo/bizTab/wf/list.vue +0 -242
@@ -1,661 +0,0 @@
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>