cloud-web-corejs 1.0.127 → 1.0.129

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.127",
4
+ "version": "1.0.129",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "lint": "eslint --ext .js,.vue src",
@@ -1,41 +1,57 @@
1
1
  <template>
2
- <form-item-wrapper :designer="designer" :field="field" :rules="rules" :design-state="designState"
3
- :parent-widget="parentWidget" :parent-list="parentList" :index-of-parent-list="indexOfParentList"
4
- :sub-form-row-index="subFormRowIndex" :sub-form-col-index="subFormColIndex"
5
- :sub-form-row-id="subFormRowId">
2
+ <form-item-wrapper
3
+ :designer="designer"
4
+ :field="field"
5
+ :rules="rules"
6
+ :design-state="designState"
7
+ :parent-widget="parentWidget"
8
+ :parent-list="parentList"
9
+ :index-of-parent-list="indexOfParentList"
10
+ :sub-form-row-index="subFormRowIndex"
11
+ :sub-form-col-index="subFormColIndex"
12
+ :sub-form-row-id="subFormRowId"
13
+ >
6
14
  <div id="uploadImage" class="upload-img" v-if="designState">
7
- <div class="el-upload el-upload--picture" style="vertical-align: middle;display: inline-block;float:left">
8
- <button type="button" class=" avatar-uploader">
15
+ <div
16
+ class="el-upload el-upload--picture"
17
+ style="vertical-align: middle; display: inline-block; float: left"
18
+ >
19
+ <button type="button" class="avatar-uploader">
9
20
  <i class="el-icon-plus avatar-uploader-icon"></i>
10
21
  </button>
11
22
  </div>
12
23
  </div>
13
- <baseUpload accept="file" :file.sync="fieldModel" :hidePasteArea.sync="isH5"
14
- :uploadDialogCustomClass="isH5?'dialog-upload-h5':null" :pickPrivateProfile="false"
15
- :multi="field.options.limit!==1"
16
- :limit="field.options.limit"
17
- resultType="Array"
18
- :edit="!field.options.disabled"
19
- @callback="submitFile"
20
- :hideInfo="field.options.hideFileInfo"
21
- :hideName="field.options.hideFileName"
22
- :showSize="!!field.options.showFileSize"
23
- :createBy="!!field.options.showFileCreateBy"
24
- :createDate="!!field.options.showFileCreateDate"
25
- :widgetSize="field.options.fileShowImageSize"
26
- v-else></baseUpload>
24
+ <baseUpload
25
+ accept="file"
26
+ :file.sync="fieldModel"
27
+ :hidePasteArea.sync="isH5"
28
+ :uploadDialogCustomClass="isH5 ? 'dialog-upload-h5' : null"
29
+ :pickPrivateProfile="false"
30
+ :multi="field.options.limit !== 1"
31
+ :limit="field.options.limit"
32
+ resultType="Array"
33
+ :edit="!field.options.disabled"
34
+ @callback="submitFile"
35
+ :hideInfo="field.options.hideFileInfo"
36
+ :hideName="field.options.hideFileName"
37
+ :showSize="!!field.options.showFileSize"
38
+ :createBy="!!field.options.showFileCreateBy"
39
+ :createDate="!!field.options.showFileCreateDate"
40
+ :widgetSize="field.options.fileShowImageSize"
41
+ v-else
42
+ ></baseUpload>
27
43
  </form-item-wrapper>
28
44
  </template>
29
45
 
30
46
  <script>
31
- import FormItemWrapper from './form-item-wrapper'
32
- import emitter from '../../../../../components/xform/utils/emitter'
47
+ import FormItemWrapper from "./form-item-wrapper";
48
+ import emitter from "../../../../../components/xform/utils/emitter";
33
49
  import i18n from "../../../../../components/xform/utils/i18n";
34
50
  import fieldMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/fieldMixin";
35
51
 
