@webitel/ui-sdk 25.6.6 → 25.6.7
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/CHANGELOG.md +6 -0
- package/dist/types/enums/WtObject/WtObject.d.ts +2 -0
- package/dist/types/modules/AuditForm/components/audit-form-question-read-wrapper.vue.d.ts +16 -15
- package/dist/types/modules/AuditForm/components/audit-form-question.vue.d.ts +20 -15
- package/dist/types/modules/AuditForm/components/audit-form.vue.d.ts +33 -13
- package/dist/types/modules/AuditForm/components/form/form-footer/audit-form-footer.vue.d.ts +13 -0
- package/dist/types/modules/AuditForm/components/form-answers/answer-editing-info/audit-form-answer-editing-info.vue.d.ts +9 -0
- package/dist/types/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options-write-row.vue.d.ts +1 -1
- package/dist/types/modules/AuditForm/components/form-questions/options/audit-form-question-options.vue.d.ts +19 -0
- package/dist/types/modules/AuditForm/components/{questions → form-questions}/score/audit-form-question-score.vue.d.ts +1 -1
- package/dist/types/modules/Userinfo/v2/enums/ScopeClass/ScopeClass.d.ts +2 -0
- package/package.json +1 -1
- package/src/enums/WtObject/WtObject.ts +2 -0
- package/src/locale/en/en.js +4 -0
- package/src/locale/ru/ru.js +4 -0
- package/src/locale/ua/ua.js +4 -0
- package/src/modules/AuditForm/components/audit-form-question-read-wrapper.vue +64 -37
- package/src/modules/AuditForm/components/audit-form-question-write-wrapper.vue +2 -2
- package/src/modules/AuditForm/components/audit-form-question.vue +43 -43
- package/src/modules/AuditForm/components/audit-form.vue +75 -54
- package/src/modules/AuditForm/components/form/form-footer/audit-form-footer.vue +65 -0
- package/src/modules/AuditForm/components/form-answers/answer-editing-info/audit-form-answer-editing-info.vue +106 -0
- package/src/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options-write-row.vue +1 -1
- package/src/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options.vue +32 -26
- package/src/modules/Userinfo/v2/enums/ScopeClass/ScopeClass.ts +2 -0
- package/src/modules/Userinfo/v2/mappings/mappings.ts +2 -0
- package/dist/types/modules/AuditForm/components/questions/options/audit-form-question-options.vue.d.ts +0 -12
- /package/src/modules/AuditForm/components/{questions → form-questions}/options/__tests__/audit-form-question-options-write-row.spec.js +0 -0
- /package/src/modules/AuditForm/components/{questions → form-questions}/options/__tests__/audit-form-question-options.spec.js +0 -0
- /package/src/modules/AuditForm/components/{questions → form-questions}/score/__tests__/audit-form-question-score.spec.js +0 -0
- /package/src/modules/AuditForm/components/{questions → form-questions}/score/audit-form-question-score.vue +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [v25.6.6] - 2025-05-07
|
|
2
|
+
### :bug: Bug Fixes
|
|
3
|
+
- [`0c370cd`](https://github.com/webitel/webitel-ui-sdk/commit/0c370cdfe2543d6fc41c38650bbd4455b263b942) - fixed search for get sys type records list [WTEL-6851](https://webitel.atlassian.net/browse/WTEL-6851) *(commit by [@plnnsimon](https://github.com/plnnsimon))*
|
|
4
|
+
|
|
5
|
+
|
|
1
6
|
## [v25.6.5] - 2025-05-05
|
|
2
7
|
### :bug: Bug Fixes
|
|
3
8
|
- [`39d99ac`](https://github.com/webitel/webitel-ui-sdk/commit/39d99ac3629658df76536b9d8e6026cb5747d9e1) - fixed styles for select tags line-height [WTEL-6360](https://webitel.atlassian.net/browse/WTEL-6360) *(commit by [@plnnsimon](https://github.com/plnnsimon))*
|
|
@@ -2086,3 +2091,4 @@
|
|
|
2086
2091
|
[v25.6.3]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.2...v25.6.3
|
|
2087
2092
|
[v25.6.4]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.3...v25.6.4
|
|
2088
2093
|
[v25.6.5]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.4...v25.6.5
|
|
2094
|
+
[v25.6.6]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.5...v25.6.6
|
|
@@ -56,5 +56,7 @@ export declare const WtObject: {
|
|
|
56
56
|
readonly Status: "status";
|
|
57
57
|
readonly Source: "source";
|
|
58
58
|
readonly CustomLookup: "customLookup";
|
|
59
|
+
readonly AuditForm: "auditForm";
|
|
60
|
+
readonly AuditRating: "auditRating";
|
|
59
61
|
};
|
|
60
62
|
export type WtObject = (typeof WtObject)[keyof typeof WtObject];
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
question:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { EngineQuestion, EngineQuestionAnswer } from 'webitel-sdk';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
question: EngineQuestion;
|
|
4
|
+
disableDragging?: boolean;
|
|
5
|
+
first?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
8
|
+
'answer'?: EngineQuestionAnswer | null;
|
|
9
|
+
};
|
|
10
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
"update:answer": (value: EngineQuestionAnswer) => any;
|
|
12
|
+
activate: () => any;
|
|
13
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
14
|
+
"onUpdate:answer"?: (value: EngineQuestionAnswer) => any;
|
|
15
|
+
onActivate?: () => any;
|
|
16
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
17
|
export default _default;
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import { EngineQuestion, EngineQuestionAnswer } from "webitel-sdk";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
question: EngineQuestion;
|
|
4
|
+
answer: EngineQuestionAnswer | null;
|
|
5
|
+
first?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare function activateQuestion(): void;
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {
|
|
2
9
|
activateQuestion: typeof activateQuestion;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
10
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
delete: () => any;
|
|
12
|
+
copy: () => any;
|
|
13
|
+
"update:question": (args_0: unknown) => any;
|
|
14
|
+
"update:answer": (args_0: unknown) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
16
|
+
onDelete?: () => any;
|
|
17
|
+
onCopy?: () => any;
|
|
18
|
+
"onUpdate:question"?: (args_0: unknown) => any;
|
|
19
|
+
"onUpdate:answer"?: (args_0: unknown) => any;
|
|
20
|
+
}>, {
|
|
6
21
|
first: boolean;
|
|
7
|
-
|
|
8
|
-
result?: Record<string, any>;
|
|
9
|
-
$props: {
|
|
10
|
-
readonly question?: Record<string, any>;
|
|
11
|
-
readonly readonly?: boolean;
|
|
12
|
-
readonly first?: boolean;
|
|
13
|
-
readonly mode?: string;
|
|
14
|
-
readonly result?: Record<string, any>;
|
|
15
|
-
};
|
|
16
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
22
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
23
|
export default _default;
|
|
18
|
-
declare function activateQuestion(): void;
|
|
@@ -1,14 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
readonly:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { EngineQuestion, EngineQuestionAnswer } from 'webitel-sdk';
|
|
2
|
+
declare const AuditFormMode: {
|
|
3
|
+
readonly Create: "create";
|
|
4
|
+
readonly Fill: "fill";
|
|
5
|
+
};
|
|
6
|
+
type AuditFormMode = typeof AuditFormMode[keyof typeof AuditFormMode];
|
|
7
|
+
type __VLS_Props = {
|
|
8
|
+
mode: AuditFormMode;
|
|
9
|
+
readonly?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
12
|
+
'answers'?: EngineQuestionAnswer[];
|
|
13
|
+
/**
|
|
14
|
+
* todo: rename to questionsModel and use instead of 'update:questions' event
|
|
15
|
+
*/
|
|
16
|
+
'questions'?: EngineQuestion[];
|
|
17
|
+
'resultComment'?: string;
|
|
18
|
+
};
|
|
19
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
+
"update:questions": (...args: any[]) => void;
|
|
21
|
+
"update:validation": (...args: any[]) => void;
|
|
22
|
+
"save:evaluation": (...args: any[]) => void;
|
|
23
|
+
"cancel:evaluation": (...args: any[]) => void;
|
|
24
|
+
"update:answers": (value: EngineQuestionAnswer[]) => void;
|
|
25
|
+
"update:resultComment": (value: string) => void;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
27
|
+
"onUpdate:questions"?: (...args: any[]) => any;
|
|
28
|
+
"onUpdate:validation"?: (...args: any[]) => any;
|
|
29
|
+
"onSave:evaluation"?: (...args: any[]) => any;
|
|
30
|
+
"onCancel:evaluation"?: (...args: any[]) => any;
|
|
31
|
+
"onUpdate:answers"?: (value: EngineQuestionAnswer[]) => any;
|
|
32
|
+
"onUpdate:resultComment"?: (value: string) => any;
|
|
33
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
34
|
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
invalid: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"fill:save": () => any;
|
|
6
|
+
"fill:cancel": () => any;
|
|
7
|
+
"create:add": () => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
|
+
"onFill:save"?: () => any;
|
|
10
|
+
"onFill:cancel"?: () => any;
|
|
11
|
+
"onCreate:add"?: () => any;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EngineQuestionAnswer } from "webitel-sdk";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
answer: EngineQuestionAnswer;
|
|
4
|
+
collapsible?: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
7
|
+
collapsible: boolean;
|
|
8
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EngineQuestion, EngineQuestionAnswer } from "webitel-sdk";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
/**
|
|
4
|
+
* question mode, NOT audit form mode
|
|
5
|
+
*/
|
|
6
|
+
mode: 'read' | 'write';
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
9
|
+
'question'?: EngineQuestion;
|
|
10
|
+
'answer'?: EngineQuestionAnswer | null;
|
|
11
|
+
};
|
|
12
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
+
"update:question": (value: EngineQuestion) => any;
|
|
14
|
+
"update:answer": (value: EngineQuestionAnswer) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
16
|
+
"onUpdate:question"?: (value: EngineQuestion) => any;
|
|
17
|
+
"onUpdate:answer"?: (value: EngineQuestionAnswer) => any;
|
|
18
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
$emit: (event: "change:
|
|
2
|
+
$emit: (event: "change:question" | "change:result", ...args: any[]) => void;
|
|
3
3
|
mode: string;
|
|
4
4
|
question: Record<string, any>;
|
|
5
5
|
result?: Record<string, any>;
|
|
@@ -41,5 +41,7 @@ export declare const ScopeClass: {
|
|
|
41
41
|
readonly ChatBots: "chat_bots";
|
|
42
42
|
readonly Cases: "cases";
|
|
43
43
|
readonly CaseComments: "case_comments";
|
|
44
|
+
readonly AuditForm: "cc_audit_form";
|
|
45
|
+
readonly AuditRating: "rating";
|
|
44
46
|
};
|
|
45
47
|
export type ScopeClass = (typeof ScopeClass)[keyof typeof ScopeClass];
|
package/package.json
CHANGED
package/src/locale/en/en.js
CHANGED
|
@@ -23,6 +23,7 @@ import { snakeToCamel } from '../../scripts';
|
|
|
23
23
|
export default {
|
|
24
24
|
// describes reusable buttons, actions, default titles, and other ui elements
|
|
25
25
|
reusable: {
|
|
26
|
+
comment: 'Comment',
|
|
26
27
|
replace: 'Replace',
|
|
27
28
|
download: 'Download',
|
|
28
29
|
history: 'History',
|
|
@@ -88,6 +89,9 @@ export default {
|
|
|
88
89
|
unassigned: 'Unassigned',
|
|
89
90
|
showUnassigned: 'Show unassigned',
|
|
90
91
|
group: 'Group',
|
|
92
|
+
updatedBy: (/*{ named }*/) => {
|
|
93
|
+
return 'Edited';
|
|
94
|
+
},
|
|
91
95
|
},
|
|
92
96
|
// yak zhe ya zaebalsya povtoriaty odni i ti sami slova!!!!
|
|
93
97
|
vocabulary: {
|
package/src/locale/ru/ru.js
CHANGED
|
@@ -23,6 +23,7 @@ import { snakeToCamel } from '../../scripts';
|
|
|
23
23
|
export default {
|
|
24
24
|
// describes reusable buttons, actions, default titles, and other ui elements
|
|
25
25
|
reusable: {
|
|
26
|
+
comment: 'Коментарий',
|
|
26
27
|
replace: 'Заменить',
|
|
27
28
|
download: 'Скачать',
|
|
28
29
|
history: 'История',
|
|
@@ -88,6 +89,9 @@ export default {
|
|
|
88
89
|
unassigned: 'Неназначенные',
|
|
89
90
|
showUnassigned: 'Показать неназначенные',
|
|
90
91
|
group: 'Группа',
|
|
92
|
+
updatedBy: (/*{ named }*/) => {
|
|
93
|
+
return 'Редактировано';
|
|
94
|
+
},
|
|
91
95
|
},
|
|
92
96
|
vocabulary: {
|
|
93
97
|
apply: 'Применить',
|
package/src/locale/ua/ua.js
CHANGED
|
@@ -23,6 +23,7 @@ import { snakeToCamel } from '../../scripts';
|
|
|
23
23
|
export default {
|
|
24
24
|
// describes reusable buttons, actions, default titles, and other ui elements
|
|
25
25
|
reusable: {
|
|
26
|
+
comment: 'Коментар',
|
|
26
27
|
replace: 'Замінити',
|
|
27
28
|
download: 'Завантажити',
|
|
28
29
|
history: 'Історія',
|
|
@@ -89,6 +90,9 @@ export default {
|
|
|
89
90
|
unassigned: 'Непризначені',
|
|
90
91
|
showUnassigned: 'Показати непризначені',
|
|
91
92
|
group: 'Група',
|
|
93
|
+
updatedBy: (/*{ named }*/) => {
|
|
94
|
+
return 'Редаговано';
|
|
95
|
+
},
|
|
92
96
|
},
|
|
93
97
|
vocabulary: {
|
|
94
98
|
apply: 'Застосувати',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<article
|
|
3
3
|
:class="{
|
|
4
|
-
'audit-form-question-read--filled':
|
|
4
|
+
'audit-form-question-read--filled': isAnswer && answerModel.score != null,
|
|
5
5
|
'audit-form-question-read--readonly': readonly,
|
|
6
6
|
}"
|
|
7
7
|
class="audit-form-question-read"
|
|
@@ -26,55 +26,61 @@
|
|
|
26
26
|
<section class="audit-form-question-read-content">
|
|
27
27
|
<component
|
|
28
28
|
:is="QuestionTypeComponent"
|
|
29
|
+
v-model:answer="answerModel"
|
|
29
30
|
:question="question"
|
|
30
|
-
:result="
|
|
31
|
+
:result="answerModel /* compat, should use 'answer' */"
|
|
31
32
|
mode="read"
|
|
32
|
-
@change:result="
|
|
33
|
+
@change:result="updateAnswer /* compat, should use 'answer' */"
|
|
33
34
|
/>
|
|
34
35
|
<div
|
|
35
|
-
v-show="
|
|
36
|
+
v-show="isAnswer"
|
|
36
37
|
class="audit-form-question--clear"
|
|
37
|
-
@click="
|
|
38
|
+
@click="resetAnswer"
|
|
38
39
|
>
|
|
39
|
-
{{
|
|
40
|
+
{{ t('webitelUI.auditForm.clearSelection') }}
|
|
40
41
|
</div>
|
|
42
|
+
<wt-input
|
|
43
|
+
v-if="answerModel?.createdAt"
|
|
44
|
+
v-model="answerModel.comment"
|
|
45
|
+
:label="t('reusable.comment')"
|
|
46
|
+
/>
|
|
41
47
|
</section>
|
|
48
|
+
|
|
49
|
+
<template v-if="answerModel?.updatedAt">
|
|
50
|
+
<wt-divider />
|
|
51
|
+
<audit-form-answer-editing-info
|
|
52
|
+
:answer="answerModel"
|
|
53
|
+
/>
|
|
54
|
+
</template>
|
|
42
55
|
</article>
|
|
43
56
|
</template>
|
|
44
57
|
|
|
45
|
-
<script setup>
|
|
46
|
-
import { computed } from 'vue';
|
|
47
|
-
import {
|
|
58
|
+
<script lang="ts" setup>
|
|
59
|
+
import { computed, inject } from 'vue';
|
|
60
|
+
import {useI18n} from "vue-i18n";
|
|
61
|
+
import {EngineAuditQuestionType, EngineQuestion, EngineQuestionAnswer} from 'webitel-sdk';
|
|
48
62
|
|
|
49
|
-
import WtIcon from '../../../components
|
|
63
|
+
import { WtDivider,WtIcon, WtInput } from '../../../components';
|
|
50
64
|
import isEmpty from '../../../scripts/isEmpty.js';
|
|
51
|
-
import
|
|
52
|
-
import
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
type: Boolean,
|
|
69
|
-
default: false,
|
|
70
|
-
},
|
|
71
|
-
first: {
|
|
72
|
-
type: Boolean,
|
|
73
|
-
default: false,
|
|
74
|
-
},
|
|
75
|
-
});
|
|
65
|
+
import AuditFormAnswerEditingInfo from "./form-answers/answer-editing-info/audit-form-answer-editing-info.vue";
|
|
66
|
+
import AuditFormQuestionOptions from './form-questions/options/audit-form-question-options.vue';
|
|
67
|
+
import AuditFormQuestionScore from './form-questions/score/audit-form-question-score.vue';
|
|
68
|
+
|
|
69
|
+
const readonly = inject('readonly');
|
|
70
|
+
|
|
71
|
+
const answerModel = defineModel<EngineQuestionAnswer | null>('answer');
|
|
72
|
+
|
|
73
|
+
const props = defineProps<{
|
|
74
|
+
question: EngineQuestion;
|
|
75
|
+
disableDragging?: boolean;
|
|
76
|
+
first?: boolean;
|
|
77
|
+
}>();
|
|
78
|
+
|
|
79
|
+
const emit = defineEmits<{
|
|
80
|
+
'activate': [];
|
|
81
|
+
}>();
|
|
76
82
|
|
|
77
|
-
const
|
|
83
|
+
const { t } = useI18n();
|
|
78
84
|
|
|
79
85
|
const QuestionTypeComponent = computed(() => {
|
|
80
86
|
if (props.question.type === EngineAuditQuestionType.Option)
|
|
@@ -84,7 +90,22 @@ const QuestionTypeComponent = computed(() => {
|
|
|
84
90
|
return null;
|
|
85
91
|
});
|
|
86
92
|
|
|
87
|
-
const
|
|
93
|
+
const isAnswer = computed(() => !isEmpty(answerModel.value));
|
|
94
|
+
|
|
95
|
+
const updateAnswer = (value: EngineQuestionAnswer) => {
|
|
96
|
+
if (readonly.value) return; // if ... then in preview mode
|
|
97
|
+
|
|
98
|
+
// coz only some properties of answer may be patched
|
|
99
|
+
const newAnswer = Object.assign(answerModel.value, value);
|
|
100
|
+
answerModel.value = newAnswer;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const resetAnswer = () => {
|
|
104
|
+
answerModel.value = {
|
|
105
|
+
...answerModel.value,
|
|
106
|
+
score: null, // reset only score field
|
|
107
|
+
};
|
|
108
|
+
};
|
|
88
109
|
</script>
|
|
89
110
|
|
|
90
111
|
<style lang="scss" scoped>
|
|
@@ -128,6 +149,12 @@ const isResult = computed(() => !isEmpty(props.result));
|
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
|
|
152
|
+
.audit-form-question-read-content {
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
gap: var(--spacing-sm);
|
|
156
|
+
}
|
|
157
|
+
|
|
131
158
|
.audit-form-question--clear {
|
|
132
159
|
cursor: pointer;
|
|
133
160
|
margin-top: var(--spacing-sm);
|
|
@@ -71,8 +71,8 @@ import WtSwitcher from '../../../components/wt-switcher/wt-switcher.vue';
|
|
|
71
71
|
import WtTooltip from '../../../components/wt-tooltip/wt-tooltip.vue';
|
|
72
72
|
import { generateQuestionOptionsSchema } from '../schemas/AuditFormQuestionOptionsSchema.js';
|
|
73
73
|
import { generateQuestionScoreSchema } from '../schemas/AuditFormQuestionScoreSchema.js';
|
|
74
|
-
import AuditFormQuestionOptions from './questions/options/audit-form-question-options.vue';
|
|
75
|
-
import AuditFormQuestionScore from './questions/score/audit-form-question-score.vue';
|
|
74
|
+
import AuditFormQuestionOptions from './form-questions/options/audit-form-question-options.vue';
|
|
75
|
+
import AuditFormQuestionScore from './form-questions/score/audit-form-question-score.vue';
|
|
76
76
|
|
|
77
77
|
const props = defineProps({
|
|
78
78
|
question: {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
:class="[
|
|
6
6
|
`audit-form-question--mode-${mode}`,
|
|
7
7
|
{
|
|
8
|
-
'audit-form-question--answered':
|
|
8
|
+
'audit-form-question--answered': isAnswer,
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
'audit-form-question--sort-ignore': first && mode === 'fill',
|
|
@@ -15,54 +15,48 @@
|
|
|
15
15
|
:first="first"
|
|
16
16
|
:question="question"
|
|
17
17
|
:readonly="readonly"
|
|
18
|
-
:result="
|
|
18
|
+
:result="answer /* compat, should be ':answer' */"
|
|
19
|
+
:answer="answer"
|
|
19
20
|
:v="v$"
|
|
20
21
|
class="audit-form-question"
|
|
21
22
|
@activate="activateQuestion"
|
|
22
|
-
@copy="
|
|
23
|
-
@delete="
|
|
24
|
-
@change:question="
|
|
25
|
-
@
|
|
23
|
+
@copy="emit('copy')"
|
|
24
|
+
@delete="emit('delete')"
|
|
25
|
+
@change:question="emit('update:question', $event) /* compat, should be removed */"
|
|
26
|
+
@update:question="emit('update:question', $event)"
|
|
27
|
+
@change:result="emit('update:answer', $event) /* compat, should be ':answer' */"
|
|
28
|
+
@update:answer="emit('update:answer', $event)"
|
|
26
29
|
/>
|
|
27
30
|
</template>
|
|
28
31
|
|
|
29
|
-
<script setup>
|
|
32
|
+
<script lang="ts" setup>
|
|
30
33
|
import { useVuelidate } from '@vuelidate/core';
|
|
31
34
|
import { required } from '@vuelidate/validators';
|
|
32
|
-
import { computed, onMounted, ref, toRefs } from 'vue';
|
|
35
|
+
import { computed, inject,onMounted, ref, toRefs } from 'vue';
|
|
36
|
+
import { EngineQuestion, EngineQuestionAnswer } from "webitel-sdk";
|
|
33
37
|
|
|
34
38
|
import vClickaway from '../../../directives/clickaway/clickaway.js';
|
|
35
39
|
import isEmpty from '../../../scripts/isEmpty.js';
|
|
36
40
|
import QuestionRead from './audit-form-question-read-wrapper.vue';
|
|
37
41
|
import QuestionWrite from './audit-form-question-write-wrapper.vue';
|
|
38
42
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
type: String,
|
|
49
|
-
},
|
|
50
|
-
first: {
|
|
51
|
-
type: Boolean,
|
|
52
|
-
default: false,
|
|
53
|
-
},
|
|
54
|
-
readonly: {
|
|
55
|
-
type: Boolean,
|
|
56
|
-
default: false,
|
|
57
|
-
},
|
|
43
|
+
const mode = inject('mode');
|
|
44
|
+
const readonly = inject('readonly');
|
|
45
|
+
|
|
46
|
+
const props = withDefaults(defineProps<{
|
|
47
|
+
question: EngineQuestion;
|
|
48
|
+
answer: EngineQuestionAnswer | null;
|
|
49
|
+
first?: boolean;
|
|
50
|
+
}>(), {
|
|
51
|
+
first: false,
|
|
58
52
|
});
|
|
59
53
|
|
|
60
|
-
const
|
|
61
|
-
'copy'
|
|
62
|
-
'delete'
|
|
63
|
-
'update:question'
|
|
64
|
-
'update:
|
|
65
|
-
|
|
54
|
+
const emit = defineEmits<{
|
|
55
|
+
'copy': [];
|
|
56
|
+
'delete': [];
|
|
57
|
+
'update:question': [unknown]; // todo
|
|
58
|
+
'update:answer': [unknown]; // todo
|
|
59
|
+
}>();
|
|
66
60
|
|
|
67
61
|
const QuestionState = {
|
|
68
62
|
SAVED: 'saved',
|
|
@@ -72,44 +66,50 @@ const QuestionState = {
|
|
|
72
66
|
const state = ref(QuestionState.SAVED);
|
|
73
67
|
|
|
74
68
|
// is needed for useVuelidate, because props.question/props.result isn't reactive
|
|
75
|
-
const { question,
|
|
69
|
+
const { question, answer } = toRefs(props);
|
|
76
70
|
|
|
77
71
|
const v$ = useVuelidate(
|
|
78
72
|
computed(() =>
|
|
79
|
-
|
|
73
|
+
mode === 'create'
|
|
80
74
|
? {
|
|
81
75
|
question: {
|
|
82
76
|
question: { required },
|
|
83
77
|
},
|
|
84
78
|
}
|
|
85
79
|
: {
|
|
86
|
-
|
|
87
|
-
required: (value) =>
|
|
88
|
-
|
|
80
|
+
answer: {
|
|
81
|
+
required: (value) => {
|
|
82
|
+
// if not required, no need to validate
|
|
83
|
+
if (!props.question.required) return true;
|
|
84
|
+
|
|
85
|
+
if (value && value?.score != null) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
91
|
),
|
|
92
|
-
{ question,
|
|
92
|
+
{ question, answer },
|
|
93
93
|
{ $autoDirty: true },
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
const component = computed(() => {
|
|
97
|
-
if (
|
|
98
|
-
if (
|
|
97
|
+
if (readonly) return QuestionRead;
|
|
98
|
+
if (mode === 'create') {
|
|
99
99
|
if (state.value === QuestionState.SAVED) return QuestionRead;
|
|
100
100
|
return QuestionWrite;
|
|
101
101
|
}
|
|
102
102
|
return QuestionRead;
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
const
|
|
105
|
+
const isAnswer = computed(() => !isEmpty(props.answer));
|
|
106
106
|
|
|
107
107
|
function saveQuestion() {
|
|
108
108
|
state.value = QuestionState.SAVED;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
function activateQuestion() {
|
|
112
|
-
if (
|
|
112
|
+
if (mode !== 'create') return;
|
|
113
113
|
state.value = QuestionState.EDIT;
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -10,78 +10,90 @@
|
|
|
10
10
|
:key="key"
|
|
11
11
|
ref="auditQuestions"
|
|
12
12
|
:first="key === 0"
|
|
13
|
-
:mode="mode"
|
|
14
13
|
:question="question"
|
|
15
|
-
:
|
|
16
|
-
:result="result && result[key] ? result[key] : null"
|
|
14
|
+
:answer="answers && answers[key] ? answers[key] : null"
|
|
17
15
|
@copy="copyQuestion({ question, key })"
|
|
18
16
|
@delete="deleteQuestion({ question, key })"
|
|
19
17
|
@update:question="handleQuestionUpdate({ key, value: $event })"
|
|
20
|
-
@update:
|
|
18
|
+
@update:answer="handleAnswerUpdate({ key, value: $event })"
|
|
21
19
|
/>
|
|
22
20
|
</div>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class="
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
|
|
22
|
+
<wt-textarea
|
|
23
|
+
v-model="resultCommentModel"
|
|
24
|
+
class="call-evaluation-form__comment"
|
|
25
|
+
:label="$t('reusable.comment')"
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
<audit-form-footer
|
|
29
|
+
:invalid="isInvalidForm"
|
|
30
|
+
@fill:save="saveEvaluation"
|
|
31
|
+
@fill:cancel="cancelEvaluation"
|
|
32
|
+
@create:add="addQuestion"
|
|
33
|
+
/>
|
|
31
34
|
</section>
|
|
32
35
|
</template>
|
|
33
36
|
|
|
34
|
-
<script setup>
|
|
37
|
+
<script lang="ts" setup>
|
|
35
38
|
import { useVuelidate } from '@vuelidate/core';
|
|
36
39
|
import cloneDeep from 'lodash/cloneDeep.js';
|
|
37
40
|
import {
|
|
38
41
|
computed,
|
|
39
42
|
nextTick,
|
|
40
43
|
onMounted,
|
|
44
|
+
provide,
|
|
41
45
|
reactive,
|
|
42
|
-
|
|
46
|
+
useTemplateRef,
|
|
43
47
|
watch,
|
|
44
|
-
watchEffect,
|
|
45
48
|
} from 'vue';
|
|
49
|
+
import {EngineQuestion, EngineQuestionAnswer} from 'webitel-sdk';
|
|
46
50
|
|
|
47
|
-
import
|
|
51
|
+
import { WtTextarea } from '../../../components';
|
|
48
52
|
import { useDestroyableSortable } from '../../../composables/useDestroyableSortable/useDestroyableSortable.js';
|
|
49
53
|
import { generateQuestionSchema } from '../schemas/AuditFormQuestionSchema.js';
|
|
50
54
|
import AuditFormQuestion from './audit-form-question.vue';
|
|
55
|
+
import AuditFormFooter from "./form/form-footer/audit-form-footer.vue";
|
|
51
56
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
57
|
+
const answersModel = defineModel<EngineQuestionAnswer[]>('answers');
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* todo: rename to questionsModel and use instead of 'update:questions' event
|
|
61
|
+
*/
|
|
62
|
+
const questions = defineModel<EngineQuestion[]>('questions', {});
|
|
63
|
+
const resultCommentModel = defineModel<string>('resultComment');
|
|
64
|
+
|
|
65
|
+
const AuditFormMode = {
|
|
66
|
+
Create: 'create',
|
|
67
|
+
Fill: 'fill',
|
|
68
|
+
} as const;
|
|
69
|
+
|
|
70
|
+
type AuditFormMode = typeof AuditFormMode[keyof typeof AuditFormMode];
|
|
71
|
+
|
|
72
|
+
const props = defineProps<{
|
|
73
|
+
mode: AuditFormMode;
|
|
74
|
+
readonly?: boolean;
|
|
75
|
+
}>();
|
|
72
76
|
|
|
73
77
|
const emit = defineEmits([
|
|
78
|
+
/**
|
|
79
|
+
* todo: remove and use questions model
|
|
80
|
+
*/
|
|
74
81
|
'update:questions',
|
|
75
|
-
'update:result',
|
|
76
82
|
'update:validation',
|
|
83
|
+
'save:evaluation',
|
|
84
|
+
'cancel:evaluation',
|
|
77
85
|
]);
|
|
78
86
|
|
|
79
87
|
const v$ = useVuelidate();
|
|
80
88
|
|
|
81
|
-
const
|
|
82
|
-
const auditQuestions = ref(null);
|
|
89
|
+
const auditQuestions = useTemplateRef('auditQuestions');
|
|
83
90
|
const isQuestionAdded = reactive({ value: false, index: null });
|
|
84
91
|
|
|
92
|
+
provide('readonly', props.readonly);
|
|
93
|
+
provide('mode', props.mode);
|
|
94
|
+
|
|
95
|
+
const isInvalidForm = computed(() => !!v$.value.$errors.length);
|
|
96
|
+
|
|
85
97
|
async function addQuestion({ index, question } = {}) {
|
|
86
98
|
const questions = [...(props.questions || [])];
|
|
87
99
|
const newQuestion = question || generateQuestionSchema();
|
|
@@ -118,24 +130,33 @@ function changeQuestionsOrder({ oldIndex, newIndex }) {
|
|
|
118
130
|
emit('update:questions', questions);
|
|
119
131
|
}
|
|
120
132
|
|
|
121
|
-
function
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
function handleAnswerUpdate({ key, value }) {
|
|
134
|
+
const answer = [...answersModel.value];
|
|
135
|
+
answer[key] = value;
|
|
136
|
+
answersModel.value = answer;
|
|
125
137
|
}
|
|
126
138
|
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
139
|
+
function initAnswers() {
|
|
140
|
+
if (!answersModel.value || !answersModel.value.length) {
|
|
141
|
+
answersModel.value = props.questions.map(() => ({}));
|
|
142
|
+
}
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
function initQuestions() {
|
|
133
|
-
if (
|
|
146
|
+
if (!props.questions?.length) {
|
|
134
147
|
addQuestion({ question: generateQuestionSchema({ required: true }) });
|
|
135
148
|
} else if (props.questions.length)
|
|
136
149
|
auditQuestions.value.at(0).activateQuestion();
|
|
137
150
|
}
|
|
138
151
|
|
|
152
|
+
function saveEvaluation() {
|
|
153
|
+
emit('save:evaluation');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function cancelEvaluation() {
|
|
157
|
+
emit('cancel:evaluation');
|
|
158
|
+
}
|
|
159
|
+
|
|
139
160
|
// https://my.webitel.com/browse/WTEL-3451, https://my.webitel.com/browse/WTEL-3436
|
|
140
161
|
// at new question added, activate this question
|
|
141
162
|
async function atQuestionAdded() {
|
|
@@ -151,7 +172,7 @@ async function atQuestionAdded() {
|
|
|
151
172
|
isQuestionAdded.index = null;
|
|
152
173
|
}
|
|
153
174
|
|
|
154
|
-
const sortableWrapper =
|
|
175
|
+
const sortableWrapper = useTemplateRef('sortableWrapper');
|
|
155
176
|
|
|
156
177
|
const { reloadSortable } = useDestroyableSortable(sortableWrapper, {
|
|
157
178
|
handle: '.audit-form-question-read__drag-icon',
|
|
@@ -166,7 +187,7 @@ const { reloadSortable } = useDestroyableSortable(sortableWrapper, {
|
|
|
166
187
|
watch(v$, () =>
|
|
167
188
|
emit('update:validation', { invalid: isInvalidForm.value, v$: v$.value }),
|
|
168
189
|
);
|
|
169
|
-
|
|
190
|
+
|
|
170
191
|
watch(
|
|
171
192
|
() => props.questions,
|
|
172
193
|
() => {
|
|
@@ -176,7 +197,11 @@ watch(
|
|
|
176
197
|
);
|
|
177
198
|
|
|
178
199
|
onMounted(() => {
|
|
179
|
-
|
|
200
|
+
if (props.mode === AuditFormMode.Create) {
|
|
201
|
+
initQuestions();
|
|
202
|
+
} else if (props.mode === AuditFormMode.Fill) {
|
|
203
|
+
initAnswers();
|
|
204
|
+
}
|
|
180
205
|
});
|
|
181
206
|
</script>
|
|
182
207
|
|
|
@@ -190,8 +215,4 @@ onMounted(() => {
|
|
|
190
215
|
display: contents;
|
|
191
216
|
}
|
|
192
217
|
}
|
|
193
|
-
|
|
194
|
-
.audit-form__add-button {
|
|
195
|
-
align-self: flex-end;
|
|
196
|
-
}
|
|
197
218
|
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<footer class="audit-form-footer">
|
|
3
|
+
<template
|
|
4
|
+
v-if="mode === 'fill'"
|
|
5
|
+
>
|
|
6
|
+
<wt-button
|
|
7
|
+
:disabled="props.invalid"
|
|
8
|
+
@click="emit('fill:save')"
|
|
9
|
+
>
|
|
10
|
+
{{ t('reusable.save') }}
|
|
11
|
+
</wt-button>
|
|
12
|
+
<wt-button
|
|
13
|
+
color="secondary"
|
|
14
|
+
@click="emit('fill:cancel')"
|
|
15
|
+
>
|
|
16
|
+
{{ t('reusable.cancel') }}
|
|
17
|
+
</wt-button>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
<wt-button
|
|
22
|
+
v-else-if="mode === 'create' && !readonly"
|
|
23
|
+
class="audit-form-footer-create-question-action"
|
|
24
|
+
:disabled="props.invalid"
|
|
25
|
+
@click="emit('create:add')"
|
|
26
|
+
>
|
|
27
|
+
{{ t('webitelUI.auditForm.addQuestion') }}
|
|
28
|
+
</wt-button>
|
|
29
|
+
</footer>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { inject } from "vue";
|
|
34
|
+
import { useI18n } from "vue-i18n";
|
|
35
|
+
|
|
36
|
+
import WtButton from "../../../../../components/wt-button/wt-button.vue";
|
|
37
|
+
|
|
38
|
+
const mode = inject('mode');
|
|
39
|
+
const readonly = inject('readonly');
|
|
40
|
+
|
|
41
|
+
const props = defineProps<{
|
|
42
|
+
invalid: boolean;
|
|
43
|
+
}>();
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits<{
|
|
46
|
+
'fill:save': [];
|
|
47
|
+
'fill:cancel': [];
|
|
48
|
+
'create:add': [];
|
|
49
|
+
}>();
|
|
50
|
+
|
|
51
|
+
const { t } = useI18n();
|
|
52
|
+
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style scoped lang="scss">
|
|
56
|
+
.audit-form-footer {
|
|
57
|
+
display: flex;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
gap: var(--spacing-sm);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.audit-form-footer-create-question-action {
|
|
63
|
+
align-self: flex-end;
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="audit-form-answer-editing-info">
|
|
3
|
+
<header class="audit-form-answer-editing-info-header">
|
|
4
|
+
<span>{{ t('reusable.updatedBy') }}</span>
|
|
5
|
+
<span>{{ answer.updatedBy.name }}</span>
|
|
6
|
+
<span>{{ updateTime }}</span>
|
|
7
|
+
</header>
|
|
8
|
+
<p
|
|
9
|
+
v-if="initialComment"
|
|
10
|
+
ref="answer-editing-comment"
|
|
11
|
+
class="audit-form-answer-editing-info-comment"
|
|
12
|
+
:class="{
|
|
13
|
+
'audit-form-answer-editing-info-comment--collapsed': collapsed,
|
|
14
|
+
}"
|
|
15
|
+
>
|
|
16
|
+
{{ initialComment }}
|
|
17
|
+
</p>
|
|
18
|
+
<footer
|
|
19
|
+
v-if="collapsed && isCommentClamped"
|
|
20
|
+
class="audit-form-answer-editing-info-footer"
|
|
21
|
+
>
|
|
22
|
+
<button
|
|
23
|
+
class="audit-form-answer-editing-info-expand-action"
|
|
24
|
+
type="button"
|
|
25
|
+
@click="collapsed = false"
|
|
26
|
+
>
|
|
27
|
+
{{ t('reusable.more') }}
|
|
28
|
+
</button>
|
|
29
|
+
</footer>
|
|
30
|
+
</section>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import {computed, ref, useTemplateRef } from "vue";
|
|
35
|
+
import { useI18n } from 'vue-i18n';
|
|
36
|
+
import {EngineQuestionAnswer} from "webitel-sdk";
|
|
37
|
+
|
|
38
|
+
const props = withDefaults(defineProps<{
|
|
39
|
+
answer: EngineQuestionAnswer;
|
|
40
|
+
collapsible?: boolean;
|
|
41
|
+
}>(), {
|
|
42
|
+
collapsible: false,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const commentElRef = useTemplateRef('answer-editing-comment');
|
|
46
|
+
|
|
47
|
+
const collapsed = ref(props.collapsible);
|
|
48
|
+
|
|
49
|
+
const { t } = useI18n();
|
|
50
|
+
|
|
51
|
+
const initialComment = props.answer.comment; /* prevent editing-info change if comment is changing */
|
|
52
|
+
|
|
53
|
+
const updateTime = computed(() => {
|
|
54
|
+
return new Date(+props.answer.updatedAt).toLocaleString();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const isCommentClamped = props.collapsible && computed(() => {
|
|
58
|
+
// https://stackoverflow.com/a/67455839
|
|
59
|
+
return commentElRef.value?.clientHeight !== commentElRef.value?.scrollHeight;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<style scoped lang="scss">
|
|
65
|
+
@use '@webitel/styleguide/typography' as *;
|
|
66
|
+
|
|
67
|
+
.audit-form-answer-editing-info {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
gap: var(--spacing-xs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.audit-form-answer-editing-info-header {
|
|
74
|
+
@extend %typo-caption;
|
|
75
|
+
display: flex;
|
|
76
|
+
gap: var(--spacing-xs);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.audit-form-answer-editing-info-comment {
|
|
80
|
+
@extend %typo-body-1;
|
|
81
|
+
|
|
82
|
+
&--collapsed {
|
|
83
|
+
line-clamp: 2;
|
|
84
|
+
-webkit-line-clamp: 2; /* coz autoprefixer wont write "-webkit" for us https://github.com/postcss/autoprefixer/issues/1322 */
|
|
85
|
+
-webkit-box-orient: vertical; /* is needed for line-clamp */
|
|
86
|
+
display: -webkit-box;
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.audit-form-answer-editing-info-footer {
|
|
92
|
+
display: flex;
|
|
93
|
+
justify-content: flex-end;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.audit-form-answer-editing-info-expand-action {
|
|
97
|
+
@extend %typo-body-1;
|
|
98
|
+
color: var(--text-link-color);
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
transition: var(--transition);
|
|
101
|
+
|
|
102
|
+
&:hover {
|
|
103
|
+
text-decoration: underline;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
</style>
|
|
@@ -48,7 +48,7 @@ const props = defineProps({
|
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
const emit = defineEmits(['
|
|
51
|
+
const emit = defineEmits(['update:option', 'delete']);
|
|
52
52
|
|
|
53
53
|
// is needed for useVuelidate, because props.question/props.result isn't reactive
|
|
54
54
|
const { option } = toRefs(props);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
class="audit-form-question-options-write"
|
|
6
6
|
>
|
|
7
7
|
<options-write-row
|
|
8
|
-
v-for="(option, key) of
|
|
8
|
+
v-for="(option, key) of questionModel.options"
|
|
9
9
|
:key="key"
|
|
10
10
|
:first="key === 0"
|
|
11
11
|
:option="option"
|
|
@@ -26,56 +26,62 @@
|
|
|
26
26
|
class="audit-form-question-options-read"
|
|
27
27
|
>
|
|
28
28
|
<wt-radio
|
|
29
|
-
v-for="opt of
|
|
29
|
+
v-for="opt of questionModel.options"
|
|
30
30
|
:key="opt.score + opt.name"
|
|
31
31
|
:label="opt.name"
|
|
32
|
-
:selected="
|
|
33
|
-
:value="opt"
|
|
34
|
-
@input="
|
|
32
|
+
:selected="answerModel?.score"
|
|
33
|
+
:value="opt.score"
|
|
34
|
+
@input="updateAnswer"
|
|
35
35
|
/>
|
|
36
36
|
</div>
|
|
37
37
|
<div v-else>Unknown mode: {{ mode }}</div>
|
|
38
38
|
</article>
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
|
-
<script setup>
|
|
42
|
-
import
|
|
43
|
-
|
|
41
|
+
<script lang="ts" setup>
|
|
42
|
+
import {EngineQuestion, EngineQuestionAnswer} from "webitel-sdk";
|
|
43
|
+
|
|
44
|
+
import { WtButton, WtRadio } from '../../../../../components';
|
|
44
45
|
import updateObject from '../../../../../scripts/updateObject.js';
|
|
45
46
|
import { generateOption } from '../../../schemas/AuditFormQuestionOptionsSchema.js';
|
|
46
47
|
import OptionsWriteRow from './audit-form-question-options-write-row.vue';
|
|
47
48
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
type: Object,
|
|
51
|
-
required: true,
|
|
52
|
-
},
|
|
53
|
-
result: {
|
|
54
|
-
type: Object,
|
|
55
|
-
},
|
|
56
|
-
mode: {
|
|
57
|
-
// options: ['read', 'write']
|
|
58
|
-
type: String,
|
|
59
|
-
default: 'read',
|
|
60
|
-
},
|
|
61
|
-
});
|
|
49
|
+
const questionModel = defineModel<EngineQuestion>('question');
|
|
50
|
+
const answerModel = defineModel<EngineQuestionAnswer | null>('answer');
|
|
62
51
|
|
|
63
|
-
const
|
|
52
|
+
const props = defineProps<{
|
|
53
|
+
/**
|
|
54
|
+
* question mode, NOT audit form mode
|
|
55
|
+
*/
|
|
56
|
+
mode: 'read' | 'write';
|
|
57
|
+
}>();
|
|
64
58
|
|
|
65
59
|
function updateQuestion({ path, value }) {
|
|
66
|
-
|
|
60
|
+
questionModel.value = updateObject({
|
|
61
|
+
obj: questionModel.value,
|
|
62
|
+
path,
|
|
63
|
+
value,
|
|
64
|
+
});
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
function addQuestionOption() {
|
|
70
|
-
const options = [...
|
|
68
|
+
const options = [...questionModel.value.options, generateOption()];
|
|
71
69
|
return updateQuestion({ path: 'options', value: options });
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
function deleteQuestionOption({ key }) {
|
|
75
|
-
const options = [...
|
|
73
|
+
const options = [...questionModel.value.options];
|
|
76
74
|
options.splice(key, 1);
|
|
77
75
|
return updateQuestion({ path: 'options', value: options });
|
|
78
76
|
}
|
|
77
|
+
|
|
78
|
+
function updateAnswer(score) {
|
|
79
|
+
answerModel.value = answerModel.value ? {
|
|
80
|
+
...answerModel.value,
|
|
81
|
+
score,
|
|
82
|
+
} : { score };
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
</script>
|
|
80
86
|
|
|
81
87
|
<style lang="scss" scoped>
|
|
@@ -65,6 +65,8 @@ export const mapScopeClassToWtObjects: Record<ScopeClass, WtObject[]> = {
|
|
|
65
65
|
[ScopeClass.ChatBots]: [WtObject.ChatBot], // routing cht_gateway
|
|
66
66
|
[ScopeClass.Cases]: [WtObject.Case], // CRM
|
|
67
67
|
[ScopeClass.CaseComments]: [WtObject.CaseComment],
|
|
68
|
+
[ScopeClass.AuditForm]: [WtObject.AuditForm],
|
|
69
|
+
[ScopeClass.AuditRating]: [WtObject.AuditRating],
|
|
68
70
|
};
|
|
69
71
|
|
|
70
72
|
export const mapScopeClassAccessTokenToCrudAction = {
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
$emit: (event: "change:result" | "change:question", ...args: any[]) => void;
|
|
3
|
-
mode: string;
|
|
4
|
-
question: Record<string, any>;
|
|
5
|
-
result?: Record<string, any>;
|
|
6
|
-
$props: {
|
|
7
|
-
readonly mode?: string;
|
|
8
|
-
readonly question?: Record<string, any>;
|
|
9
|
-
readonly result?: Record<string, any>;
|
|
10
|
-
};
|
|
11
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
12
|
-
export default _default;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|