@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.
Files changed (31) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/types/enums/WtObject/WtObject.d.ts +2 -0
  3. package/dist/types/modules/AuditForm/components/audit-form-question-read-wrapper.vue.d.ts +16 -15
  4. package/dist/types/modules/AuditForm/components/audit-form-question.vue.d.ts +20 -15
  5. package/dist/types/modules/AuditForm/components/audit-form.vue.d.ts +33 -13
  6. package/dist/types/modules/AuditForm/components/form/form-footer/audit-form-footer.vue.d.ts +14 -0
  7. package/dist/types/modules/AuditForm/components/form-answers/answer-editing-info/audit-form-answer-editing-info.vue.d.ts +9 -0
  8. package/dist/types/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options-write-row.vue.d.ts +1 -1
  9. package/dist/types/modules/AuditForm/components/form-questions/options/audit-form-question-options.vue.d.ts +19 -0
  10. package/dist/types/modules/AuditForm/components/{questions → form-questions}/score/audit-form-question-score.vue.d.ts +1 -1
  11. package/dist/types/modules/Userinfo/v2/enums/ScopeClass/ScopeClass.d.ts +2 -0
  12. package/package.json +3 -3
  13. package/src/enums/WtObject/WtObject.ts +2 -0
  14. package/src/locale/en/en.js +4 -0
  15. package/src/locale/ru/ru.js +4 -0
  16. package/src/locale/ua/ua.js +4 -0
  17. package/src/modules/AuditForm/components/audit-form-question-read-wrapper.vue +64 -37
  18. package/src/modules/AuditForm/components/audit-form-question-write-wrapper.vue +2 -2
  19. package/src/modules/AuditForm/components/audit-form-question.vue +43 -43
  20. package/src/modules/AuditForm/components/audit-form.vue +88 -54
  21. package/src/modules/AuditForm/components/form/form-footer/audit-form-footer.vue +66 -0
  22. package/src/modules/AuditForm/components/form-answers/answer-editing-info/audit-form-answer-editing-info.vue +106 -0
  23. package/src/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options-write-row.vue +1 -1
  24. package/src/modules/AuditForm/components/{questions → form-questions}/options/audit-form-question-options.vue +32 -26
  25. package/src/modules/Userinfo/v2/enums/ScopeClass/ScopeClass.ts +2 -0
  26. package/src/modules/Userinfo/v2/mappings/mappings.ts +2 -0
  27. package/dist/types/modules/AuditForm/components/questions/options/audit-form-question-options.vue.d.ts +0 -12
  28. /package/src/modules/AuditForm/components/{questions → form-questions}/options/__tests__/audit-form-question-options-write-row.spec.js +0 -0
  29. /package/src/modules/AuditForm/components/{questions → form-questions}/options/__tests__/audit-form-question-options.spec.js +0 -0
  30. /package/src/modules/AuditForm/components/{questions → form-questions}/score/__tests__/audit-form-question-score.spec.js +0 -0
  31. /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
