cloud-web-corejs 1.0.54-dev.803 → 1.0.54-dev.805

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloud-web-corejs",
3
3
  "private": false,
4
- "version": "1.0.54-dev.803",
4
+ "version": "1.0.54-dev.805",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "dev:micro": "vue-cli-service serve --port 17527",
@@ -3,7 +3,7 @@
3
3
  <!-- 按钮顺序(.fr 里 DOM 次序即从左到右):
4
4
  翻单 → 提交流程 → 业务按钮(默认插槽) → 重置 → 保存
5
5
  #before 是留给"要排在翻单之前"的特例,一般不用。
6
- 另外 wfUtil 的「流程操作」下拉 / 「修改单据」是 append 到本容器最前面的,会落在最左侧。 -->
6
+ 另外 wfUtil 的「更多」下拉 / 「修改单据」是 append 到本容器最前面的,会落在最左侧。 -->
7
7
  <slot name="before"></slot>
8
8
  <!-- ① 上一单 / 下一单:列表侧 openDetail 传了 navRows 才出现 -->
9
9
  <template v-if="showBillNav">
@@ -83,7 +83,7 @@
83
83
  * </div>
84
84
  *
85
85
  * 注意:根节点是 .d-header 里的 .fr,别再往外包一层,否则布局会散,
86
- * 而且 wfUtil 的「流程操作」下拉 / 「修改单据」就是往 .el-form .d-header > .fr 里塞的。
86
+ * 而且 wfUtil 的「更多」下拉 / 「修改单据」就是往 .el-form .d-header > .fr 里塞的。
87
87
  */
88
88
  export default {
89
89
  name: "BizBillActions",
@@ -6,13 +6,15 @@
6
6
  v-if="!isHideWf"
7
7
  >
8
8
  <template #default>
9
- <!-- 审批按钮条留在流程模块内,不随 wfActionInHeaderEnabled 搬走或隐藏。
10
- 开了该开关时,详情标题栏另挂一份(wfActionDropdown.vue):通过/驳回/撤回平铺,
11
- 其余收进「流程操作」下拉。 -->
9
+ <!-- 审批按钮条:标题栏那份挂上后(headerActionsMounted)整条 v-show 藏掉。
10
+ 用 v-show 而不是 v-if,是为了保住 addOpinionBtn——下拉里「补充意见」走的是
11
+ $refs.addOpinionBtn.openDialog()。开了 wfActionInHeaderEnabled 时,详情标题栏
12
+ 另挂一份(wfActionDropdown.vue):通过/驳回/撤回平铺,其余收进「更多」下拉。 -->
12
13
  <div
13
14
  ref="wfActionBar"
14
15
  style="margin: -36px 0 8px 124px; position: relative; z-index: 2; height: 28px"
15
16
  v-if="!wfConfig.hiddenAllButton"
17
+ v-show="!headerActionsMounted"
16
18
  >
17
19
  <el-button
18
20
  type="success"
@@ -386,6 +386,8 @@ wfContentMixin = {
386
386
  candidateDatas:[],
387
387
  wfSendTaskId: null,
388
388
  showAddOpinionButton: false,
389
+ //标题栏那份审批入口挂上后为 true,流程模块按钮条据此 v-show 隐藏
390
+ headerActionsMounted: false,
389
391
 
390
392
  addOpinionEnabled: false,
391
393
  modifyCurrentCandidateEnabled: false,
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="wf-action-dropdown-wrap button-sty" v-show="items.length">
3
- <!-- 通过 / 驳回 / 撤回 挪出下拉,在标题栏直接平铺;其余操作仍收在「流程操作」下拉里 -->
3
+ <!-- 通过 / 驳回 / 撤回 挪出下拉,在标题栏直接平铺;其余操作仍收在「更多」下拉里 -->
4
4
  <el-button
5
5
  v-for="item in standaloneItems"
6
6
  :key="item.key"
@@ -12,7 +12,7 @@
12
12
  </el-button>
13
13
  <el-dropdown trigger="hover" v-if="dropdownItems.length">
14
14
  <el-button type="primary" class="button-sty">
15
- {{ $t1("流程操作") }}
15
+ {{ $t1("更多") }}
16
16
  <i class="el-icon-arrow-down el-icon--right"></i>
17
17
  </el-button>
18
18
  <el-dropdown-menu slot="dropdown">
@@ -200,11 +200,12 @@ f = async function (option) {
200
200
  }
201
201
 
202
202
  /* 审批操作:开了 wfActionInHeaderEnabled 时,在详情模块标题栏再挂一份 —— 通过/驳回/撤回
203
- 平铺成独立按钮,其余收进「流程操作」下拉(wfActionDropdown.vue)。流程模块里的
204
- 原按钮条不动、不隐藏;点击走流程面板实例上的同一套方法。
203
+ 平铺成独立按钮,其余收进「更多」下拉(wfActionDropdown.vue)。挂上后把流程面板
204
+ headerActionsMounted 置 true,模块内原按钮条 v-show 藏掉(addOpinionBtn 还在,
205
+ 下拉里「补充意见」才能点开)。点击走流程面板实例上的同一套方法。
205
206
  放在「修改单据」「流程启动」之后挂——appendPrevChildDom 是前插,最后插的排最左,
206
- 最终顺序:通过/驳回/撤回/流程操作 → 修改单据 → 内建/业务按钮。
207
- hiddenAllButton / 素身详情(取不到 .fr) 自动跳过。
207
+ 最终顺序:通过/驳回/撤回/更多 → 修改单据 → 内建/业务按钮。
208
+ hiddenAllButton / 素身详情(取不到 .fr) 自动跳过,那种情况模块按钮条继续留着。
208
209
  _hideWf 也必须跳过:那种页面 content.vue 根节点 v-if 掉了,弹框根本没渲染出来,
209
210
  挂上去就是一排点了没反应的按钮(wfInfo 照样有值,光看 items 判断不出来)。 */
210
211
  if (shouldMountHeaderActions({
@@ -221,6 +222,7 @@ f = async function (option) {
221
222
  });
222
223
  instances.push(dropdownVm);
223
224
  appendPrevChildDom(wfBtnRegion, dropdownVm.$mount().$el);
225
+ contentInstance.headerActionsMounted = true;
224
226
  }
225
227
 
226
228
  registerDispose();
@@ -168,7 +168,9 @@ export default {
168
168
  width: "1200px",
169
169
  fullscreen: this.option.fullscreen,
170
170
  };
171
- config = Object.assign({}, config, this.option.dialogConfig, { customClass });
171
+ config = Object.assign({}, config, this.option.dialogConfig, {
172
+ customClass,
173
+ });
172
174
  config.title = this.$t1(config.title);
173
175
  return config;
174
176
  },
@@ -190,7 +192,9 @@ export default {
190
192
  if (this.option.showFooter == false) {
191
193
  classStr = classStr + " nfootBtn";
192
194
  }
193
- config = Object.assign({}, config, this.option.bodyConfig, { class: classStr });
195
+ config = Object.assign({}, config, this.option.bodyConfig, {
196
+ class: classStr,
197
+ });
194
198
  return config;
195
199
  },
196
200
  },
@@ -198,7 +202,6 @@ export default {
198
202
  /*let dataId = this.option?.formConfig?.dataId??null
199
203
  delete this.option?.formConfig?.dataId
200
204
  this.dataId = dataId;*/
201
-
202
205
  this.formConfig = this.option?.formConfig || {};
203
206
 
204
207
  let currentFormConfig = this.getFormConfig();
@@ -305,9 +308,9 @@ export default {
305
308
  this.close();
306
309
  }
307
310
  },
308
- setConfirmButtonHidden(val){
311
+ setConfirmButtonHidden(val) {
309
312
  this.confirmButtonVisible = val || false;
310
- }
313
+ },
311
314
  },