36
52
  export default {
37
53
  name: "vabUpload-widget",
38
- componentName: 'FieldWidget', //必须固定为FieldWidget,用于接收父级组件的broadcast事件
54
+ componentName: "FieldWidget", //必须固定为FieldWidget,用于接收父级组件的broadcast事件
39
55
  mixins: [emitter, fieldMixin, i18n],
40
56
  props: {
41
57
  field: Object,
@@ -46,44 +62,44 @@ export default {
46
62
 
47
63
  designState: {
48
64
  type: Boolean,
49
- default: false
65
+ default: false,
50
66
  },
51
67
 
52
- subFormRowIndex: { /* 子表单组件行索引,从0开始计数 */
53
- type: Number,
54
- default: -1
68
+ subFormRowIndex: {
69
+ /* 子表单组件行索引,从0开始计数 */ type: Number,
70
+ default: -1,
55
71
  },
56
- subFormColIndex: { /* 子表单组件列索引,从0开始计数 */
57
- type: Number,
58
- default: -1
72
+ subFormColIndex: {
73
+ /* 子表单组件列索引,从0开始计数 */ type: Number,
74
+ default: -1,
75
+ },
76
+ subFormRowId: {
77
+ /* 子表单组件行Id,唯一id且不可变 */ type: String,
78
+ default: "",
59
79
  },
60
- subFormRowId: { /* 子表单组件行Id,唯一id且不可变 */
61
- type: String,
62
- default: ''
63
- }
64
80
  },
65
81
  components: {
66
82
  FormItemWrapper,
67
83
  },
68
- inject: ['refList', 'globalOptionData', 'globalModel', 'getFormConfig'],
84
+ inject: ["refList", "globalOptionData", "globalModel", "getFormConfig"],
69
85
  data() {
70
86
  return {
71
87
  oldFieldValue: [], //field组件change之前的值
72
88
  fieldModel: [],
73
89
  rules: [],
74
- isH5: false
75
- }
90
+ isH5: false,
91
+ };
76
92
  },
77
93
  watch: {
78
94
  fieldModel(val) {
79
95
  this.handleChangeEvent(val);
80
- }
96
+ },
81
97
  },
82
98
  computed: {
83
99
  formDataId() {
84
100
  let formRef = this.getFormRef();
85
101
  return formRef.dataId;
86
- }
102
+ },
87
103
  },
88
104
  beforeCreate() {
89
105
  /* 这里不能访问方法和属性!! */
@@ -93,26 +109,26 @@ export default {
93
109
  /* 注意:子组件mounted在父组件created之后、父组件mounted之前触发,故子组件mounted需要用到的prop
94
110
  需要在父组件created中初始化!! */
95
111
 
96
- this.isH5 = this.getFormConfig().layoutType === 'H5';
112
+ this.isH5 = this.getFormConfig().layoutType === "H5";
97
113
 
98
- this.initFieldModel()
99
- this.registerToRefList()
100
- this.initEventHandler()
101
- this.buildFieldRules()
114
+ this.initFieldModel();
115
+ this.registerToRefList();
116
+ this.initEventHandler();
117
+ this.buildFieldRules();
102
118
 
103
- this.handleOnCreated()
119
+ this.handleOnCreated();
104
120
  },
105
121
 
106
122
  mounted() {
107
- this.handleOnMounted()
123
+ this.handleOnMounted();
108
124
  },
109
125
 
110
126
  beforeDestroy() {
111
- this.unregisterFromRefList()
127
+ this.unregisterFromRefList();
112
128
  },
113
129
  methods: {
114
130
  setValue(val) {
115
- let data = val || []
131
+ let data = val || [];
116
132
  this.fieldModel = data;
117
133
  this.getFormRef().formDataModel[this.fieldKeyName] = data;
118
134
  },
@@ -122,10 +138,12 @@ export default {
122
138
  let reportTemplate = this.getFormRef().reportTemplate;
123
139
  let formCode = reportTemplate.formCode;
124
140
  let formScriptEnabled = this.field.options.formScriptEnabled || false;
125
- let scriptCode = this.field.options.formScriptCode || "getList"
141
+ let scriptCode = this.field.options.formScriptCode || "getList";
126
142
  if (!scriptCode) return;
127
143
  if (dataId) {
128
- let accessParam = this.handleCustomEvent(this.field.options.formScriptParam)
144
+ let accessParam = this.handleCustomEvent(
145
+ this.field.options.formScriptParam
146
+ );
129
147
  return this.formHttp({
130
148
  // url: "/" + reportTemplate.serviceName + "/form_ins/getList",
131
149
  scriptCode: scriptCode,
@@ -135,22 +153,123 @@ export default {
135
153
  taBm: this.fieldKeyName,
136
154
  data: {
137
155
  ...accessParam,
138
- id: dataId
139
- }
156
+ id: dataId,
157
+ },
140
158
  },
141
- callback: res => {
159
+ callback: (res) => {
142
160
  let rows = res.objx || [];
143
- this.setValue(rows)
144
- this.handleCustomEvent(this.field.options.formScriptSuccess,['res'],[res]);
145
- }
161
+ this.setValue(rows);
162
+ this.handleCustomEvent(
163
+ this.field.options.formScriptSuccess,
164
+ ["res"],
165
+ [res]
166
+ );
167
+ },
146
168
  });
147
169
  }
148
170
  },
149
171
  submitFile(rows, fileInfos) {
150
172
  // this.handlLineCode(fileInfos);
151
- let eventParamNames = ['attachments', 'fileInfos'];
173
+ let eventParamNames = ["attachments", "fileInfos"];
152
174
  let eventParamValues = [rows, fileInfos];
153
- this.handleCustomEvent(this.field.options.onAfterConfirmFile, eventParamNames, eventParamValues)
175
+ this.handleCustomEvent(
176
+ this.field.options.onAfterConfirmFile,
177
+ eventParamNames,
178
+ eventParamValues
179
+ );
180
+ },
181
+ setValueByUrl(fileUrl) {
182
+ let value = [];
183
+ if (fileUrl) {
184
+ let row = this.parseFileUrl(fileUrl);
185
+ if (row) {
186
+ value.push(row);
187
+ }
188
+ }
189
+ this.setValue(value);
190
+ },
191
+ parseFileUrl(fileUrl) {
192
+ if (!fileUrl) return null;
193
+ let result = null;
194
+
195
+ // 输入校验
196
+ if (typeof fileUrl !== "string") {
197
+ throw new TypeError("输入必须是字符串格式");
198
+ }
199
+ if (!fileUrl.trim()) {
200
+ throw new Error("URL不能为空");
201
+ }
202
+
203
+ // 基本URL格式验证
204
+ const urlRegex =
205
+ /^(https?:\/\/)?([\w.-]+)(:\d+)?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/i;
206
+ if (!urlRegex.test(fileUrl)) {
207
+ throw new Error("无效的URL格式");
208
+ }
209
+
210
+ // 提取域名部分
211
+ const domainRegex = /^(https?:\/\/[^\/]+)/i;
212
+ const domainMatch = fileUrl.match(domainRegex);
213
+ if (!domainMatch) {
214
+ throw new Error("URL缺少协议或域名部分");
215
+ }
216
+ const domain = domainMatch[0];
217
+
218
+ // 提取完整路径
219
+ const url = fileUrl.substring(domain.length);
220
+ if (!url || url === "/") {
221
+ throw new Error("URL缺少文件路径部分");
222
+ }
223
+
224
+ // 提取带扩展名的文件名
225
+ const filenameRegex = /[^\/]+$/;
226
+ const filenameMatch = url.match(filenameRegex);
227
+ if (!filenameMatch) {
228
+ throw new Error("无法从路径中提取文件名");
229
+ }
230
+ const fullFilename = filenameMatch[0];
231
+
232
+ // 验证文件名格式(至少1字符+扩展名)
233
+ const nameFormat = /^.+\..+$/;
234
+ if (!nameFormat.test(fullFilename)) {
235
+ throw new Error(`无效的文件名格式: ${fullFilename}`);
236
+ }
237
+
238
+ // 修复点:更可靠的文件名和扩展名分离
239
+ const lastDotIndex = fullFilename.lastIndexOf(".");
240
+ const filenameBase = fullFilename.substring(0, lastDotIndex); // 点之前部分
241
+ const extension = fullFilename.substring(lastDotIndex + 1).toLowerCase(); // 点之后部分
242
+
243
+ // 扩展名验证
244
+ /* const validExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp'];
245
+ if (!validExtensions.includes(extension)) {
246
+ throw new Error(`不支持的扩展名类型: ${extension}`);
247
+ } */
248
+
249
+ let thumbnail = null,
250
+ large = null,
251
+ medium = null,
252
+ source = null;
253
+ if (this.$commonFileUtil.isPicture(extension)) {
254
+ thumbnail = url;
255
+ large = url;
256
+ medium = url;
257
+ source = url;
258
+ }
259
+
260
+ result = {
261
+ extension,
262
+ domain,
263
+ url,
264
+ thumbnail,
265
+ large,
266
+ medium,
267
+ source,
268
+ name: fullFilename,
269
+ };
270
+
271
+ // 返回结构化对象
272
+ return result;
154
273
  },
155
274
  /*handlLineCode(fileInfos) {
156
275
  let allPromise = [];
@@ -224,8 +343,8 @@ export default {
224
343
  this.error = errorMessage;
225
344
  this.loading = false;
226
345
  },*/
227
- }
228
- }
346
+ },
347
+ };
229
348
  </script>