- declare const _default: import("vue").DefineComponent<{}, {
2
- $emit: (event: "change:result" | "activate", ...args: any[]) => void;
3
- question: Record<string, any>;
4
- result: Record<string, any>;
5
- disableDragging: boolean;
6
- readonly: boolean;
7
- first: boolean;
8
- $props: {
9
- readonly question?: Record<string, any>;
10
- readonly result?: Record<string, any>;
11
- readonly disableDragging?: boolean;
12
- readonly readonly?: boolean;
13
- readonly first?: boolean;
14
- };
15
- }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
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
- declare const _default: import("vue").DefineComponent<{}, {
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
- $emit: (event: "delete" | "copy" | "update:question" | "update:result", ...args: any[]) => void;
4
- question: Record<string, any>;
5
- readonly: boolean;
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
- mode?: string;
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
- declare const _default: import("vue").DefineComponent<{}, {
2
- $emit: (event: "update:result" | "update:questions" | "update:validation", ...args: any[]) => void;
3
- mode: string;
4
- readonly: boolean;
5
- questions: unknown[];
6
- result?: unknown[];
7
- $props: {
8
- readonly mode?: string;
9
- readonly readonly?: boolean;
10
- readonly questions?: unknown[];
11
- readonly result?: unknown[];
12
- };
13
- }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
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;
@@ -1,5 +1,5 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
- $emit: (event: "delete" | "change:option", ...args: any[]) => void;
2
+ $emit: (event: "delete" | "update:option", ...args: any[]) => void;
3
3
  option: Record<string, any>;
4
4
  first: boolean;
5
5
  $props: {
@@ -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:result" | "change:question", ...args: any[]) => void;
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.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.2.19",
111
+ "webitel-sdk": "^25.4.3",
112
112
  "xlsx": "0.18.5",
113
113
  "zod": "^3.24.2"
114
114
  },
@@ -56,6 +56,8 @@ export const WtObject = {
56
56
  Status: 'status',
57
57
  Source: 'source',
58
58
  CustomLookup: 'customLookup',
59
+ AuditForm: 'auditForm',
60
+ AuditRating: 'auditRating',
59
61
  } as const;
60
62
 
61
63
  export type WtObject = (typeof WtObject)[keyof typeof WtObject];
@@ -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: {
@@ -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: 'Применить',
@@ -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': isResult && result.score != null,
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="result"
31
+ :result="answerModel /* compat, should use 'answer' */"
31
32
  mode="read"
32
- @change:result="!readonly && emit('change:result', $event)"
33
+ @change:result="updateAnswer /* compat, should use 'answer' */"
33
34
  />
34
35
  <div
35
- v-show="isResult"
36
+ v-show="isAnswer"
36
37
  class="audit-form-question--clear"
37
- @click="emit('change:result', {})"
38
+ @click="resetAnswer"
38
39
  >
39
- {{ $t('webitelUI.auditForm.clearSelection') }}
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 { EngineAuditQuestionType } from 'webitel-sdk';
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/wt-icon/wt-icon.vue';
63
+ import { WtDivider,WtIcon, WtInput } from '../../../components';
50
64
  import isEmpty from '../../../scripts/isEmpty.js';
51
- import AuditFormQuestionOptions from './questions/options/audit-form-question-options.vue';
52
- import AuditFormQuestionScore from './questions/score/audit-form-question-score.vue';
53
-
54
- const props = defineProps({
55
- question: {
56
- type: Object,
57
- required: true,
58
- },
59
- result: {
60
- type: [Object, null],
61
- required: true,
62
- },
63
- disableDragging: {
64
- type: Boolean,
65
- default: false,
66
- },
67
- readonly: {
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 emit = defineEmits(['change:result', 'activate']);
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 isResult = computed(() => !isEmpty(props.result));
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': isResult,
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="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="emits('copy')"
23
- @delete="emits('delete')"
24
- @change:question="emits('update:question', $event)"
25
- @change:result="emits('update:result', $event)"
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 props = defineProps({
40
- question: {
41
- type: Object,
42
- required: true,
43
- },
44
- result: {
45
- type: Object,
46
- },
47
- mode: {
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 emits = defineEmits([
61
- 'copy',
62
- 'delete',
63
- 'update:question',
64
- 'update:result',
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, result } = toRefs(props);
69
+ const { question, answer } = toRefs(props);
76
70
 
77
71
  const v$ = useVuelidate(
78
72
  computed(() =>
79
- props.mode === 'create'
73
+ mode === 'create'
80
74
  ? {
81
75
  question: {
82
76
  question: { required },
83
77
  },
84
78
  }
85
79
  : {
86
- result: {
87
- required: (value) =>
88
- question.value.required ? !isEmpty(value) : true,
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, result },
92
+ { question, answer },
93
93
  { $autoDirty: true },
94
94
  );
95
95
 
96
96
  const component = computed(() => {
97
- if (props.readonly) return QuestionRead;
98
- if (props.mode === 'create') {
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 isResult = computed(() => !isEmpty(props.result));
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 (props.mode !== 'create') return;
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
- :readonly="readonly"
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:result="handleResultUpdate({ key, value: $event })"
18
+ @update:answer="handleAnswerUpdate({ key, value: $event })"
21
19
  />
22
20
  </div>
23
- <wt-button
24
- v-if="mode === 'create' && !readonly"
25
- :disabled="isInvalidForm"
26
- class="audit-form__add-button"
27
- @click="addQuestion"
28
- >
29
- {{ $t('webitelUI.auditForm.addQuestion') }}
30
- </wt-button>
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 WtButton from '../../../components/wt-button/wt-button.vue';
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 props = defineProps({
53
- mode: {
54
- type: String,
55
- required: true,
56
- /*
57
- * Available options: ['create', 'fill']
58
- * */
59
- },
60
- questions: {
61
- type: Array,
62
- required: true,
63
- },
64
- result: {
65
- type: Array,
66
- },
67
- readonly: {
68
- type: Boolean,
69
- default: false,
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 isInvalidForm = computed(() => !!v$.value.$errors.length);
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
- await emit('update:questions', questions);
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 handleResultUpdate({ key, value }) {
122
- const result = [...props.result];
123
- result[key] = value;
124
- emit('update:result', result);
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 initResult() {
128
- const result = props.questions?.map(() => ({}));
129
- emit('update:result', result);
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 (props.mode === 'create' && !props.questions?.length) {
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
- const sortableWrapper = ref(null);
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
- watchEffect(initResult);
203
+
170
204
  watch(
171
205
  () => props.questions,
172
206
  () => {
@@ -176,7 +210,11 @@ watch(
176
210
  );
177
211
 
178
212
  onMounted(() => {
179
- initQuestions();
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(['change:option', 'delete']);
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 question.options"
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 question.options"
29
+ v-for="opt of questionModel.options"
30
30
  :key="opt.score + opt.name"
31
31
  :label="opt.name"
32
- :selected="result"
33
- :value="opt"
34
- @input="emit('change:result', $event)"
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 WtButton from '../../../../../components/wt-button/wt-button.vue';
43
- import WtRadio from '../../../../../components/wt-radio/wt-radio.vue';
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 props = defineProps({
49
- question: {
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 emit = defineEmits(['change:question', 'change:result']);
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
- emit('change:question', updateObject({ obj: props.question, path, value }));
60
+ questionModel.value = updateObject({
61
+ obj: questionModel.value,
62
+ path,
63
+ value,
64
+ });
67
65
  }
68
66
 
69
67
  function addQuestionOption() {
70
- const options = [...props.question.options, generateOption()];
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 = [...props.question.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>
@@ -42,6 +42,8 @@ export const ScopeClass = {
42
42
  ChatBots: 'chat_bots',
43
43
  Cases: 'cases',
44
44
  CaseComments: 'case_comments',
45
+ AuditForm: 'cc_audit_form',
46
+ AuditRating: 'rating',
45
47
  } as const;
46
48
 
47
49
  export type ScopeClass = (typeof ScopeClass)[keyof typeof ScopeClass];
@@ -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;