312
315
  };
313
316
  </script>
@@ -86,6 +86,13 @@ export default {
86
86
  if (this.isSameFieldModelValue(modelValue)) return;
87
87
  this.handleChangeEvent(modelValue);
88
88
  },
89
+ /* fieldMixin.setDisabled 只改 field.options.disabled 和 this.disabled,而本组件的
90
+ 可编辑态是 initOption 里快照进 option.edit 的,不同步就永远停在 created 时的值。
91
+ 这里只改 option 的字段、不换 option 引用:换引用会让 base-attachment 取值用的
92
+ $watch 重新求值,白跑一次 initRows(cloneDeep + nextTick 五个 init),表格里按行数放大。 */
93
+ 'field.options.disabled'(val) {
94
+ this.option.edit = !val;
95
+ },
89
96
  'option':function(){
90
97
 
91
98
  }
@@ -156,6 +163,13 @@ export default {
156
163
  },
157
164
  methods: {
158
165
  initOption(){
166
+ /* setDisabled 是裸赋值 this.field.options.disabled = xxx;存量表单 JSON 的 options
167
+ 里缺这个键时会变成非响应式新增属性,上面的 watch 收不到通知(fieldMixin 补默认
168
+ options 的 initConfig 已注释掉,indexMixin/data-table-mixin 里都要 hasOwnProperty
169
+ 兜底,说明确有缺键的 schema)。先补键,让后续赋值走响应式通道。 */
170
+ if (!this.field.options.hasOwnProperty('disabled')) {
171
+ this.$set(this.field.options, 'disabled', false);
172
+ }
159
173
  this.option = {
160
174
  title: '附件',
161
175
  edit: !this.field.options.disabled,
@@ -280,10 +280,6 @@ export default {
280
280
  overflow: hidden;
281
281
  white-space: nowrap;
282
282
  }
283
-
284
- ::v-deep .el-form-item--mini.el-form-item {
285
- margin-bottom: 6px;
286
- }
287
283
  }
288
284
 
289
285
  /* 隐藏Chrome浏览器中el-input数字输入框右侧的上下调整小箭头 */
@@ -978,6 +978,10 @@ export default {
978
978
  value: "editInput",
979
979
  label: "文本输入框",
980
980
  },
981
+ {
982
+ value: "textarea",
983
+ label: "多行文本输入框",
984
+ },
981
985
  {
982
986
  value: "editNumber",
983
987
  label: "数字输入框",
@@ -22,6 +22,10 @@
22
22
  </el-select>
23
23
  </el-form-item>
24
24
  <el-form-item label="下拉按钮选项"></el-form-item>
25
+ <draggable
26
+ tag="ul"
27
+ class="draggable-box"
28
+ >
25
29
  <li
26
30
  v-for="(colItem, colIdx) in selectedWidget.widgetList"
27
31
  :key="colIdx"
@@ -1,5 +1,5 @@
1
1
  export const constantRoutes = [
2
- {
2
+ /*{
3
3
  // 呼叫中心(CC)专用入口:只带 appid/appkey/account/callNo,
4
4
  // 先换取 tp 再 replace 到 /form_outLinkView
5
5
  path: "/cc_form_outLinkView",
@@ -22,7 +22,7 @@ export const constantRoutes = [
22
22
  icon: "dashboard",
23
23
  },
24
24
  },
25
- {
25
+ {
26
26
  // bizTab 示例 A:手写接口版(前端 mock,无流程,不吃后台前置条件)
27
27
  path: "/demo/bizTab/simple",
28
28
  component: () => import("@base/views/demo/bizTab/simple/list"),
@@ -70,7 +70,7 @@ export const constantRoutes = [
70
70
  title: "formDialog 示例",
71
71
  icon: "dashboard",
72
72
  },
73
- },
73
+ },
74
74
  ],
75
- },
75
+ },*/
76
76
  ];
@@ -51,7 +51,7 @@
51
51
  class="allDel icon-quanbushanchu" @click="clearChecked()"></a></el-tooltip>
52
52
  <div class="list">
53
53
  <div class="item" v-for="(checkRow, index) in checkRows" :key="index">
54
- <p>{{ getCheckLabel(checkRow, 'name') }}</p>
54
+ <p>{{ getCheckLabel(checkRow, 'bdCompanyCode') }}</p>
55
55
  <a class="el-icon-close" @click="clearTable1Select(index)"></a>
56
56
  </div>
57
57
  </div>
@@ -212,16 +212,14 @@
212
212
  class="search-input"
213
213
  max="200"
214
214
  v-model="szTaMb.sszstEn"
215
- @clear="
216
- szTaMb.sszst = null;
217
- szTaMb.sszstBm = null;
218
- $forceUpdate();
219
- "
215
+ @clear="clearSszst"
220
216
  :disabled="szTaMb.taType === 0"
221
217
  v-el-readonly
222
218
  clearable
223
219
  >
220
+ <!-- element 的 suffix 插槽不受 disabled 影响,图标要自己按禁用条件收起来 -->
224
221
  <i
222
+ v-if="szTaMb.taType !== 0"
225
223
  slot="suffix"
226
224
  class="el-input__icon el-icon-search"
227
225
  @click="showSzTaMbDialog = true"
@@ -293,15 +291,13 @@
293
291
  class="search-input"
294
292
  max="200"
295
293
  v-model="szTaMb.menuKindName"
296
- @clear="
297
- szTaMb.menuKindCode = '';
298
- $forceUpdate();
299
- "
294
+ @clear="clearMenuKind"
300
295
  v-el-readonly
301
296
  clearable
302
297
  :disabled="otherFlag"
303
298
  >
304
299
  <i
300
+ v-if="!otherFlag"
305
301
  slot="suffix"
306
302
  class="el-input__icon el-icon-search"
307
303
  @click="showMenuKindDialog = true"
@@ -396,7 +392,7 @@
396
392
  class="button-sty"
397
393
  icon="el-icon-upload2"
398
394
  @click="excelExport"
399
- >导出</el-button
395
+ >{{ $t1("导出") }}</el-button
400
396
  >
401
397
  </template>
402
398
  <template #default>
@@ -469,11 +465,12 @@
469
465
  >
470
466
  <span slot="suffix" class="el-input__suffix-inner">
471
467
  <i
472
- v-if="row.referenceZd"
468
+ v-if="row.referenceZd && !!row.zdEn"
473
469
  class="el-input__icon el-icon-circle-close"
474
470
  @click.stop="confirmClearReferenceZd(row)"
475
471
  ></i>
476
472
  <i
473
+ v-if="!!row.zdEn"
477
474
  class="el-input__icon el-icon-search"
478
475
  @click="openReferenceZdDialog(row, rowIndex, $table)"
479
476
  ></i>
@@ -510,7 +507,7 @@
510
507
  >
511
508
  <el-input
512
509
  v-model="row.zdEn"
513
- @keydown.native="inputZdEn(row)"
510
+ @focus="cacheZdEn(row)"
514
511
  @input="
515
512
  (val) => {
516
513
  changeZdEn(val, row);
@@ -674,11 +671,11 @@
674
671
  class="search-input"
675
672
  v-model="row.toTaBmZd"
676
673
  clearable
677
- @clear="$forceUpdate()"
678
674
  v-el-readonly
679
675
  :disabled="!!row.systems || !!row.relationZd"
680
676
  >
681
677
  <i
678
+ v-if="!row.systems && !row.relationZd"
682
679
  slot="suffix"
683
680
  class="el-input__icon el-icon-search"
684
681
  @click="openToTaBmZdDialog(row, rowIndex, $table)"
@@ -748,12 +745,6 @@
748
745
  @confirm="confirmInsertSzTaMb"
749
746
  :multi="false"
750
747
  />
751
- <szTaMbDialog
752
- v-if="showItemSzTaMbDialog"
753
- :visiable.sync="showItemSzTaMbDialog"
754
- @confirm="confirmInsertItemSzTaMb"
755
- multi="false"
756
- />
757
748
  <MenuKindDialog
758
749
  v-if="showMenuKindDialog"
759
750
  :visiable.sync="showMenuKindDialog"
@@ -788,12 +779,7 @@
788
779
  class="search-input"
789
780
  max="200"
790
781
  v-model="referenceEntity"
791
- @clear="
792
- referenceKey = null;
793
- refServiceName = null;
794
- referenceShowFields = [];
795
- $forceUpdate();
796
- "
782
+ @clear="clearReferenceEntity"
797
783
  v-el-readonly
798
784
  clearable
799
785
  >
@@ -889,6 +875,7 @@
889
875
  :visiable.sync="showEntityFieldDialog1"
890
876
  @confirm="confirmEntityFieldDialog1"
891
877
  :taBm="referenceEntity"
878
+ :rows="referenceKeyRows"
892
879
  :multi="false"
893
880
  />
894
881
  <zdDialog
@@ -896,6 +883,7 @@
896
883
  :visiable.sync="showEntityFieldDialog2"
897
884
  @confirm="confirmEntityFieldDialog2"
898
885
  :taBm="referenceEntity"
886
+ :rows="referenceShowRows"
899
887
  :multi="true"
900
888
  />
901
889
  <preformDialog
@@ -982,10 +970,7 @@
982
970
  class="search-input"
983
971
  max="200"
984
972
  v-model="toTaBmZdEntity"
985
- @clear="
986
- toTaBmZdEntity = null;
987
- toTaBmZdField = null;
988
- "
973
+ @clear="toTaBmZdField = null"
989
974
  v-el-readonly
990
975
  clearable
991
976
  >
@@ -1056,6 +1041,7 @@
1056
1041
  :visiable.sync="showEntityFieldDialog3"
1057
1042
  @confirm="confirmEntityFieldDialog3"
1058
1043
  :taBm="toTaBmZdEntity"
1044
+ :rows="toTaBmZdFieldRows"
1059
1045
  :multi="false"
1060
1046
  />
1061
1047
  <!--end-->
@@ -72,16 +72,17 @@ modules = {
72
72
  treeDefaultZds: [],
73
73
  productOption: {},
74
74
  showSzTaMbDialog: false,
75
- showItemSzTaMbDialog: false,
76
75
  showMenuKindDialog: false,
77
76
  productCategoryCodes: [],
78
- zdEnIndex: "",
79
77
 
80
78
  referenceEntity: null,
81
79
  referenceKey: null,
82
80
  referenceShowFields: null,
83
81
  refServiceName: null,
84
- currentIndex: 0,
82
+ // 存行引用而不是行索引:两个弹框都是 modal=false(没有遮罩),
83
+ // 开着的时候还能点后面的「新增」,而 addTaMbItems 是 splice(0,0) 插到最前面,
84
+ // 存索引会当场整体错位,配置写到隔壁行上
85
+ currentRow: null,
85
86
  showReferenceZdDialog: false,
86
87
 
87
88
  showEntityDialog: false,
@@ -101,40 +102,18 @@ modules = {
101
102
  showTmDialog: false,
102
103
 
103
104
  showToTaBmZdDialog: false,
105
+ // 和 currentRow 分开存:两个弹框可以同时打开,共用一个会互相覆盖
106
+ toTaBmZdRow: null,
104
107
  toTaBmZdEntity: null,
105
108
  toTaBmZdField: null,
106
109
  showEntityDialog3: false,
107
110
  showEntityFieldDialog3: false,
108
111
 
109
- inputValue: null, // 当前值
110
- preValue: null, // 上一次的值(变更前的值)
112
+ preValue: null, // 字段名输入框获得焦点时的原值(changeZdEn 用来迁移子行)
111
113
 
112
114
  sid: null,
113
115
  showOtherAuthDialog:false,
114
116
 
115
- zdTypeMap: {
116
- Boolean: "布尔",
117
- Integer: "整数",
118
- Long: "长整数",
119
- Decimal: "精度小数",
120
- Money: "金额",
121
- Text: "文本",
122
- TextArea: "长文本",
123
- DateTime: "日期时间",
124
- Reference: "关联表(文本)",
125
- ReferenceLong: "关联表(长整型)",
126
- },
127
-
128
- treeFlagMap:{
129
- name: "名称",
130
- wbs: "WBS码",
131
- parent: "上级ID",
132
- treePath: "树ID路径",
133
- treePathName: "树名称路径",
134
- hasChild: "是否有下级",
135
- grade: "层级",
136
- },
137
-
138
117
  readonly: false,
139
118
  isCompare: false,
140
119
  };
@@ -143,6 +122,40 @@ modules = {
143
122
  ...mapGetters([
144
123
  "userFlag",
145
124
  ]),
125
+ // 这两张映射表只用于 fieldCompare 显示"旧值",文案必须和模板里
126
+ // el-option 的 label 走同一套 $t1,否则英文环境下下拉是英文、对比值是中文
127
+ zdTypeMap() {
128
+ return {
129
+ Boolean: this.$t1("布尔"),
130
+ Integer: this.$t1("整数"),
131
+ Long: this.$t1("长整数"),
132
+ Decimal: this.$t1("精度小数"),
133
+ Money: this.$t1("金额"),
134
+ Text: this.$t1("文本"),
135
+ TextArea: this.$t1("长文本"),
136
+ DateTime: this.$t1("日期时间"),
137
+ Reference: this.$t1("关联表(文本)"),
138
+ ReferenceLong: this.$t1("关联表(长整型)"),
139
+ };
140
+ },
141
+ // 单选弹框存的是字段名字符串,zdDialog 的 rows 要的是行对象(按 fieldKey=taZdMc 匹配)
142
+ referenceKeyRows() {
143
+ return this.referenceKey ? [{taZdMc: this.referenceKey}] : [];
144
+ },
145
+ toTaBmZdFieldRows() {
146
+ return this.toTaBmZdField ? [{taZdMc: this.toTaBmZdField}] : [];
147
+ },
148
+ treeFlagMap() {
149
+ return {
150
+ name: this.$t1("名称"),
151
+ wbs: this.$t1("WBS码"),
152
+ parent: this.$t1("上级ID"),
153
+ treePath: this.$t1("树ID路径"),
154
+ treePathName: this.$t1("树名称路径"),
155
+ hasChild: this.$t1("是否有下级"),
156
+ grade: this.$t1("层级"),
157
+ };
158
+ },
146
159
  },
147
160
  created() {
148
161
  if(this.hData){
@@ -174,6 +187,12 @@ modules = {
174
187
  getData(callback) {
175
188
  if(this.extractedObj){
176
189
  this.dataId = this.extractedObj.id;
190
+ // callback 分支(getNewData → createModifyTable)不能在这里被吞掉,
191
+ // 否则从该入口进来点「创建/更新数据表」会静默无反应
192
+ if (callback) {
193
+ callback({objx: this.$baseLodash.cloneDeep(this.extractedObj)});
194
+ return;
195
+ }
177
196
  this.initData(this.extractedObj)
178
197
  //获取操作日志数据
179
198
  this.$refs["oplogTable"].initData({
@@ -222,10 +241,10 @@ modules = {
222
241
  });
223
242
  } else if (this.hData){
224
243
  this.dataId = this.hData.id
225
- /* this.isEdit = true;
226
- this.szTaMb = this.$baseLodash.cloneDeep(this.hData);
227
- this.getMenuKindAuth(this.szTaMb.menuKindCode);
228
- this.getCreatedTableColumns(); */
244
+ if (callback) {
245
+ callback({objx: this.$baseLodash.cloneDeep(this.hData)});
246
+ return;
247
+ }
229
248
  this.initData(this.$baseLodash.cloneDeep(this.hData));
230
249
  if (this.compareHData && this.$attrs.isCompare) {
231
250
  this.oldSzTaMb = this.$baseLodash.cloneDeep(this.compareHData);
@@ -240,34 +259,6 @@ modules = {
240
259
  this.getMenuKindAuth(this.szTaMb.menuKindCode);
241
260
  }
242
261
  },
243
- updateStatus(status) {
244
- let text;
245
- if (status === 3) {
246
- text = this.$t1("您确定要作废吗?");
247
- }
248
- this.$baseConfirm(text).then(() => {
249
- this.$http({
250
- aes: true,
251
- url: USER_PREFIX + `/szTaMb/updateStatus`,
252
- method: `post`,
253
- data: {
254
- id: this.dataId,
255
- status: status,
256
- },
257
- isLoading: true,
258
- success: (res) => {
259
- this.$message({
260
- message: res.content,
261
- type: "success",
262
- duration: 500,
263
- onClose: (t) => {
264
- this.$baseReload();
265
- },
266
- });
267
- },
268
- });
269
- });
270
- },
271
262
  saveData() {
272
263
  this.$refs.editForm.$baseValidate((valid) => {
273
264
  if (valid) {
@@ -277,11 +268,68 @@ modules = {
277
268
  this.$baseAlert(this.$t1("明细不能为空!"));
278
269
  return false;
279
270
  }
271
+ if (!this.validateItems(szTaZdMbDTOs)) {
272
+ return false;
273
+ }
280
274
  this.szTaMb.szTaZdMbDTOs = szTaZdMbDTOs;
281
275
  this.openPreformDialog();
282
276
  }
283
277
  });
284
278
  },
279
+ /**
280
+ * 明细必填校验。
281
+ *
282
+ * 表格开了虚拟滚动(initVxeTable 默认 scrollY.gt = 20),超过 20 行以后屏幕外的行
283
+ * 根本不会渲染,单元格里那些 el-form-item 也就没挂上去 —— el-form 的 validate
284
+ * 只能覆盖当前视口。字段数超过 20 的数据表模板是常态,所以必填必须自己按 fullData 走一遍。
285
+ */
286
+ validateItems(szTaZdMbDTOs) {
287
+ let requiredFields = [
288
+ {field: "zdEn", label: this.$t1("实体字段名称")},
289
+ {field: "zdCh", label: this.$t1("字段描述")},
290
+ ];
291
+ // Object.create(null) 而不是 {}:字段名可能叫 constructor / toString 之类,
292
+ // 普通对象会命中原型链上的同名属性,误判成重复
293
+ let seenZdEn = Object.create(null);
294
+ for (let i = 0; i < szTaZdMbDTOs.length; i++) {
295
+ let row = szTaZdMbDTOs[i];
296
+ for (let j = 0; j < requiredFields.length; j++) {
297
+ let {field, label} = requiredFields[j];
298
+ let value = row[field];
299
+ if (value === null || value === undefined || String(value).trim() === "") {
300
+ this.$baseAlert(
301
+ this.$t1("第{index}行的[{label}]不能为空!", {
302
+ index: i + 1,
303
+ label,
304
+ })
305
+ );
306
+ this.scrollToItemRow(row);
307
+ return false;
308
+ }
309
+ }
310
+ // 实体字段名重复的话建表时才会炸,这里提前拦住
311
+ let zdEn = String(row.zdEn).trim();
312
+ if (seenZdEn[zdEn] !== undefined) {
313
+ this.$baseAlert(
314
+ this.$t1("第{index}行的实体字段名称[{zdEn}]与第{index2}行重复!", {
315
+ index: i + 1,
316
+ zdEn,
317
+ index2: seenZdEn[zdEn] + 1,
318
+ })
319
+ );
320
+ this.scrollToItemRow(row);
321
+ return false;
322
+ }
323
+ seenZdEn[zdEn] = i;
324
+ }
325
+ return true;
326
+ },
327
+ scrollToItemRow(row) {
328
+ let $table = this.$refs["table-szTaZdMb"];
329
+ if ($table && $table.scrollToRow) {
330
+ $table.scrollToRow(row);
331
+ }
332
+ },
285
333
  saveDataHandle(preformData) {
286
334
  let formData = {
287
335
  ...this.szTaMb,
@@ -357,10 +405,10 @@ modules = {
357
405
  let taZdMc = row.taZdMc;
358
406
  let createdTableColumnArray = this.createdTableColumnArray;
359
407
  let oldResult = createdTableColumnArray.includes(row?.hData?.taZdMc)
360
- ? "是"
408
+ ? this.$t1("是")
361
409
  : "_";
362
410
  let result = taZdMc && createdTableColumnArray.includes(taZdMc)
363
- ? "是"
411
+ ? this.$t1("是")
364
412
  : "_";
365
413
  return [
366
414
  <el-form-item>
@@ -551,11 +599,6 @@ modules = {
551
599
  },
552
600
  },
553
601
  ],
554
- config:{
555
- // rowConfig:{
556
- // height: 60,
557
- // }
558
- }
559
602
  };
560
603
  this.$vxeTableUtil.initVxeTable(tableOption).then((opts) => {
561
604
  this.productOption = opts;
@@ -611,9 +654,14 @@ modules = {
611
654
  },
612
655
  deleteItem(row, rowIndex) {
613
656
  if (row.referenceZd) {
657
+ // clearReferenceZd 是 filter 出新数组赋值回去,传进来的 rowIndex 会失效,
658
+ // 所以下面必须重新按行引用定位
614
659
  this.clearReferenceZd(row);
615
660
  }
616
- this.szTaMb.szTaZdMbDTOs.splice(rowIndex, 1);
661
+ let index = this.szTaMb.szTaZdMbDTOs.indexOf(row);
662
+ if (index >= 0) {
663
+ this.szTaMb.szTaZdMbDTOs.splice(index, 1);
664
+ }
617
665
  },
618
666
  confirmInsertSzTaMb(rows) {
619
667
  if (rows.length > 0) {
@@ -623,21 +671,27 @@ modules = {
623
671
  this.$set(this.szTaMb, "sszstBm", row.taBm);
624
672
  }
625
673
  },
626
- confirmInsertItemSzTaMb(rows) {
627
- if (rows.length > 0) {
628
- let row = rows[0];
629
- let szTaZdMbDTO = this.szTaMb.szTaZdMbDTOs[this.zdEnIndex];
630
- this.$set(szTaZdMbDTO, "zdEn", row.taBm + "." + szTaZdMbDTO.zdEn);
631
- this.$set(szTaZdMbDTO, "dybm", row.taEn);
632
- }
633
- },
634
674
  confirmInsertMenuKind(rows) {
635
675
  if (rows.length > 0) {
636
676
  let row = rows[0];
637
677
  this.$set(this.szTaMb, "menuKindCode", row.menuKindCode);
638
678
  this.$set(this.szTaMb, "menuKindName", row.name);
679
+ // 权限是按表单分类取的,换了分类必须重取:
680
+ // 否则新建单据(进来时 menuKindCode 为空、menuKindAuth 停在 editAuth:0)
681
+ // 手工选完分类后「保存」按钮依然不渲染,流程直接走不下去
682
+ this.getMenuKindAuth(row.menuKindCode);
639
683
  }
640
684
  },
685
+ clearSszst() {
686
+ // sszst 不在 szTaMb 的初始声明里(confirmInsertSzTaMb 也是 $set 写进去的),走 $set
687
+ this.$set(this.szTaMb, "sszst", null);
688
+ this.$set(this.szTaMb, "sszstBm", null);
689
+ },
690
+ clearMenuKind() {
691
+ this.szTaMb.menuKindCode = "";
692
+ // 反向同理:分类清空后旧分类的权限不能继续留着
693
+ this.menuKindAuth = { editAuth: 0 };
694
+ },
641
695
  getNewData(callback) {
642
696
  this.getData((res0) => {
643
697
  let szTaMb = res0.objx;
@@ -658,12 +712,14 @@ modules = {
658
712
  });
659
713
  },
660
714
  createModifyTable() {
715
+ let url = this.getServiceUrl("/dbTable/createUpdateTable");
716
+ if (!url) return;
661
717
  let text = this.$t1("您确定要创建/更新数据表吗?");
662
718
  this.$baseConfirm(text).then(() => {
663
719
  this.getNewData((data) => {
664
720
  this.$http({
665
721
  aes: true,
666
- url: "/" + this.szTaMb.serviceName + `/dbTable/createUpdateTable`,
722
+ url: url,
667
723
  method: `post`,
668
724
  data: data,
669
725
  isLoading: true,
@@ -681,6 +737,18 @@ modules = {
681
737
  });
682
738
  });
683
739
  },
740
+ /**
741
+ * 拼「服务名 + 接口路径」。serviceName 为空时不要拼出 /null/... 打到后端,
742
+ * 直接提示并返回 null,由调用方中止。
743
+ */
744
+ getServiceUrl(path) {
745
+ let serviceName = this.szTaMb.serviceName;
746
+ if (!serviceName) {
747
+ this.$baseAlert(this.$t1("服务名不能为空,请先选择表单分类"));
748
+ return null;
749
+ }
750
+ return "/" + serviceName + path;
751
+ },
684
752
  isReferenceZdType(zdType) {
685
753
  return zdType === "Reference" || zdType === "ReferenceLong";
686
754
  },
@@ -691,37 +759,55 @@ modules = {
691
759
  let referenceKey = null;
692
760
  let referenceShowFields = [];
693
761
 
762
+ let referenceShowRows = [];
763
+
694
764
  if (referenceZd) {
695
765
  let index = referenceZd.indexOf(".");
696
766
  referenceEntity = referenceZd.substring(0, index);
697
767
  referenceKey = referenceZd.substr(index + 1);
698
- referenceShowFields = this.szTaMb.szTaZdMbDTOs
768
+ // 回填已有的关联显示字段行时必须带上 zdEn / zdCh:
769
+ // confirmReferenceZdDialog 新建行要用它们拼 "ref_" + zdEn,
770
+ // 只回填 taZdMc 会生成 zdEn 为 "ref_undefined"、zdCh 为空的脏行
771
+ referenceShowRows = this.szTaMb.szTaZdMbDTOs
699
772
  .filter((item) => {
700
- let flag = false;
701
- if (item.relationZd === referenceZd || item.relationZd === referenceZd2) {
702
- flag = true
703
- }
704
- return flag;
773
+ return item.relationZd === referenceZd || item.relationZd === referenceZd2;
705
774
  })
706
775
  .map((item) => {
707
- return item.referenceZd.substr(index + 1);
776
+ let taZdMc = item.referenceZd ? item.referenceZd.substr(index + 1) : null;
777
+ return {
778
+ taZdMc,
779
+ zdEn: item.zdEn ? item.zdEn.replace(/^ref_/, "") : taZdMc,
780
+ zdCh: item.zdCh,
781
+ };
708
782
  });
783
+ referenceShowFields = referenceShowRows.map((item) => item.taZdMc);
709
784
  }
710
785
 
711
786
  this.referenceEntity = referenceEntity;
712
787
  this.referenceKey = referenceKey;
713
788
  this.referenceShowFields = referenceShowFields;
714
789
  this.refServiceName = row.refServiceName ?? null;
790
+ this.referenceShowRows = referenceShowRows;
715
791
 
716
- this.referenceShowRows = referenceShowFields.map((item) => {
717
- return {
718
- taZdMc: item,
719
- };
720
- });
721
-
722
- this.currentIndex = rowIndex;
792
+ this.currentRow = row;
723
793
  this.showReferenceZdDialog = true;
724
794
  },
795
+ /**
796
+ * item 是不是 parentRow 在 parentRefZd 这个关联配置下带出来的显示字段行。
797
+ *
798
+ * relationZd 历史上出现过三种写法(无后缀 / 后缀是主字段 zdEn / 后缀是子行自己的 zdEn),
799
+ * 这里全部认,避免漏匹配导致子行变成孤儿。
800
+ */
801
+ isReferenceChildRow(item, parentRow, parentRefZd) {
802
+ if (!parentRefZd || !item.relationZd) {
803
+ return false;
804
+ }
805
+ return (
806
+ item.relationZd === parentRefZd
807
+ || item.relationZd === parentRefZd + "." + parentRow.zdEn
808
+ || item.relationZd === parentRefZd + "." + item.zdEn
809
+ );
810
+ },
725
811
  changeZdType(row) {
726
812
  let map = {
727
813
  "Integer": "11",
@@ -736,23 +822,6 @@ modules = {
736
822
  this.clearReferenceZd(row);
737
823
  }
738
824
  },
739
- getReferenceChildRows(row) {
740
- let referenceZd = row.referenceZd;
741
- if (!referenceZd && !row.zdEn) {
742
- return [];
743
- }
744
- let referenceZd2 = referenceZd ? referenceZd + "." + row.zdEn : null;
745
- let relationZdSuffix = row.zdEn ? "." + row.zdEn : null;
746
- return this.szTaMb.szTaZdMbDTOs.filter((item) => {
747
- if (referenceZd && (referenceZd === item.relationZd || referenceZd2 === item.relationZd)) {
748
- return true;
749
- }
750
- if (relationZdSuffix && item.relationZd && item.relationZd.endsWith(relationZdSuffix)) {
751
- return true;
752
- }
753
- return false;
754
- });
755
- },
756
825
  confirmClearReferenceZd(row) {
757
826
  if (!row.referenceZd) {
758
827
  return;
@@ -761,11 +830,9 @@ modules = {
761
830
  this.$baseAlert(this.$t1("该字段已在数据库中创建,不能清空关联配置"));
762
831
  return;
763
832
  }
764
- let childRows = this.getReferenceChildRows(row);
765
- if (childRows.some((item) => this.hasFieldCreated(item))) {
766
- this.$baseAlert(this.$t1("关联显示字段已在数据库中创建,不能清空关联配置"));
767
- return;
768
- }
833
+ // 这里原来还有一道「关联显示字段已在数据库中创建」的检查,是死代码:
834
+ // 显示字段行不建库、taZdMc 恒为空,hasFieldCreated 永远返回 false。
835
+ // 连同它唯一的调用方 getReferenceChildRows 一并删掉。
769
836
  let text = this.$t1("清空关联配置将同时删除关联显示字段,您确定要继续吗?");
770
837
  this.$baseConfirm(text).then(() => {
771
838
  this.clearReferenceZd(row);
@@ -788,7 +855,11 @@ modules = {
788
855
  row.refServiceName = null;
789
856
  },
790
857
  confirmReferenceZdDialog() {
791
- let row = this.szTaMb.szTaZdMbDTOs[this.currentIndex];
858
+ let row = this.currentRow;
859
+ if (!row) {
860
+ this.showReferenceZdDialog = false;
861
+ return;
862
+ }
792
863
  let oldReferenceZd = row.referenceZd;
793
864
  let oldReferenceZd2 = row.referenceZd + "." + row.zdEn;
794
865
 
@@ -799,6 +870,18 @@ modules = {
799
870
 
800
871
  let referenceShowFields = this.referenceShowFields;
801
872
 
873
+ // 关联表 / 关联字段任一为空都拼不出合法的 referenceZd,硬走下去
874
+ // 新建行的 relationZd 会拼成 "null.xxx",父子彻底断开、之后再也认不回来。
875
+ // 两个都为空是"清空关联配置",属于合法操作,放行走下面的删除分支。
876
+ if (referenceEntity && !referenceKey) {
877
+ this.$baseAlert(this.$t1("关联字段不能为空"));
878
+ return;
879
+ }
880
+ if (!referenceZd && referenceShowFields.length) {
881
+ this.$baseAlert(this.$t1("关联表不能为空"));
882
+ return;
883
+ }
884
+
802
885
  let keys = referenceShowFields.map((item) => {
803
886
  return referenceEntity + "." + item;
804
887
  });
@@ -819,6 +902,10 @@ modules = {
819
902
  delIndex.push(index);
820
903
  } else {
821
904
  item.refServiceName = refServiceName;
905
+ // 关联表没变、只换了关联字段时,保留下来的子行必须把 relationZd 迁到新的
906
+ // referenceZd 上。否则它们既变成认不回来的孤儿行,
907
+ // 又会因为下面 oldKeys 匹配不到而被当成"新字段"重复插入一遍。
908
+ item.relationZd = referenceZd ? referenceZd + "." + row.zdEn : null;
822
909
  }
823
910
  }
824
911
  });
@@ -831,7 +918,7 @@ modules = {
831
918
  }
832
919
 
833
920
  let oldKeys = this.szTaMb.szTaZdMbDTOs
834
- .filter((item) => (referenceZd === item.relationZd || (referenceZd + "." + item.zdEn) === item.relationZd))
921
+ .filter((item) => this.isReferenceChildRow(item, row, referenceZd))
835
922
  .map((item) => item.referenceZd);
836
923
  let addReferenceShowFields = referenceShowFields.filter((item, index) => {
837
924
  return !oldKeys.includes(referenceEntity + "." + item);
@@ -839,23 +926,32 @@ modules = {
839
926
 
840
927
  let addIndex = -1;
841
928
  let lastIndex = this.szTaMb.szTaZdMbDTOs.findLastIndex((item) => {
842
- return referenceZd === item.relationZd || (referenceZd + "." + item.zdEn) === item.relationZd;
929
+ return this.isReferenceChildRow(item, row, referenceZd);
843
930
  });
844
- addIndex = lastIndex >= 0 ? lastIndex + 1 : this.currentIndex + 1;
931
+ addIndex = lastIndex >= 0
932
+ ? lastIndex + 1
933
+ : this.szTaMb.szTaZdMbDTOs.indexOf(row) + 1;
845
934
 
846
935
  let referenceShowRows = this.referenceShowRows;
847
936
 
848
937
  let addReferenceShowRows = referenceShowRows.filter((item, index) => {
849
938
  return addReferenceShowFields.includes(item.taZdMc);
850
939
  });
940
+ // 已占用的字段名,用来给新建行避让重名;本轮生成的也要边生成边记进去
941
+ let usedZdEns = this.szTaMb.szTaZdMbDTOs
942
+ .map((item) => item.zdEn)
943
+ .filter((item) => !!item);
851
944
  addReferenceShowRows.forEach((item, index) => {
852
945
  let rIndex = addIndex + index;
853
946
  let orders = (row.orders || 0) + index + 1;
854
947
 
948
+ let zdEn = this.buildReferenceZdEn(item.zdEn || item.taZdMc, row, usedZdEns);
949
+ usedZdEns.push(zdEn);
950
+
855
951
  let newItem = this.createRow();
856
952
  Object.assign(newItem, {
857
- zdEn: "ref_" + item.zdEn,
858
- zdCh: item.zdCh,
953
+ zdEn,
954
+ zdCh: item.zdCh || null,
859
955
  required: false,
860
956
  referenceZd: referenceEntity + "." + item.taZdMc,
861
957
  zdType: "Text",
@@ -873,6 +969,35 @@ modules = {
873
969
  this.handleReferenceOrders(row);
874
970
  this.showReferenceZdDialog = false;
875
971
  },
972
+ /**
973
+ * 生成关联显示字段行的实体字段名。
974
+ *
975
+ * 基础名是 ref_<源字段>。两个字段绑同一张表的同一个字段时会撞
976
+ * (典型:创建人 / 修改人都关联 sc_user.id 并显示 name,都想叫 ref_name),
977
+ * 撞了才退化成 ref_<父字段>_<源字段>;还撞就往后加序号。
978
+ * 先到先得,已存在的行不改名,所以存量数据不受影响。
979
+ *
980
+ * @param {String} srcName 源字段名
981
+ * @param {Object} parentRow 发起关联的主字段行
982
+ * @param {Array} usedZdEns 已占用的字段名(含本轮刚生成的)
983
+ */
984
+ buildReferenceZdEn(srcName, parentRow, usedZdEns) {
985
+ let base = "ref_" + srcName;
986
+ if (!usedZdEns.includes(base)) {
987
+ return base;
988
+ }
989
+ let withParent = parentRow.zdEn
990
+ ? "ref_" + parentRow.zdEn + "_" + srcName
991
+ : base;
992
+ if (withParent !== base && !usedZdEns.includes(withParent)) {
993
+ return withParent;
994
+ }
995
+ let index = 2;
996
+ while (usedZdEns.includes(withParent + "_" + index)) {
997
+ index++;
998
+ }
999
+ return withParent + "_" + index;
1000
+ },
876
1001
  createRow(){
877
1002
  let row = {
878
1003
  "orders": null,
@@ -912,11 +1037,9 @@ modules = {
912
1037
  let orders = row.orders || 0;
913
1038
  if (referenceZd) {
914
1039
  this.szTaMb.szTaZdMbDTOs
915
- .filter((item) => referenceZd === item.relationZd || (referenceZd + "." + item.zdEn === item.relationZd))
1040
+ .filter((item) => this.isReferenceChildRow(item, row, referenceZd))
916
1041
  .forEach((item, index) => {
917
- if (referenceZd === item.relationZd || (referenceZd + "." + item.zdEn === item.relationZd)) {
918
- item.orders = orders + index + 1;
919
- }
1042
+ item.orders = orders + index + 1;
920
1043
  });
921
1044
  }
922
1045
  },
@@ -926,14 +1049,23 @@ modules = {
926
1049
  if (this.referenceEntity !== row.taBm) {
927
1050
  this.referenceKey = null;
928
1051
  this.referenceShowFields = [];
1052
+ // 换了关联表,上一张表的显示字段行必须一起丢掉,
1053
+ // 否则 confirmReferenceZdDialog 会拿旧表的 taZdMc 去拼新表的 referenceZd
1054
+ this.referenceShowRows = [];
929
1055
  }
930
1056
  this.referenceEntity = row.taBm;
931
1057
  this.refServiceName = row.serviceName;
932
1058
  }
933
1059
  },
1060
+ clearReferenceEntity() {
1061
+ this.referenceKey = null;
1062
+ this.refServiceName = null;
1063
+ this.referenceShowFields = [];
1064
+ this.referenceShowRows = [];
1065
+ },
934
1066
  openEntityFieldDialog1() {
935
1067
  if (!this.referenceEntity) {
936
- this.$baseAlert("关联表不能为空");
1068
+ this.$baseAlert(this.$t1("关联表不能为空"));
937
1069
  return;
938
1070
  }
939
1071
  this.showEntityFieldDialog1 = true;
@@ -946,21 +1078,22 @@ modules = {
946
1078
  },
947
1079
  openEntityFieldDialog2() {
948
1080
  if (!this.referenceEntity) {
949
- this.$baseAlert("关联表不能为空");
1081
+ this.$baseAlert(this.$t1("关联表不能为空"));
950
1082
  return;
951
1083
  }
952
1084
  this.showEntityFieldDialog2 = true;
953
1085
  },
954
1086
  confirmEntityFieldDialog2(rows) {
955
- if (rows.length) {
956
- this.referenceShowRows = rows;
957
- this.referenceShowFields = rows.map((row) => {
958
- return row.taZdMc;
959
- });
960
- }
1087
+ // 不能用 rows.length 兜底:回填可用之后,把勾选全部取消掉
1088
+ // 就是"清空显示字段"的正常操作,必须让它生效
1089
+ this.referenceShowRows = rows || [];
1090
+ this.referenceShowFields = this.referenceShowRows.map((row) => {
1091
+ return row.taZdMc;
1092
+ });
961
1093
  },
962
1094
  getCreatedTableColumns() {
963
- if (!this.szTaMb.taBm) return;
1095
+ // 这里是首屏静默取数,serviceName 缺失时直接跳过,不弹提示打扰用户
1096
+ if (!this.szTaMb.taBm || !this.szTaMb.serviceName) return;
964
1097
  this.$http({
965
1098
  aes: true,
966
1099
  url: "/" + this.szTaMb.serviceName + "/dbTable/getTableColumns",
@@ -1044,9 +1177,6 @@ modules = {
1044
1177
  let min = 100;
1045
1178
  let szTaZdMbDTOs = this.szTaMb.szTaZdMbDTOs;
1046
1179
  let value = 0;
1047
- let allOrders = szTaZdMbDTOs
1048
- .filter((item) => item.orders !== null && item.orders !== undefined)
1049
- .map((item) => item.orders);
1050
1180
  szTaZdMbDTOs.forEach((item) => {
1051
1181
  let orders = item.orders;
1052
1182
  if (orders !== null && orders !== undefined && orders < 9000) {
@@ -1091,10 +1221,12 @@ modules = {
1091
1221
  this.$baseAlert(this.$t1("数据表不能为空"));
1092
1222
  return;
1093
1223
  }
1224
+ let url = this.getServiceUrl("/dbTable/getSzTaZdMbs");
1225
+ if (!url) return;
1094
1226
  this.showDtDialog = false;
1095
1227
  this.$http({
1096
1228
  // aes: true,
1097
- url: "/" + this.szTaMb.serviceName + `/dbTable/getSzTaZdMbs`,
1229
+ url: url,
1098
1230
  method: `post`,
1099
1231
  data: {
1100
1232
  stringOne: dbTable,
@@ -1198,10 +1330,15 @@ modules = {
1198
1330
  }
1199
1331
  this.toTaBmZdEntity = toTaBmZdEntity;
1200
1332
  this.toTaBmZdField = toTaBmZdField;
1201
- this.currentIndex = rowIndex;
1333
+ this.toTaBmZdRow = row;
1202
1334
  this.showToTaBmZdDialog = true;
1203
1335
  },
1204
1336
  confirmToTaBmZdDialog() {
1337
+ let row = this.toTaBmZdRow;
1338
+ if (!row) {
1339
+ this.showToTaBmZdDialog = false;
1340
+ return;
1341
+ }
1205
1342
  let toTaBmZdEntity = this.toTaBmZdEntity;
1206
1343
  let toTaBmZdField = this.toTaBmZdField;
1207
1344
  if (!toTaBmZdEntity) {
@@ -1212,8 +1349,7 @@ modules = {
1212
1349
  this.$baseAlert(this.$t1("对应表字段不能为空"));
1213
1350
  return;
1214
1351
  }
1215
- this.szTaMb.szTaZdMbDTOs[this.currentIndex].toTaBmZd =
1216
- toTaBmZdEntity + "." + toTaBmZdField;
1352
+ row.toTaBmZd = toTaBmZdEntity + "." + toTaBmZdField;
1217
1353
  this.showToTaBmZdDialog = false;
1218
1354
  },
1219
1355
  openEntityDialog3() {
@@ -1241,20 +1377,31 @@ modules = {
1241
1377
  this.toTaBmZdField = row.taZdMc;
1242
1378
  }
1243
1379
  },
1244
- inputZdEn(row) {
1245
-
1246
- this.preValue = row.zdEn; // 更新旧值
1247
- this.fkey = true
1380
+ /**
1381
+ * 进入字段名输入框时记下原值。
1382
+ *
1383
+ * 原来是靠 keydown 开闸(fkey),但鼠标右键粘贴、拖拽填入、部分输入法提交路径
1384
+ * 都不产生 keydown,那些场景下 changeZdEn 整个被跳过,子行的 relationZd
1385
+ * 会停在旧字段名上变成孤儿行。改成 focus 播种,任何修改途径都覆盖得到。
1386
+ */
1387
+ cacheZdEn(row) {
1388
+ this.preValue = row.zdEn;
1248
1389
  },
1390
+ /**
1391
+ * 改字段名时,把该行关联带出来的显示字段行的 relationZd 一起迁过去。
1392
+ */
1249
1393
  changeZdEn(val, row) {
1250
- if(!this.fkey)return
1251
1394
  let oldVal = this.preValue;
1252
- let newVal = val
1395
+ let newVal = val;
1396
+ this.preValue = newVal;
1397
+ if (oldVal === undefined || oldVal === null || oldVal === newVal) {
1398
+ return;
1399
+ }
1253
1400
  if (this.isReferenceZdType(row.zdType)) {
1254
1401
  let referenceZd = row.referenceZd;
1255
1402
  if (referenceZd) {
1256
- let referenceZd2 = row.referenceZd + "." + oldVal
1257
- let relationZd = row.referenceZd + "." + newVal
1403
+ let referenceZd2 = referenceZd + "." + oldVal;
1404
+ let relationZd = referenceZd + "." + newVal;
1258
1405
  this.szTaMb.szTaZdMbDTOs.forEach((item, index) => {
1259
1406
  if (referenceZd === item.relationZd || referenceZd2 === item.relationZd) {
1260
1407
  item.relationZd = relationZd;
@@ -1262,7 +1409,6 @@ modules = {
1262
1409
  });
1263
1410
  }
1264
1411
  }
1265
- this.fkey = false
1266
1412
  },
1267
1413
 
1268
1414
  getOtherMenuKindAuth() {
@@ -1287,7 +1433,7 @@ modules = {
1287
1433
  this.$baseReload()
1288
1434
  },
1289
1435
  excelExport(){
1290
- this.$excelExport({title: '数据表字段明细导出', targetRef: 'table-szTaZdMb', prefix: USER_PREFIX, type: 'selected'})
1436
+ this.$excelExport({title: this.$t1('数据表字段明细导出'), targetRef: 'table-szTaZdMb', prefix: USER_PREFIX, type: 'selected'})
1291
1437
  },
1292
1438
  getHValue(row, column) {
1293
1439
  if (row.hData && row.hData.id) {
@@ -54,6 +54,9 @@ modules = {
54
54
  ...this.param,
55
55
  };
56
56
  },
57
+ callback: (rows) => {
58
+ this.restoreChecked(rows);
59
+ },
57
60
  columns: [
58
61
  { type: "checkbox", width: 48, resizable: false, fixed: "left" },
59
62
  {
@@ -111,6 +114,35 @@ modules = {
111
114
  that.vxeOption = opts;
112
115
  });
113
116
  },
117
+ /**
118
+ * 列表每次查询完,把已选中的字段重新勾上。
119
+ *
120
+ * selectDialogMixins.initSetting 只把 rows 播种进 checkRows(右侧已选列表),
121
+ * 表格自身的勾选状态没人恢复 —— 不补这一步,弹框打开时左边一个勾都没有,
122
+ * 用户再勾一个新字段就会把原有的显示字段整组顶掉。
123
+ */
124
+ restoreChecked(rows) {
125
+ let checkRows = this.checkRows;
126
+ if (!checkRows || !checkRows.length || !rows || !rows.length) {
127
+ return;
128
+ }
129
+ let fieldKey = this.fieldKey;
130
+ let keys = checkRows.map((item) => item[fieldKey]);
131
+ let targetRows = rows.filter((row) => keys.includes(row[fieldKey]));
132
+ if (!targetRows.length) {
133
+ return;
134
+ }
135
+ // 回填进来的可能只是 { taZdMc } 这样的占位行,用列表里的真实行替换掉,
136
+ // 保证「确定」抛给调用方的是带 zdEn / zdCh 的完整数据
137
+ this.checkRows = checkRows.map((item) => {
138
+ let real = targetRows.find((row) => row[fieldKey] === item[fieldKey]);
139
+ return real || item;
140
+ });
141
+ let $grid = this.$refs[this.defaultTableRefName];
142
+ if ($grid && $grid.setCheckboxRow) {
143
+ $grid.setCheckboxRow(targetRows, true);
144
+ }
145
+ },
114
146
  },
115
147
  };
116
148
  export default modules;
@@ -107,7 +107,9 @@ export default {
107
107
  this.$getBaseDicts({
108
108
  code: "sysType",
109
109
  success: ({ dicts }) => {
110
- this.showVocMenuBtn = (dicts || []).some((item) => item.sn === "voc");
110
+ let vocItem = (dicts || []).find((item) => item.sn === "voc");
111
+ this.showVocMenuBtn = !!vocItem;
112
+ this.vocMenuLabel = (vocItem && vocItem.value) || "";
111
113
  },
112
114
  }).finally(() => {
113
115
  this.initTableList();
@@ -120,6 +122,7 @@ export default {
120
122
  showEdit: false,
121
123
  showVocEdit: false,
122
124
  showVocMenuBtn: false,
125
+ vocMenuLabel: "",
123
126
  vxeOption: {},
124
127
  formData: {},
125
128
  };
@@ -229,7 +232,7 @@ export default {
229
232
  }}
230
233
  v-show={this.showVocMenuBtn}
231
234
  >
232
- {this.$t1("VOC菜单")}
235
+ {this.vocMenuLabel}
233
236
  </a>,
234
237
  ];
235
238
  },
@@ -4,7 +4,7 @@
4
4
  <div class="d-header clearfix">
5
5
  <div class="fl">
6
6
  <i class="el-icon-info" />
7
- {{ $t1("VOC菜单") }}{{ role.name ? " - " + role.name : "" }}
7
+ {{ vocMenuLabel }}{{ role.name ? " - " + role.name : "" }}
8
8
  </div>
9
9
  <div class="fr">
10
10
  <el-button
@@ -65,7 +65,7 @@
65
65
  </table>
66
66
  </template>
67
67
  </baseTabPane>
68
- <baseTabPane :label="$t1('VOC菜单')">
68
+ <baseTabPane :label="vocMenuLabel">
69
69
  <template #default>
70
70
  <div class="role-box">
71
71
  <div class="item" v-for="item in allMenus" :key="item.id">
@@ -133,17 +133,28 @@ export default {
133
133
  return {
134
134
  dataId: "",
135
135
  sysType: "voc",
136
+ vocMenuLabel: "",
136
137
  role: {},
137
138
  allMenus: [],
138
139
  };
139
140
  },
140
141
  created() {
141
142
  if (this._dataId) this.dataId = this._dataId;
143
+ this.loadVocMenuLabel();
142
144
  },
143
145
  mounted() {
144
146
  this.getData();
145
147
  },
146
148
  methods: {
149
+ loadVocMenuLabel() {
150
+ this.$getBaseDicts({
151
+ code: "sysType",
152
+ success: ({ dicts }) => {
153
+ let vocItem = (dicts || []).find((item) => item.sn === this.sysType);
154
+ if (vocItem) this.vocMenuLabel = vocItem.value || "";
155
+ },
156
+ });
157
+ },
147
158
  getData() {
148
159
  if (!this.dataId) {
149
160
  this.initMenuData();