230
349
 
231
350
  <style lang="scss" scoped>
@@ -236,17 +355,19 @@ export default {
236
355
  }
237
356
 
238
357
  .hideUploadDiv {
239
- ::v-deep div.el-upload--picture-card { /* 隐藏最后的图片上传按钮 */
358
+ ::v-deep div.el-upload--picture-card {
359
+ /* 隐藏最后的图片上传按钮 */
240
360
  display: none;
241
361
  }
242
362
 
243
- ::v-deep div.el-upload--text { /* 隐藏最后的文件上传按钮 */
363
+ ::v-deep div.el-upload--text {
364
+ /* 隐藏最后的文件上传按钮 */
244
365
  display: none;
245
366
  }
246
367
 
247
- ::v-deep div.el-upload__tip { /* 隐藏最后的文件上传按钮提示 */
368
+ ::v-deep div.el-upload__tip {
369
+ /* 隐藏最后的文件上传按钮提示 */
248
370
  display: none;
249
371
  }
250
372
  }
251
-
252
373
  </style>
@@ -206,15 +206,18 @@
206
206
  </component>
207
207
  </template>-->
208
208
  <template #widget="obj">
209
- <template
210
- v-if="!!fieldSchemaMap[obj.row._X_ROW_KEY] && fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.widget.id]">
209
+ <template v-if="!!getTableColumnWidget(obj)">
211
210
  <template v-if="obj.column.params.widget.type == 'status'">
212
- <template
213
- v-for="(item,index) in fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.widget.id].options.statusParam">
214
- <span
215
- v-if="obj.row[getFieldKeyName(fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.widget.id])]===item.value"
216
- :key="fieldSchemaMap[obj.row._X_ROW_KEY][obj.column.params.widget.id].id+'-'+index" class="list-tag"
217
- :class="item.type">{{ getI18nLabel(item.label) }}</span>
211
+ <template v-for="(item,index) in getTableColumnWidget(obj).options.statusParam">
212
+ <template v-if="isShowColumnStatusWidget(obj,item)">
213
+ <span
214
+ v-if="getTableColumnWidget(obj).options.formScriptEnabled || getTableColumnWidget(obj).options.commonAttributeEnabled"
215
+ :key="getTableColumnWidget(obj).id+'-'+index">{{ getI18nLabel(item[getTableColumnStatusWidgetLabelKey(obj)]) }}</span>
216
+ <span
217
+ v-else
218
+ :key="getTableColumnWidget(obj).id+'-'+index" class="list-tag"
219
+ :class="item.type">{{ getI18nLabel(item[getTableColumnStatusWidgetLabelKey(obj)]) }}</span>
220
+ </template>
218
221
  </template>
219
222
  </template>
220
223
  <component
@@ -242,7 +245,7 @@
242
245
  <div>
243
246
  <template v-for="(fieldWidget,index) in obj.column.params.widgetList">
244
247
  <component
245
- v-if="!!fieldSchemaMap[obj.row._X_ROW_KEY]"
248
+ v-if="!!fieldSchemaMap[obj.row._X_ROW_KEY] && !!obj.row._X_ROW_KEY"
246
249
  :is="getColumnWidgetName(fieldWidget)"
247
250
  v-bind="getRowWidgetOption(obj,fieldWidget)"
248
251
  :form-model="globalModel.formModel"
@@ -252,7 +255,7 @@
252
255
  :columnConfig="obj.column.params.columnConfig"
253
256
  :subFormRowIndex="obj.rowIndex"
254
257
  :subFormRowId="obj.row._X_ROW_KEY"
255
- formItemProp="false"
258
+ :formItemProp="getColumnProp2(fieldWidget, obj)"
256
259
  :tableParam="obj"
257
260
  >
258
261
  <template v-for="slot in Object.keys($scopedSlots)" v-slot:[slot]="scope">