rb-document-form-constructor 0.9.16 → 0.9.18

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.
@@ -1,301 +1,308 @@
1
- <template>
2
- <b-form v-if="formConfig && formConfig.sections" class="rb-doc-form" @submit.prevent>
3
- <div
4
- v-for="section in formConfig.sections"
5
- :key="section.labelRu"
6
- :class="className"
7
- class="rb-form-section"
8
- >
9
- <b-row>
10
- <b-col lg="12">
11
- <h4>{{ getDisplayField(section) }}</h4>
12
- </b-col>
13
- <template v-for="column in section.columns">
14
- <b-col :key="column.index" :lg="getColumnSize(section)" :sm="12">
15
- <template v-for="field in column.fields">
16
- {{ field.valueName }}
17
- <b-form-row v-if="field.visible" :key="field.name">
18
- <b-col lg="12">
19
- <b-form-group
20
- ref="inputContainer"
21
- :data-field="field.name"
22
- :invalid-feedback="validationState[`${field.name}__feedback`]"
23
- :state="validationState[field.name]"
24
- >
25
- <component
26
- v-bind:is="field.input.type"
27
- :id="field.name"
28
- :ref="field.ref? field.ref: field.name"
29
- v-model="doc[field.name]"
30
- :disabled="!editable || !field.editable"
31
- :markForBackResolution="isResolvableField(field)"
32
- :required="field.required"
33
- :resolve-value="getResolveValue(field)"
34
- :resolveFromObject="isResolvableField(field)"
35
- :resolveObject.sync="doc[getResolveFieldName(field)]"
36
- :state="validationState[field.name]"
37
- v-bind="field.input.propsData"
38
- @change="onEventFired('change', $event, field)"
39
- @click="onEventFired('click', $event, field)"
40
- @input="onEventFired('input', $event, field)"
41
- @hook:created="onEventFired('created', $event, field)"
42
- @hook:destroyed="onEventFired('destroyed', $event, field)"
43
- @hook:activated="onEventFired('activated', $event, field)"
44
- @hook:mounted="onEventFired('mounted', $event, field)"
45
- ></component>
46
- <template #label>
47
- <span :title="getDisplayField(field)">{{ getDisplayField(field) }}</span>
48
- <span v-if="showRequiredInLabel && field.required" class="text-danger"
49
- >*</span
50
- >
51
- </template>
52
- </b-form-group>
53
- </b-col>
54
- </b-form-row>
55
- </template>
56
- </b-col>
57
- </template>
58
- </b-row>
59
- </div>
60
- </b-form>
61
- </template>
62
-
63
- <script>
64
- import Vue from 'vue';
65
- import {UtFormConstructor} from '../utils/UtFormConstructor';
66
- import typeOf from 'typeof';
67
- import {UtFormConfig} from '@/utils/UtFormConfig';
68
- import {UtArray} from "@/utils/UtArray";
69
-
70
- export default {
71
- name: 'DocForm',
72
- props: {
73
- formConfig: Object,
74
- applyDefaultValues: {type: Boolean, default: true},
75
- doc: {type: Object, default: () => ({})},
76
- refSuffix: {type: String, default: 'Id'},
77
- editable: {type: Boolean, default: true},
78
- displayField: {type: String, default: 'labelRu'},
79
- showRequiredInLabel: {type: Boolean, default: true},
80
- className: {type: String, default: 'container'},
81
- },
82
- data() {
83
- return {
84
- validationState: {},
85
- };
86
- },
87
- watch: {
88
- formConfig() {
89
- this.validationState = {};
90
- this.execApplyDefaultValues();
91
- this.execApplyDefaultValRule();
92
- },
93
- },
94
- methods: {
95
- getResolveValueName(field) {
96
- if ((field.dict || field.ref) && !field.multiple) {
97
- return field.name.substring(0, field.name.length - 2);
98
- }
99
- return field.name;
100
- },
101
- getResolveValue(field) {
102
- return this.doc[this.getResolveValueName(field)]
103
- ? this.doc[this.getResolveValueName(field)]
104
- : null;
105
- },
106
- getDisplayField(value) {
107
- if (!value[this.displayField]) {
108
- return value.labelRu;
109
- } else {
110
- return value[this.displayField];
111
- }
112
- },
113
- isResolvableField(field) {
114
- return !!field.ref;
115
- },
116
- getResolveObject(field) {
117
- if (this.isResolvableField(field)) {
118
- let resolveFieldName = this.getResolveFieldName(field);
119
- return field.multiple ? this.doc[field.name] : this.doc[resolveFieldName];
120
- } else {
121
- return null;
122
- }
123
- },
124
- getResolveFieldName(field) {
125
- let resolveFieldName = field?.name
126
- if (resolveFieldName?.endsWith('Id')) {
127
- resolveFieldName = field.name.substring(0, field.name.length - 2);
128
- }
129
- return resolveFieldName;
130
- },
131
- onEventFired(eventName, event, field) {
132
- if (field.rules) {
133
- field.rules.forEach((rule) => {
134
- if (rule.event === eventName && rule.script) {
135
- this.runRule(rule, {event, eventName});
136
- }
137
- });
138
- }
139
- },
140
- onGlobalEventFired(eventName, event) {
141
- let fields = UtFormConfig.getFields(this.formConfig);
142
- fields.forEach((f) => {
143
- if (f.rules) {
144
- f.rules.forEach((r) => {
145
- if (r.event === eventName) {
146
- this.runRule(r, {event, eventName});
147
- }
148
- });
149
- }
150
- });
151
- },
152
- createRuleContext(additionalContext) {
153
- return Object.assign(
154
- {
155
- form: this,
156
- doc: this.doc,
157
- ...additionalContext,
158
- },
159
- UtFormConstructor.getRuleContext(),
160
- );
161
- },
162
- runRule(rule, context) {
163
- UtFormConstructor.runRule(this.createRuleContext(context), rule.script);
164
- },
165
- isValueEmpty(fieldName) {
166
- if (this.doc[fieldName] == null) {
167
- return true;
168
- }
169
- if (Array.isArray(this.doc[fieldName]) && !this.doc[fieldName]?.length) {
170
- return true;
171
- }
172
-
173
- if (typeOf(this.doc[fieldName] === 'string') && this.doc[fieldName] === '') {
174
- return true;
175
- }
176
- return false;
177
- },
178
- isValueLessThanMax(fieldname, max) {
179
- if (this.doc[fieldname] && max) {
180
- return this.doc[fieldname]?.length > parseInt(max);
181
- }
182
- return false;
183
- },
184
- isValueLessThanMin(fieldname, min) {
185
- if (this.doc[fieldname] && min) {
186
- return parseInt(this.doc[fieldname]) < parseInt(min);
187
- }
188
-
189
- return false;
190
- },
191
- validate(callback = () => {
192
- }) {
193
- this.formConfig.sections.forEach((s) => {
194
- s.columns.forEach((c) => {
195
- c.fields.forEach((f) => {
196
-
197
- let feedback = '';
198
-
199
- if (f.required && this.isValueEmpty(f.name)) {
200
- feedback += this.getDisplayField(f);
201
- }
202
-
203
- if (f.type === 'integer' && this.isValueLessThanMin(f.name, f.input.propsData.min)) {
204
- feedback += f.input.propsData.min;
205
- }
206
- // TODO: Костыль так как на бэке нету типа memo
207
- if (f.input.type === 'b-form-textarea' && this.isValueLessThanMax(f.name, f.input.propsData?.max)) {
208
- feedback += `\nМаксимальное значение для этого поля ${f.input.propsData?.max}`;
209
- }
210
-
211
- if (f.required && f.input.propsData?.isInlineTableInput) {
212
- const findErrors = this.$refs?.[f.name]?.[0]?.getIsDirty?.() ?? [];
213
- const errors = UtArray.removeDuplicate(findErrors, 'field')?.map(f => f?.label).join(', ')
214
- feedback = errors ? this.$t('validate.multiRequired', {field: errors}) : this.isValueEmpty(f.name) ? this.getDisplayField(f) : ''
215
- }
216
- if (feedback) {
217
- Vue.set(this.validationState, f.name, false);
218
- Vue.set(this.validationState, `${f.name}__feedback`, feedback);
219
- } else {
220
- Vue.set(this.validationState, f.name, null);
221
- }
222
- callback(feedback, this.$refs, f, this.doc)
223
- this.onEventFired(
224
- 'validate',
225
- {
226
- validationState: this.validationState,
227
- doc: this.doc,
228
- },
229
- f,
230
- );
231
- });
232
- });
233
- });
234
- for (let fieldName in this.validationState) {
235
- if (this.validationState[fieldName] === false) {
236
- return false;
237
- }
238
- }
239
-
240
- return true;
241
- },
242
- getColumnSize(section) {
243
- const MAX_COLUMN_SIZE = 12;
244
- if (!section || !section.columnCount) {
245
- return MAX_COLUMN_SIZE;
246
- }
247
-
248
- let colSize = Math.floor(MAX_COLUMN_SIZE / section.columnCount);
249
- return colSize;
250
- },
251
- isNotUndefinedAndNull(value) {
252
- return !(value === null || value === undefined)
253
- },
254
- execApplyDefaultValues() {
255
- if (this.applyDefaultValues) {
256
- this.formConfig.sections.forEach((r) => {
257
- r.columns.forEach((c) => {
258
- c.fields.forEach((f) => {
259
- if (this.isNotUndefinedAndNull(f.defaultValue)) {
260
- let defValue;
261
- if (this.defaultValue && typeOf(f.defaultValue) === 'function') {
262
- defValue = f.defaultValue();
263
- } else {
264
- defValue = f.defaultValue == null ? null : f.defaultValue;
265
- }
266
- this.$set(this.doc, f.name, (f.defaultValue = defValue));
267
- }
268
- });
269
- });
270
- });
271
- }
272
- },
273
- execApplyDefaultValRule() {
274
- this.formConfig.sections.forEach((el) => {
275
- el.columns.forEach((c) => {
276
- c.fields.forEach((f) => {
277
- if (f.rules) {
278
- if (!f.defaultValue) {
279
- const rule = f.rules.find((rule) => rule.event === 'defaultValue');
280
- if (rule && !this.doc[f.name]) {
281
- this.$set(this.doc, f.name, (f.defaultValue = eval(rule.script)));
282
- }
283
- }
284
- }
285
- });
286
- });
287
- });
288
- },
289
- },
290
- mounted() {
291
- this.execApplyDefaultValues();
292
- this.execApplyDefaultValRule();
293
- this.onGlobalEventFired('form-mounted', this);
294
- },
295
- activated() {
296
- this.execApplyDefaultValues();
297
- this.execApplyDefaultValRule();
298
- this.onGlobalEventFired('form-activated', this);
299
- },
300
- };
301
- </script>
1
+ <template>
2
+ <b-form v-if="formConfig && formConfig.sections" class="rb-doc-form" @submit.prevent>
3
+ <div
4
+ v-for="section in formConfig.sections"
5
+ :key="section.labelRu"
6
+ :class="className"
7
+ class="rb-form-section"
8
+ >
9
+ <b-row>
10
+ <b-col lg="12">
11
+ <h4>{{ getDisplayField(section) }}</h4>
12
+ </b-col>
13
+ <template v-for="column in section.columns">
14
+ <b-col :key="column.index" :lg="getColumnSize(section)" :sm="12">
15
+ <template v-for="field in column.fields">
16
+ {{ field.valueName }}
17
+ <b-form-row v-if="field.visible" :key="field.name">
18
+ <b-col lg="12">
19
+ <b-form-group
20
+ ref="inputContainer"
21
+ :data-field="field.name"
22
+ :invalid-feedback="validationState[`${field.name}__feedback`]"
23
+ :state="validationState[field.name]"
24
+ >
25
+ <component
26
+ v-bind:is="field.input.type"
27
+ :id="field.name"
28
+ :ref="field.ref? field.ref: field.name"
29
+ v-model="doc[field.name]"
30
+ :disabled="!editable || !field.editable"
31
+ :markForBackResolution="isResolvableField(field)"
32
+ :required="field.required"
33
+ :resolve-value="getResolveValue(field)"
34
+ :resolveFromObject="isResolvableField(field)"
35
+ :resolveObject.sync="doc[getResolveFieldName(field)]"
36
+ :state="validationState[field.name]"
37
+ v-bind="field.input.propsData"
38
+ @change="onEventFired('change', $event, field)"
39
+ @click="onEventFired('click', $event, field)"
40
+ @input="onEventFired('input', $event, field)"
41
+ @hook:created="onEventFired('created', $event, field)"
42
+ @hook:destroyed="onEventFired('destroyed', $event, field)"
43
+ @hook:activated="onEventFired('activated', $event, field)"
44
+ @hook:mounted="onEventFired('mounted', $event, field)"
45
+ ></component>
46
+ <template #label>
47
+ <span :title="getDisplayField(field)">{{ getDisplayField(field) }}</span>
48
+ <span v-if="showRequiredInLabel && field.required" class="text-danger"
49
+ >*</span
50
+ >
51
+ </template>
52
+ </b-form-group>
53
+ </b-col>
54
+ </b-form-row>
55
+ </template>
56
+ </b-col>
57
+ </template>
58
+ </b-row>
59
+ </div>
60
+ </b-form>
61
+ </template>
62
+
63
+ <script>
64
+ import Vue from 'vue';
65
+ import {UtFormConstructor} from '../utils/UtFormConstructor';
66
+ import typeOf from 'typeof';
67
+ import {UtFormConfig} from '@/utils/UtFormConfig';
68
+ import {UtArray} from "@/utils/UtArray";
69
+
70
+ export default {
71
+ name: 'DocForm',
72
+ props: {
73
+ formConfig: Object,
74
+ applyDefaultValues: {type: Boolean, default: true},
75
+ doc: {type: Object, default: () => ({})},
76
+ refSuffix: {type: String, default: 'Id'},
77
+ editable: {type: Boolean, default: true},
78
+ displayField: {type: String, default: 'labelRu'},
79
+ showRequiredInLabel: {type: Boolean, default: true},
80
+ className: {type: String, default: 'container'},
81
+ },
82
+ data() {
83
+ return {
84
+ validationState: {},
85
+ };
86
+ },
87
+ watch: {
88
+ formConfig() {
89
+ this.validationState = {};
90
+ this.execApplyDefaultValues();
91
+ this.execApplyDefaultValRule();
92
+ },
93
+ },
94
+ methods: {
95
+ getResolveValueName(field) {
96
+ if ((field.dict || field.ref) && !field.multiple) {
97
+ return field.name.substring(0, field.name.length - 2);
98
+ }
99
+ return field.name;
100
+ },
101
+ getResolveValue(field) {
102
+ return this.doc[this.getResolveValueName(field)]
103
+ ? this.doc[this.getResolveValueName(field)]
104
+ : null;
105
+ },
106
+ getDisplayField(value) {
107
+ if (!value[this.displayField]) {
108
+ return value.labelRu;
109
+ } else {
110
+ return value[this.displayField];
111
+ }
112
+ },
113
+ isResolvableField(field) {
114
+ return !!field.ref;
115
+ },
116
+ getResolveObject(field) {
117
+ if (this.isResolvableField(field)) {
118
+ let resolveFieldName = this.getResolveFieldName(field);
119
+ return field.multiple ? this.doc[field.name] : this.doc[resolveFieldName];
120
+ } else {
121
+ return null;
122
+ }
123
+ },
124
+ getResolveFieldName(field) {
125
+ let resolveFieldName = field?.name
126
+ if (resolveFieldName?.endsWith('Id')) {
127
+ resolveFieldName = field.name.substring(0, field.name.length - 2);
128
+ }
129
+ return resolveFieldName;
130
+ },
131
+ onEventFired(eventName, event, field) {
132
+ if (field.rules) {
133
+ field.rules.forEach((rule) => {
134
+ if (rule.event === eventName && rule.script) {
135
+ this.runRule(rule, {event, eventName});
136
+ }
137
+ });
138
+ }
139
+ },
140
+ onGlobalEventFired(eventName, event) {
141
+ let fields = UtFormConfig.getFields(this.formConfig);
142
+ fields.forEach((f) => {
143
+ if (f.rules) {
144
+ f.rules.forEach((r) => {
145
+ if (r.event === eventName) {
146
+ this.runRule(r, {event, eventName});
147
+ }
148
+ });
149
+ }
150
+ });
151
+ },
152
+ createRuleContext(additionalContext) {
153
+ return Object.assign(
154
+ {
155
+ form: this,
156
+ doc: this.doc,
157
+ ...additionalContext,
158
+ },
159
+ UtFormConstructor.getRuleContext(),
160
+ );
161
+ },
162
+ runRule(rule, context) {
163
+ UtFormConstructor.runRule(this.createRuleContext(context), rule.script);
164
+ },
165
+ isValueEmpty(fieldName) {
166
+ if (this.doc[fieldName] == null) {
167
+ return true;
168
+ }
169
+ if (Array.isArray(this.doc[fieldName]) && !this.doc[fieldName]?.length) {
170
+ return true;
171
+ }
172
+
173
+ if (typeOf(this.doc[fieldName] === 'string') && this.doc[fieldName] === '') {
174
+ return true;
175
+ }
176
+ return false;
177
+ },
178
+ isValueLessThanMax(fieldname, max) {
179
+ if (this.doc[fieldname] && max) {
180
+ return this.doc[fieldname]?.length > parseInt(max);
181
+ }
182
+ return false;
183
+ },
184
+ isValueLessThanMin(fieldname, min) {
185
+ if (this.doc[fieldname] && min) {
186
+ return parseInt(this.doc[fieldname]) < parseInt(min);
187
+ }
188
+
189
+ return false;
190
+ },
191
+ validate(callback = () => {
192
+ }) {
193
+ this.formConfig.sections.forEach((s) => {
194
+ s.columns.forEach((c) => {
195
+ c.fields.forEach((f) => {
196
+ let feedback = '';
197
+
198
+ if (f.required && this.isValueEmpty(f.name)) {
199
+ feedback += this.getDisplayField(f);
200
+ }
201
+
202
+ if (f.type === 'integer' && this.isValueLessThanMin(f.name, f.input.propsData.min)) {
203
+ feedback += f.input.propsData.min;
204
+ }
205
+ // TODO: Костыль так как на бэке нету типа memo
206
+ if (f.input.type === 'b-form-textarea' && this.isValueLessThanMax(f.name, f.input.propsData?.max)) {
207
+ feedback += `\nМаксимальное значение для этого поля ${f.input.propsData?.max}`;
208
+ }
209
+
210
+ if (f.required && f.input.propsData?.isInlineTableInput) {
211
+ const findErrors = this.$refs?.[f.name]?.[0]?.getIsDirty?.() ?? [];
212
+ const errors = UtArray.removeDuplicate(findErrors, 'field')?.map(f => f?.label).join(', ')
213
+ feedback = errors ? this.$t('validate.multiRequired', {field: errors}) : this.isValueEmpty(f.name) ? this.getDisplayField(f) : ''
214
+ }
215
+ // 🔥 Кастомная валидация для конкретного поля
216
+ if (typeof f.validate === 'function') {
217
+ console.log(f, this.doc);
218
+ const customError = f.validate(this.doc[f.name], f, this.doc, this.formConfig);
219
+ if (customError) {
220
+ feedback += `\n${customError}`;
221
+ }
222
+ }
223
+ if (feedback) {
224
+ Vue.set(this.validationState, f.name, false);
225
+ Vue.set(this.validationState, `${f.name}__feedback`, feedback);
226
+ } else {
227
+ Vue.set(this.validationState, f.name, null);
228
+ }
229
+ callback(feedback, this.$refs, f, this.doc)
230
+ this.onEventFired(
231
+ 'validate',
232
+ {
233
+ validationState: this.validationState,
234
+ doc: this.doc,
235
+ },
236
+ f,
237
+ );
238
+ });
239
+ });
240
+ });
241
+ for (let fieldName in this.validationState) {
242
+ if (this.validationState[fieldName] === false) {
243
+ return false;
244
+ }
245
+ }
246
+
247
+ return true;
248
+ },
249
+ getColumnSize(section) {
250
+ const MAX_COLUMN_SIZE = 12;
251
+ if (!section || !section.columnCount) {
252
+ return MAX_COLUMN_SIZE;
253
+ }
254
+
255
+ let colSize = Math.floor(MAX_COLUMN_SIZE / section.columnCount);
256
+ return colSize;
257
+ },
258
+ isNotUndefinedAndNull(value) {
259
+ return !(value === null || value === undefined)
260
+ },
261
+ execApplyDefaultValues() {
262
+ if (this.applyDefaultValues) {
263
+ this.formConfig.sections.forEach((r) => {
264
+ r.columns.forEach((c) => {
265
+ c.fields.forEach((f) => {
266
+ if (this.isNotUndefinedAndNull(f.defaultValue)) {
267
+ let defValue;
268
+ if (this.defaultValue && typeOf(f.defaultValue) === 'function') {
269
+ defValue = f.defaultValue();
270
+ } else {
271
+ defValue = f.defaultValue == null ? null : f.defaultValue;
272
+ }
273
+ this.$set(this.doc, f.name, (f.defaultValue = defValue));
274
+ }
275
+ });
276
+ });
277
+ });
278
+ }
279
+ },
280
+ execApplyDefaultValRule() {
281
+ this.formConfig.sections.forEach((el) => {
282
+ el.columns.forEach((c) => {
283
+ c.fields.forEach((f) => {
284
+ if (f.rules) {
285
+ if (!f.defaultValue) {
286
+ const rule = f.rules.find((rule) => rule.event === 'defaultValue');
287
+ if (rule && !this.doc[f.name]) {
288
+ this.$set(this.doc, f.name, (f.defaultValue = eval(rule.script)));
289
+ }
290
+ }
291
+ }
292
+ });
293
+ });
294
+ });
295
+ },
296
+ },
297
+ mounted() {
298
+ this.execApplyDefaultValues();
299
+ this.execApplyDefaultValRule();
300
+ this.onGlobalEventFired('form-mounted', this);
301
+ },
302
+ activated() {
303
+ this.execApplyDefaultValues();
304
+ this.execApplyDefaultValRule();
305
+ this.onGlobalEventFired('form-activated', this);
306
+ },
307
+ };
308
+ </script>