@webitel/ui-sdk 25.6.6 → 25.6.8
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 +20 -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 +14 -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 +3 -3
- 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 +88 -54
- package/src/modules/AuditForm/components/form/form-footer/audit-form-footer.vue +66 -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,21 @@
|
|
|
1
|
+
## [v25.6.7] - 2025-05-08
|
|
2
|
+
### :sparkles: New Features
|
|
3
|
+
- [`cf7f6a7`](https://github.com/webitel/webitel-ui-sdk/commit/cf7f6a7b15d03779422f0b07ca4a5cc3a6f1acbd) - enhance audit-form components with improved styling and layout [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
4
|
+
- [`4adcd22`](https://github.com/webitel/webitel-ui-sdk/commit/4adcd2287c9cafb043350107b7fb8b9981b15abc) - small audit form result ui improvements and fixes [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
5
|
+
- [`5cf68bf`](https://github.com/webitel/webitel-ui-sdk/commit/5cf68bff9e9601955ad55430de5bdcdf48bde59d) - implemented audit form crud, still needs refactors and minor fixes [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
6
|
+
- [`8dca647`](https://github.com/webitel/webitel-ui-sdk/commit/8dca647d49a8124f837502d1423483c06b45e24d) - audit form editing in progress [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
7
|
+
|
|
8
|
+
### :recycle: Refactors
|
|
9
|
+
- [`d739383`](https://github.com/webitel/webitel-ui-sdk/commit/d739383afbfd47ec5bfeb2431ae97393921ae758) - refactors and fixes to use audit-form in auditor app [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
10
|
+
- [`0723bf0`](https://github.com/webitel/webitel-ui-sdk/commit/0723bf0229d6981a3f272261a6b7fd178481d758) - audit-related values added WtObject and ScopeClass enums [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
11
|
+
- [`4fc05fe`](https://github.com/webitel/webitel-ui-sdk/commit/4fc05feff5253e44eb57b4d7a5e8bcab98a0bc49) - audit form refactors [WTEL-5679](https://webitel.atlassian.net/browse/WTEL-5679) *(commit by [@dlohvinov](https://github.com/dlohvinov))*
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [v25.6.6] - 2025-05-07
|
|
15
|
+
### :bug: Bug Fixes
|
|
16
|
+
- [`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))*
|
|
17
|
+
|
|
18
|
+
|
|
1
19
|
## [v25.6.5] - 2025-05-05
|
|
2
20
|
### :bug: Bug Fixes
|
|
3
21
|
- [`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 +2104,5 @@
|
|
|
2086
2104
|
[v25.6.3]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.2...v25.6.3
|
|
2087
2105
|
[v25.6.4]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.3...v25.6.4
|
|
2088
2106
|
[v25.6.5]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.4...v25.6.5
|
|
2107
|
+
[v25.6.6]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.5...v25.6.6
|
|
2108
|
+
[v25.6.7]: https://github.com/webitel/webitel-ui-sdk/compare/v25.6.6...v25.6.7
|
|
@@ -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,14 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
invalid: boolean;
|
|
3
|
+
disabledSave?: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"fill:save": () => any;
|
|
7
|
+
"fill:cancel": () => any;
|
|
8
|
+
"create:add": () => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
"onFill:save"?: () => any;
|
|
11
|
+
"onFill:cancel"?: () => any;
|
|
12
|
+
"onCreate:add"?: () => any;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webitel/ui-sdk",
|
|
3
|
-
"version": "25.6.
|
|
3
|
+
"version": "25.6.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npm run docs:dev",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"orval": "orval",
|
|
17
17
|
"utils:link": "npm link",
|
|
18
18
|
"utils:update-node": "nvm install --lts && nvm alias default node",
|
|
19
|
-
"utils:i": "npm install"
|
|
19
|
+
"utils:i": "npm install --install-links"
|
|
20
20
|
},
|
|
21
21
|
"main": "./dist/ui-sdk.js",
|
|
22
22
|
"type": "module",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"vue-multiselect": "^3.1.0",
|
|
109
109
|
"vue-observe-visibility": "^2.0.0-alpha.1",
|
|
110
110
|
"vue-router": "^4.5.0",
|
|
111
|
-
"webitel-sdk": "^25.
|
|
111
|
+
"webitel-sdk": "^25.4.3",
|
|
112
112
|
"xlsx": "0.18.5",
|
|
113
113
|
"zod": "^3.24.2"
|
|
114
114
|
},
|
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,96 @@
|
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
|
|
22
|
+
<wt-textarea
|
|
23
|
+
v-if="mode === AuditFormMode.Fill"
|
|
24
|
+
:value="resultCommentModel"
|
|
25
|
+
class="call-evaluation-form__comment"
|
|
26
|
+
:label="$t('reusable.comment')"
|
|
27
|
+
@input="handleResultCommentUpdate"
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<audit-form-footer
|
|
31
|
+
:invalid="isInvalidForm"
|
|
32
|
+
:disabled-save="!isAnswersTouched"
|
|
33
|
+
@fill:save="saveEvaluation"
|
|
34
|
+
@fill:cancel="cancelEvaluation"
|
|
35
|
+
@create:add="addQuestion"
|
|
36
|
+
/>
|
|
31
37
|
</section>
|
|
32
38
|
</template>
|
|
33
39
|
|
|
34
|
-
<script setup>
|
|
40
|
+
<script lang="ts" setup>
|
|
35
41
|
import { useVuelidate } from '@vuelidate/core';
|
|
36
42
|
import cloneDeep from 'lodash/cloneDeep.js';
|
|
37
43
|
import {
|
|
38
44
|
computed,
|
|
39
45
|
nextTick,
|
|
40
46
|
onMounted,
|
|
47
|
+
provide,
|
|
41
48
|
reactive,
|
|
42
49
|
ref,
|
|
50
|
+
useTemplateRef,
|
|
43
51
|
watch,
|
|
44
|
-
watchEffect,
|
|
45
52
|
} from 'vue';
|
|
53
|
+
import {EngineQuestion, EngineQuestionAnswer} from 'webitel-sdk';
|
|
46
54
|
|
|
47
|
-
import
|
|
55
|
+
import { WtTextarea } from '../../../components';
|
|
48
56
|
import { useDestroyableSortable } from '../../../composables/useDestroyableSortable/useDestroyableSortable.js';
|
|
49
57
|
import { generateQuestionSchema } from '../schemas/AuditFormQuestionSchema.js';
|
|
50
58
|
import AuditFormQuestion from './audit-form-question.vue';
|
|
59
|
+
import AuditFormFooter from "./form/form-footer/audit-form-footer.vue";
|
|
51
60
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
61
|
+
const answersModel = defineModel<EngineQuestionAnswer[]>('answers');
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* todo: rename to questionsModel and use instead of 'update:questions' event
|
|
65
|
+
*/
|
|
66
|
+
const questions = defineModel<EngineQuestion[]>('questions', {});
|
|
67
|
+
const resultCommentModel = defineModel<string>('resultComment');
|
|
68
|
+
|
|
69
|
+
const AuditFormMode = {
|
|
70
|
+
Create: 'create',
|
|
71
|
+
Fill: 'fill',
|
|
72
|
+
} as const;
|
|
73
|
+
|
|
74
|
+
type AuditFormMode = typeof AuditFormMode[keyof typeof AuditFormMode];
|
|
75
|
+
|
|
76
|
+
const props = defineProps<{
|
|
77
|
+
mode: AuditFormMode;
|
|
78
|
+
readonly?: boolean;
|
|
79
|
+
}>();
|
|
72
80
|
|
|
73
81
|
const emit = defineEmits([
|
|
82
|
+
/**
|
|
83
|
+
* todo: remove and use questions model
|
|
84
|
+
*/
|
|
74
85
|
'update:questions',
|
|
75
|
-
'update:result',
|
|
76
86
|
'update:validation',
|
|
87
|
+
'save:evaluation',
|
|
88
|
+
'cancel:evaluation',
|
|
77
89
|
]);
|
|
78
90
|
|
|
79
91
|
const v$ = useVuelidate();
|
|
80
92
|
|
|
81
|
-
const
|
|
82
|
-
const auditQuestions = ref(null);
|
|
93
|
+
const auditQuestions = useTemplateRef('auditQuestions');
|
|
83
94
|
const isQuestionAdded = reactive({ value: false, index: null });
|
|
84
95
|
|
|
96
|
+
const isAnswersTouched = ref(false);
|
|
97
|
+
|
|
98
|
+
provide('readonly', props.readonly);
|
|
99
|
+
provide('mode', props.mode);
|
|
100
|
+
|
|
101
|
+
const isInvalidForm = computed(() => !!v$.value.$errors.length);
|
|
102
|
+
|
|
85
103
|
async function addQuestion({ index, question } = {}) {
|
|
86
104
|
const questions = [...(props.questions || [])];
|
|
87
105
|
const newQuestion = question || generateQuestionSchema();
|
|
@@ -89,7 +107,7 @@ async function addQuestion({ index, question } = {}) {
|
|
|
89
107
|
else questions.push(newQuestion);
|
|
90
108
|
isQuestionAdded.value = true;
|
|
91
109
|
isQuestionAdded.index = index || 'last';
|
|
92
|
-
|
|
110
|
+
emit('update:questions', questions);
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
function handleQuestionUpdate({ key, value }) {
|
|
@@ -118,24 +136,35 @@ function changeQuestionsOrder({ oldIndex, newIndex }) {
|
|
|
118
136
|
emit('update:questions', questions);
|
|
119
137
|
}
|
|
120
138
|
|
|
121
|
-
function
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
139
|
+
function handleAnswerUpdate({ key, value }) {
|
|
140
|
+
const answer = [...answersModel.value];
|
|
141
|
+
answer[key] = value;
|
|
142
|
+
answersModel.value = answer;
|
|
143
|
+
|
|
144
|
+
isAnswersTouched.value = true;
|
|
125
145
|
}
|
|
126
146
|
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
147
|
+
function initAnswers() {
|
|
148
|
+
if (!answersModel.value || !answersModel.value.length) {
|
|
149
|
+
answersModel.value = props.questions.map(() => ({}));
|
|
150
|
+
}
|
|
130
151
|
}
|
|
131
152
|
|
|
132
153
|
function initQuestions() {
|
|
133
|
-
if (
|
|
154
|
+
if (!props.questions?.length) {
|
|
134
155
|
addQuestion({ question: generateQuestionSchema({ required: true }) });
|
|
135
156
|
} else if (props.questions.length)
|
|
136
157
|
auditQuestions.value.at(0).activateQuestion();
|
|
137
158
|
}
|
|
138
159
|
|
|
160
|
+
function saveEvaluation() {
|
|
161
|
+
emit('save:evaluation');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function cancelEvaluation() {
|
|
165
|
+
emit('cancel:evaluation');
|
|
166
|
+
}
|
|
167
|
+
|
|
139
168
|
// https://my.webitel.com/browse/WTEL-3451, https://my.webitel.com/browse/WTEL-3436
|
|
140
169
|
// at new question added, activate this question
|
|
141
170
|
async function atQuestionAdded() {
|
|
@@ -151,7 +180,12 @@ async function atQuestionAdded() {
|
|
|
151
180
|
isQuestionAdded.index = null;
|
|
152
181
|
}
|
|
153
182
|
|
|
154
|
-
|
|
183
|
+
function handleResultCommentUpdate(value) {
|
|
184
|
+
resultCommentModel.value = value;
|
|
185
|
+
isAnswersTouched.value = true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const sortableWrapper = useTemplateRef('sortableWrapper');
|
|
155
189
|
|
|
156
190
|
const { reloadSortable } = useDestroyableSortable(sortableWrapper, {
|
|
157
191
|
handle: '.audit-form-question-read__drag-icon',
|
|
@@ -166,7 +200,7 @@ const { reloadSortable } = useDestroyableSortable(sortableWrapper, {
|
|
|
166
200
|
watch(v$, () =>
|
|
167
201
|
emit('update:validation', { invalid: isInvalidForm.value, v$: v$.value }),
|
|
168
202
|
);
|
|
169
|
-
|
|
203
|
+
|
|
170
204
|
watch(
|
|
171
205
|
() => props.questions,
|
|
172
206
|
() => {
|
|
@@ -176,7 +210,11 @@ watch(
|
|
|
176
210
|
);
|
|
177
211
|
|
|
178
212
|
onMounted(() => {
|
|
179
|
-
|
|
213
|
+
if (props.mode === AuditFormMode.Create) {
|
|
214
|
+
initQuestions();
|
|
215
|
+
} else if (props.mode === AuditFormMode.Fill) {
|
|
216
|
+
initAnswers();
|
|
217
|
+
}
|
|
180
218
|
});
|
|
181
219
|
</script>
|
|
182
220
|
|
|
@@ -190,8 +228,4 @@ onMounted(() => {
|
|
|
190
228
|
display: contents;
|
|
191
229
|
}
|
|
192
230
|
}
|
|
193
|
-
|
|
194
|
-
.audit-form__add-button {
|
|
195
|
-
align-self: flex-end;
|
|
196
|
-
}
|
|
197
231
|
</style>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<footer class="audit-form-footer">
|
|
3
|
+
<template
|
|
4
|
+
v-if="mode === 'fill'"
|
|
5
|
+
>
|
|
6
|
+
<wt-button
|
|
7
|
+
:disabled="props.invalid || disabledSave"
|
|
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
|
+
disabledSave?: boolean;
|
|
44
|
+
}>();
|
|
45
|
+
|
|
46
|
+
const emit = defineEmits<{
|
|
47
|
+
'fill:save': [];
|
|
48
|
+
'fill:cancel': [];
|
|
49
|
+
'create:add': [];
|
|
50
|
+
}>();
|
|
51
|
+
|
|
52
|
+
const { t } = useI18n();
|
|
53
|
+
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<style scoped lang="scss">
|
|
57
|
+
.audit-form-footer {
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
gap: var(--spacing-sm);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.audit-form-footer-create-question-action {
|
|
64
|
+
margin-left: auto;
|
|
65
|
+
}
|
|
66
|
+
</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
|