@webitel/ui-sdk 3.0.3 → 3.0.5
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/dist/ui-sdk.common.js +46 -43
- package/dist/ui-sdk.common.js.map +1 -1
- package/dist/ui-sdk.css +1 -1
- package/dist/ui-sdk.umd.js +49 -46
- package/dist/ui-sdk.umd.js.map +1 -1
- package/dist/ui-sdk.umd.min.js +1 -1
- package/dist/ui-sdk.umd.min.js.map +1 -1
- package/package.json +4 -1
- package/src/components/molecules/wt-datepicker/wt-datepicker.vue +2 -2
- package/src/components/molecules/wt-select/wt-select.vue +1 -1
- package/src/components/organisms/wt-table-column-select/wt-table-column-select.vue +3 -3
- package/src/locale/en/en.js +12 -0
- package/src/locale/ru/ru.js +12 -0
- package/src/locale/ua/ua.js +12 -0
- package/src/mixins/validationMixin/validationMixin.js +12 -12
- package/src/modules/AuditForm/components/__tests__/audit-form-question-read-wrapper.spec.js +14 -0
- package/src/modules/AuditForm/components/__tests__/audit-form-question-write-wrapper.spec.js +59 -0
- package/src/modules/AuditForm/components/__tests__/audit-form-question.spec.js +14 -0
- package/src/modules/AuditForm/components/__tests__/audit-form.spec.js +66 -0
- package/src/modules/AuditForm/components/audit-form-question-read-wrapper.vue +100 -0
- package/src/modules/AuditForm/components/audit-form-question-write-wrapper.vue +151 -0
- package/src/modules/AuditForm/components/audit-form-question.vue +102 -0
- package/src/modules/AuditForm/components/audit-form.vue +142 -0
- package/src/modules/AuditForm/components/questions/__tests__/audit-form-question-options.spec.js +46 -0
- package/src/modules/AuditForm/components/questions/__tests__/audit-form-question-score.spec.js +30 -0
- package/src/modules/AuditForm/components/questions/audit-form-question-options.vue +124 -0
- package/src/modules/AuditForm/components/questions/audit-form-question-score.vue +89 -0
- package/src/modules/AuditForm/composables/useDestroyableSortable.js +66 -0
- package/src/modules/AuditForm/schemas/AuditFormQuestionOptionsSchema.js +11 -0
- package/src/modules/AuditForm/schemas/AuditFormQuestionSchema.js +8 -0
- package/src/modules/AuditForm/schemas/AuditFormQuestionScoreSchema.js +6 -0
- package/src/scripts/__tests__/updateObject.spec.js +19 -0
- package/src/scripts/updateObject.js +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webitel/ui-sdk",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"serve-lib": "vue-cli-service serve",
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@vue/compat": "^3.2.47",
|
|
31
|
+
"@vuelidate/core": "^2.0.0",
|
|
32
|
+
"@vuelidate/validators": "^2.0.0",
|
|
31
33
|
"clipboard-copy": "^4.0.1",
|
|
32
34
|
"core-js": "^3.6.5",
|
|
33
35
|
"csv-stringify": "^5.5.3",
|
|
@@ -39,6 +41,7 @@
|
|
|
39
41
|
"jszip-utils": "^0.1.0",
|
|
40
42
|
"node-polyfill-webpack-plugin": "^1.1.4",
|
|
41
43
|
"plyr": "3.6.2",
|
|
44
|
+
"sortablejs": "^1.15.0",
|
|
42
45
|
"tiny-emitter": "^2.1.0",
|
|
43
46
|
"vue": "^3.2.47",
|
|
44
47
|
"vue-i18n": "^9.2.2",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
monday-first
|
|
18
18
|
@input="$emit('change', $event.getTime())"
|
|
19
19
|
>
|
|
20
|
-
<template slot
|
|
20
|
+
<template v-slot:afterDateInput>
|
|
21
21
|
<wt-icon
|
|
22
22
|
:color="disabled ? 'disabled' : 'default'"
|
|
23
23
|
class="wt-datepicker__calendar-icon"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
icon="arrow-down"
|
|
30
30
|
></wt-icon>
|
|
31
31
|
</template>
|
|
32
|
-
<template slot
|
|
32
|
+
<template v-slot:beforeCalendarHeader>
|
|
33
33
|
<wt-icon
|
|
34
34
|
class="wt-datepicker__month-arrow wt-datepicker__month-arrow--left"
|
|
35
35
|
icon="arrow-left"
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
class="wt-table-column-select__popup"
|
|
15
15
|
@close="close"
|
|
16
16
|
>
|
|
17
|
-
<template slot
|
|
17
|
+
<template v-slot:title>
|
|
18
18
|
{{ $t('webitelUI.tableColumnSelect.title') }}
|
|
19
19
|
</template>
|
|
20
|
-
<template slot
|
|
20
|
+
<template v-slot:main>
|
|
21
21
|
<ul class="wt-table-column-select__popup__list">
|
|
22
22
|
<li
|
|
23
23
|
v-for="(col, key) of changeableDraft"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
</li>
|
|
30
30
|
</ul>
|
|
31
31
|
</template>
|
|
32
|
-
<template slot
|
|
32
|
+
<template v-slot:actions>
|
|
33
33
|
<wt-button
|
|
34
34
|
@click="setShownColumns"
|
|
35
35
|
>{{ $t('reusable.add') }}
|
package/src/locale/en/en.js
CHANGED
|
@@ -46,6 +46,8 @@ export default {
|
|
|
46
46
|
downloadAll: 'Download all',
|
|
47
47
|
warning: 'Warning',
|
|
48
48
|
doNotSave: 'Don\'t save',
|
|
49
|
+
required: 'Required',
|
|
50
|
+
copy: 'Copy',
|
|
49
51
|
},
|
|
50
52
|
// yak zhe ya zaebalsya povtoriaty odni i ti sami slova!!!!
|
|
51
53
|
vocabulary: {
|
|
@@ -280,5 +282,15 @@ export default {
|
|
|
280
282
|
copy: 'Copy',
|
|
281
283
|
copied: 'Copied to clipboard!',
|
|
282
284
|
},
|
|
285
|
+
auditForm: {
|
|
286
|
+
question: 'Criteria',
|
|
287
|
+
option: 'Option | Options',
|
|
288
|
+
score: 'Score | Scores',
|
|
289
|
+
addQuestion: 'Add criteria',
|
|
290
|
+
type: {
|
|
291
|
+
options: 'Options',
|
|
292
|
+
score: 'Score',
|
|
293
|
+
},
|
|
294
|
+
},
|
|
283
295
|
},
|
|
284
296
|
};
|
package/src/locale/ru/ru.js
CHANGED
|
@@ -45,6 +45,8 @@ export default {
|
|
|
45
45
|
downloadAll: 'Скачать всё',
|
|
46
46
|
warning: 'Предупреждение',
|
|
47
47
|
doNotSave: 'Не сохранять',
|
|
48
|
+
required: 'Обязательный',
|
|
49
|
+
copy: 'Скопировать',
|
|
48
50
|
},
|
|
49
51
|
vocabulary: {
|
|
50
52
|
language: 'Язык',
|
|
@@ -276,5 +278,15 @@ export default {
|
|
|
276
278
|
copy: 'Копировать',
|
|
277
279
|
copied: 'Скопировано!',
|
|
278
280
|
},
|
|
281
|
+
auditForm: {
|
|
282
|
+
question: 'Критерий',
|
|
283
|
+
option: 'Вариант | Варианты',
|
|
284
|
+
score: 'Бал | Балы',
|
|
285
|
+
addQuestion: 'Добавить критерий',
|
|
286
|
+
type: {
|
|
287
|
+
options: 'Критерии',
|
|
288
|
+
score: 'Бал',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
279
291
|
},
|
|
280
292
|
};
|
package/src/locale/ua/ua.js
CHANGED
|
@@ -46,6 +46,8 @@ export default {
|
|
|
46
46
|
downloadAll: 'Завантажити все',
|
|
47
47
|
warning: 'Попередження',
|
|
48
48
|
doNotSave: 'Не зберігати',
|
|
49
|
+
required: 'Обов\'язковий',
|
|
50
|
+
copy: 'Скопіювати',
|
|
49
51
|
},
|
|
50
52
|
vocabulary: {
|
|
51
53
|
language: 'Мова',
|
|
@@ -276,5 +278,15 @@ export default {
|
|
|
276
278
|
copy: 'Копіювати',
|
|
277
279
|
copied: 'Скопійовано!',
|
|
278
280
|
},
|
|
281
|
+
auditForm: {
|
|
282
|
+
question: 'Критерій',
|
|
283
|
+
option: 'Варіант | Варіанти',
|
|
284
|
+
score: 'Бал | Бали',
|
|
285
|
+
addQuestion: 'Додати критерій',
|
|
286
|
+
type: {
|
|
287
|
+
options: 'Критерії',
|
|
288
|
+
score: 'Бал',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
279
291
|
},
|
|
280
292
|
};
|
|
@@ -19,21 +19,21 @@ export default {
|
|
|
19
19
|
validationText() {
|
|
20
20
|
let validationText = '';
|
|
21
21
|
if (this.isValidation && this.invalid) {
|
|
22
|
-
if (this.v.required
|
|
23
|
-
else if (this.v.numeric
|
|
24
|
-
else if (this.v.email
|
|
25
|
-
else if (this.v.gatewayHostValidator
|
|
26
|
-
else if (this.v.ipValidator
|
|
27
|
-
else if (this.v.macValidator
|
|
28
|
-
else if (this.v.minValue
|
|
29
|
-
else if (this.v.maxValue
|
|
30
|
-
else if (this.v.sipAccountValidator
|
|
31
|
-
else if (this.v.minLength
|
|
32
|
-
else if (this.v.url
|
|
22
|
+
if (this.v.required.$invalid) validationText = this.$t('validation.required');
|
|
23
|
+
else if (this.v.numeric.$invalid) validationText = this.$t('validation.numeric');
|
|
24
|
+
else if (this.v.email.$invalid) validationText = this.$t('validation.email');
|
|
25
|
+
else if (this.v.gatewayHostValidator.$invalid) validationText = this.$t('validation.gatewayHostValidator');
|
|
26
|
+
else if (this.v.ipValidator.$invalid) validationText = this.$t('validation.ipValidator');
|
|
27
|
+
else if (this.v.macValidator.$invalid) validationText = this.$t('validation.macValidator');
|
|
28
|
+
else if (this.v.minValue.$invalid) validationText = `${this.$t('validation.minValue')} ${this.v.$params.minValue.min}`;
|
|
29
|
+
else if (this.v.maxValue.$invalid) validationText = `${this.$t('validation.maxValue')} ${this.v.$params.maxValue.max}`;
|
|
30
|
+
else if (this.v.sipAccountValidator.$invalid) validationText = this.$t('validation.sipAccountValidator');
|
|
31
|
+
else if (this.v.minLength.$invalid) validationText = `${this.$t('validation.minLength')} ${this.v.$params.minLength.min}`;
|
|
32
|
+
else if (this.v.url.$invalid) validationText = `${this.$t('validation.url')}`;
|
|
33
33
|
}
|
|
34
34
|
// eslint-disable-next-line no-restricted-syntax
|
|
35
35
|
for (const { name, text } of this.customValidators) {
|
|
36
|
-
if (this.v[name]
|
|
36
|
+
if (this.v[name].$invalid) validationText = text;
|
|
37
37
|
}
|
|
38
38
|
return validationText;
|
|
39
39
|
},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import AuditFormQuestionReadWrapper from '../audit-form-question-read-wrapper.vue';
|
|
3
|
+
|
|
4
|
+
describe('AuditFormQuestionReadWrapper', () => {
|
|
5
|
+
it('renders a component', () => {
|
|
6
|
+
const wrapper = shallowMount(AuditFormQuestionReadWrapper, {
|
|
7
|
+
props: {
|
|
8
|
+
question: {},
|
|
9
|
+
result: {},
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
expect(wrapper.isVisible()).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import {
|
|
3
|
+
generateQuestionOptionsSchema
|
|
4
|
+
} from '../../schemas/AuditFormQuestionOptionsSchema';
|
|
5
|
+
import AuditFormQuestionWriteWrapper from '../audit-form-question-write-wrapper.vue';
|
|
6
|
+
import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema';
|
|
7
|
+
import { generateQuestionScoreSchema } from '../../schemas/AuditFormQuestionScoreSchema';
|
|
8
|
+
|
|
9
|
+
const v = { question: {} };
|
|
10
|
+
|
|
11
|
+
describe('AuditFormQuestionWriteWrapper', () => {
|
|
12
|
+
it('renders a component', () => {
|
|
13
|
+
const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
|
|
14
|
+
props: {
|
|
15
|
+
question: {},
|
|
16
|
+
v,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
expect(wrapper.isVisible()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('correctly changes question', () => {
|
|
22
|
+
const question = generateQuestionSchema();
|
|
23
|
+
const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
|
|
24
|
+
props: {
|
|
25
|
+
question,
|
|
26
|
+
v,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
wrapper.findComponent({ name: 'wt-switcher' }).vm.$emit('change', !question.required);
|
|
30
|
+
expect(wrapper.emitted()['change:question'][0][0].required)
|
|
31
|
+
.toBe(!question.required);
|
|
32
|
+
});
|
|
33
|
+
it('correctly changes question type to Score', () => {
|
|
34
|
+
const question = {};
|
|
35
|
+
const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
|
|
36
|
+
props: {
|
|
37
|
+
question,
|
|
38
|
+
v,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
wrapper.find('.audit-form-question-write-content-question')
|
|
42
|
+
.findComponent({ name: 'wt-select' }).vm.$emit('input', { value: 'score' });
|
|
43
|
+
expect(wrapper.emitted()['change:question'][0][0])
|
|
44
|
+
.toEqual(generateQuestionScoreSchema());
|
|
45
|
+
});
|
|
46
|
+
it('correctly changes question type to Options', () => {
|
|
47
|
+
const question = {};
|
|
48
|
+
const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
|
|
49
|
+
props: {
|
|
50
|
+
question,
|
|
51
|
+
v,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
wrapper.find('.audit-form-question-write-content-question')
|
|
55
|
+
.findComponent({ name: 'wt-select' }).vm.$emit('input', { value: 'options' });
|
|
56
|
+
expect(wrapper.emitted()['change:question'][0][0])
|
|
57
|
+
.toEqual(generateQuestionOptionsSchema());
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import AuditFormQuestion from '../audit-form-question.vue';
|
|
3
|
+
|
|
4
|
+
describe('AuditFormQuestion', () => {
|
|
5
|
+
it('renders a component', () => {
|
|
6
|
+
const wrapper = shallowMount(AuditFormQuestion, {
|
|
7
|
+
props: {
|
|
8
|
+
question: {},
|
|
9
|
+
result: {},
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
expect(wrapper.isVisible()).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import AuditForm from '../audit-form.vue';
|
|
3
|
+
import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
useDestroyableSortable,
|
|
7
|
+
} from '../../composables/useDestroyableSortable';
|
|
8
|
+
|
|
9
|
+
jest.mock('../../composables/useDestroyableSortable');
|
|
10
|
+
|
|
11
|
+
useDestroyableSortable.mockImplementation(() => ({}));
|
|
12
|
+
|
|
13
|
+
describe('AuditForm', () => {
|
|
14
|
+
it('renders a component', () => {
|
|
15
|
+
const wrapper = shallowMount(AuditForm, {
|
|
16
|
+
props: {
|
|
17
|
+
mode: '',
|
|
18
|
+
questions: [],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
expect(wrapper.isVisible()).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
it('add question button triggers update question event', () => {
|
|
24
|
+
const wrapper = shallowMount(AuditForm, {
|
|
25
|
+
props: {
|
|
26
|
+
mode: 'create',
|
|
27
|
+
questions: [],
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
wrapper.findComponent('.audit-form__add-button').vm.$emit('click');
|
|
31
|
+
expect(wrapper.emitted()['update:questions'][0][0])
|
|
32
|
+
.toEqual([generateQuestionSchema()]);
|
|
33
|
+
});
|
|
34
|
+
it('delete event from child question emits update without passed question', () => {
|
|
35
|
+
const wrapper = shallowMount(AuditForm, {
|
|
36
|
+
props: {
|
|
37
|
+
mode: 'create',
|
|
38
|
+
questions: [generateQuestionSchema()],
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
wrapper.findComponent({ name: 'audit-form-question' }).vm.$emit('delete', { key: 0 });
|
|
42
|
+
expect(wrapper.emitted()['update:questions'][0][0])
|
|
43
|
+
.toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
it('copy event from child question emits update with duplicated questions', () => {
|
|
46
|
+
const question = generateQuestionSchema();
|
|
47
|
+
const wrapper = shallowMount(AuditForm, {
|
|
48
|
+
props: {
|
|
49
|
+
mode: 'create',
|
|
50
|
+
questions: [question],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
wrapper.findComponent({ name: 'audit-form-question' }).vm.$emit('copy', { question, key: 0 });
|
|
54
|
+
expect(wrapper.emitted()['update:questions'][0][0])
|
|
55
|
+
.toEqual([question, question]);
|
|
56
|
+
});
|
|
57
|
+
it('initializes result depending on passed questions', () => {
|
|
58
|
+
const wrapper = shallowMount(AuditForm, {
|
|
59
|
+
props: {
|
|
60
|
+
mode: 'fill',
|
|
61
|
+
questions: [generateQuestionSchema(), generateQuestionSchema(), generateQuestionSchema()],
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
expect(wrapper.emitted()['update:result'][0][0]).toEqual([null, null, null]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<article
|
|
3
|
+
class="audit-form-question-read"
|
|
4
|
+
:class="{
|
|
5
|
+
'audit-form-question-read--filled': result && result.score != null,
|
|
6
|
+
}"
|
|
7
|
+
@keyup.enter="emit('activate')"
|
|
8
|
+
@click="emit('activate')"
|
|
9
|
+
>
|
|
10
|
+
<header class="audit-form-question-read-header">
|
|
11
|
+
<p
|
|
12
|
+
class="audit-form-question-read-text"
|
|
13
|
+
:class="{
|
|
14
|
+
'audit-form-question-read-text--required': question.required,
|
|
15
|
+
}"
|
|
16
|
+
>{{ question.text }}</p>
|
|
17
|
+
<wt-icon
|
|
18
|
+
class="audit-form-question-read__drag-icon"
|
|
19
|
+
v-if="!disableDragging"
|
|
20
|
+
icon="move"
|
|
21
|
+
color="secondary"
|
|
22
|
+
></wt-icon>
|
|
23
|
+
</header>
|
|
24
|
+
<section class="audit-form-question-read-content">
|
|
25
|
+
<component
|
|
26
|
+
:is="QuestionTypeComponent"
|
|
27
|
+
:question="question"
|
|
28
|
+
:result="result"
|
|
29
|
+
mode="read"
|
|
30
|
+
@change:result="emit('change:result', $event)"
|
|
31
|
+
></component>
|
|
32
|
+
</section>
|
|
33
|
+
</article>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
import { computed } from 'vue';
|
|
38
|
+
import AuditFormQuestionOptions from './questions/audit-form-question-options.vue';
|
|
39
|
+
import AuditFormQuestionScore from './questions/audit-form-question-score.vue';
|
|
40
|
+
import WtIcon from '../../../components/atoms/wt-icon/wt-icon.vue';
|
|
41
|
+
|
|
42
|
+
const props = defineProps({
|
|
43
|
+
question: {
|
|
44
|
+
type: Object,
|
|
45
|
+
required: true,
|
|
46
|
+
},
|
|
47
|
+
result: {
|
|
48
|
+
type: Object,
|
|
49
|
+
required: true,
|
|
50
|
+
},
|
|
51
|
+
disableDragging: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const emit = defineEmits([
|
|
58
|
+
'change:result',
|
|
59
|
+
'activate',
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const QuestionTypeComponent = computed(() => {
|
|
63
|
+
if (props.question.type === 'options') return AuditFormQuestionOptions;
|
|
64
|
+
if (props.question.type === 'score') return AuditFormQuestionScore;
|
|
65
|
+
return null;
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<style lang="scss" scoped>
|
|
70
|
+
.audit-form-question-read {
|
|
71
|
+
position: relative;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: var(--spacing-sm);
|
|
75
|
+
|
|
76
|
+
&--filled {
|
|
77
|
+
background: var(--secondary-color-50);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.audit-form-question-read__drag-icon {
|
|
82
|
+
position: absolute;
|
|
83
|
+
top: 0;
|
|
84
|
+
left: 50%;
|
|
85
|
+
transform: translateX(-50%);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.audit-form-question-read-header {
|
|
89
|
+
margin-bottom: var(--spacing-xs);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.audit-form-question-read-text {
|
|
93
|
+
&--required {
|
|
94
|
+
&:after {
|
|
95
|
+
content: '*';
|
|
96
|
+
color: var(--false-color);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<article class="audit-form-question-write">
|
|
3
|
+
<header class="audit-form-question-write-header">
|
|
4
|
+
<wt-switcher
|
|
5
|
+
:value="question.required"
|
|
6
|
+
:label="$t('reusable.required')"
|
|
7
|
+
@change="updateQuestion({ path: 'required', value: $event })"
|
|
8
|
+
></wt-switcher>
|
|
9
|
+
<div class="audit-form-question-write-header__actions">
|
|
10
|
+
<wt-tooltip>
|
|
11
|
+
<template v-slot:activator>
|
|
12
|
+
<wt-icon-btn
|
|
13
|
+
icon="copy"
|
|
14
|
+
@click="emit('copy')"
|
|
15
|
+
></wt-icon-btn>
|
|
16
|
+
</template>
|
|
17
|
+
{{ $t('reusable.copy') }}
|
|
18
|
+
</wt-tooltip>
|
|
19
|
+
<wt-tooltip>
|
|
20
|
+
<template v-slot:activator>
|
|
21
|
+
<wt-icon-btn
|
|
22
|
+
icon="bucket"
|
|
23
|
+
:disabled="disableDelete"
|
|
24
|
+
@click="emit('delete')"
|
|
25
|
+
></wt-icon-btn>
|
|
26
|
+
</template>
|
|
27
|
+
{{ $t('reusable.delete') }}
|
|
28
|
+
</wt-tooltip>
|
|
29
|
+
</div>
|
|
30
|
+
</header>
|
|
31
|
+
<section class="audit-form-question-write-content">
|
|
32
|
+
<div class="audit-form-question-write-content-question">
|
|
33
|
+
<wt-input
|
|
34
|
+
:value="question.text"
|
|
35
|
+
:label="$t('webitelUI.auditForm.question')"
|
|
36
|
+
:v="v.question.text"
|
|
37
|
+
required
|
|
38
|
+
@input="updateQuestion({ path: 'text', value: $event })"
|
|
39
|
+
></wt-input>
|
|
40
|
+
<wt-select
|
|
41
|
+
:value="prettifiedQuestionType"
|
|
42
|
+
:options="QuestionType"
|
|
43
|
+
track-by="value"
|
|
44
|
+
:clearable="false"
|
|
45
|
+
:label="$t('vocabulary.type')"
|
|
46
|
+
@input="handleQuestionTypeChange($event.value)"
|
|
47
|
+
></wt-select>
|
|
48
|
+
</div>
|
|
49
|
+
<component
|
|
50
|
+
:is="QuestionTypeComponent"
|
|
51
|
+
:question="question"
|
|
52
|
+
mode="write"
|
|
53
|
+
@change:question="emit('change:question', $event)"
|
|
54
|
+
></component>
|
|
55
|
+
</section>
|
|
56
|
+
</article>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script setup>
|
|
60
|
+
import set from 'lodash/set';
|
|
61
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
62
|
+
import { computed } from 'vue';
|
|
63
|
+
import WtTooltip from '../../../components/atoms/wt-tooltip/wt-tooltip.vue';
|
|
64
|
+
import WtSwitcher from '../../../components/molecules/wt-switcher/wt-switcher.vue';
|
|
65
|
+
import WtIconBtn from '../../../components/molecules/wt-icon-btn/wt-icon-btn.vue';
|
|
66
|
+
import WtInput from '../../../components/molecules/wt-input/wt-input.vue';
|
|
67
|
+
import WtSelect from '../../../components/molecules/wt-select/wt-select.vue';
|
|
68
|
+
|
|
69
|
+
import AuditFormQuestionOptions from './questions/audit-form-question-options.vue';
|
|
70
|
+
import AuditFormQuestionScore from './questions/audit-form-question-score.vue';
|
|
71
|
+
|
|
72
|
+
import { generateQuestionScoreSchema } from '../schemas/AuditFormQuestionScoreSchema';
|
|
73
|
+
import { generateQuestionOptionsSchema } from '../schemas/AuditFormQuestionOptionsSchema';
|
|
74
|
+
|
|
75
|
+
const props = defineProps({
|
|
76
|
+
question: {
|
|
77
|
+
type: Object,
|
|
78
|
+
required: true,
|
|
79
|
+
},
|
|
80
|
+
disableDelete: {
|
|
81
|
+
type: Boolean,
|
|
82
|
+
default: true,
|
|
83
|
+
},
|
|
84
|
+
v: {
|
|
85
|
+
type: Object,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const emit = defineEmits([
|
|
90
|
+
'change:question',
|
|
91
|
+
'copy',
|
|
92
|
+
'delete',
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const QuestionType = [
|
|
96
|
+
{ value: 'options', locale: 'webitelUI.auditForm.type.options' },
|
|
97
|
+
{ value: 'score', locale: 'webitelUI.auditForm.type.score' },
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const prettifiedQuestionType = computed(() => QuestionType.find(({ value }) => value === props.question.type));
|
|
101
|
+
|
|
102
|
+
const QuestionTypeComponent = computed(() => {
|
|
103
|
+
if (props.question.type === 'options') return AuditFormQuestionOptions;
|
|
104
|
+
if (props.question.type === 'score') return AuditFormQuestionScore;
|
|
105
|
+
return null;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
function updateQuestion({ path, value }) {
|
|
109
|
+
const question = set(cloneDeep(props.question), path, value);
|
|
110
|
+
emit('change:question', question);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function handleQuestionTypeChange(type) {
|
|
114
|
+
const question = cloneDeep(props.question);
|
|
115
|
+
if (type === 'options') {
|
|
116
|
+
Object.assign(question, generateQuestionOptionsSchema());
|
|
117
|
+
} else if (type === 'score') {
|
|
118
|
+
Object.assign(question, generateQuestionScoreSchema());
|
|
119
|
+
}
|
|
120
|
+
emit('change:question', question);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<style lang="scss" scoped>
|
|
126
|
+
.audit-form-question.audit-form-question-write {
|
|
127
|
+
display: flex;
|
|
128
|
+
flex-direction: column;
|
|
129
|
+
gap: var(--spacing-sm);
|
|
130
|
+
box-shadow: var(--elevation-3);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.audit-form-question-write-header {
|
|
134
|
+
display: flex;
|
|
135
|
+
justify-content: space-between;
|
|
136
|
+
align-items: center;
|
|
137
|
+
|
|
138
|
+
&__actions {
|
|
139
|
+
display: flex;
|
|
140
|
+
gap: var(--spacing-sm);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.audit-form-question-write-content-question {
|
|
145
|
+
display: grid;
|
|
146
|
+
grid-template-columns: 3fr 1fr;
|
|
147
|
+
gap: var(--spacing-sm);
|
|
148
|
+
margin-right: calc(24px + var(--spacing-sm)); // delete icon action for type "options"
|
|
149
|
+
margin-bottom: var(--spacing-sm);
|
|
150
|
+
}
|
|
151
|
+
</style>
|