shared-ritm 1.2.121 → 1.2.123

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 (109) hide show
  1. package/README.md +103 -103
  2. package/dist/index.css +1 -1
  3. package/dist/shared-ritm.es.js +3549 -3563
  4. package/dist/shared-ritm.umd.js +137 -137
  5. package/dist/types/api/services/ControlsService.d.ts +1 -0
  6. package/dist/types/api/types/Api_Controls.d.ts +7 -0
  7. package/dist/types/utils/faceApiHelper.d.ts +2 -2
  8. package/package.json +1 -1
  9. package/src/App.vue +2461 -2461
  10. package/src/api/services/AuthService.ts +53 -53
  11. package/src/api/services/CommentsService.ts +24 -24
  12. package/src/api/services/ControlsService.ts +69 -65
  13. package/src/api/services/FileService.ts +17 -17
  14. package/src/api/services/GanttService.ts +17 -17
  15. package/src/api/services/MetricsService.ts +110 -110
  16. package/src/api/services/ProjectsService.ts +79 -79
  17. package/src/api/services/RepairsService.ts +119 -119
  18. package/src/api/services/TasksService.ts +145 -145
  19. package/src/api/types/Api_Auth.ts +86 -86
  20. package/src/api/types/Api_Comment.ts +40 -40
  21. package/src/api/types/Api_Controls.ts +79 -72
  22. package/src/api/types/Api_Files.ts +7 -7
  23. package/src/api/types/Api_Projects.ts +60 -60
  24. package/src/api/types/Api_Service.ts +9 -9
  25. package/src/api/types/Api_Tasks.ts +319 -319
  26. package/src/common/app-button/AppButton.vue +173 -173
  27. package/src/common/app-checkbox/AppCheckbox.vue +26 -26
  28. package/src/common/app-date-picker/AppDatePicker.vue +81 -81
  29. package/src/common/app-datepicker/AppDatepicker.vue +165 -165
  30. package/src/common/app-dialogs/AppConfirmDialog.vue +99 -99
  31. package/src/common/app-dropdown/AppDropdown.vue +31 -31
  32. package/src/common/app-icon/AppIcon.vue +108 -108
  33. package/src/common/app-input/AppInput.vue +148 -148
  34. package/src/common/app-input-search/AppInputSearch.vue +174 -174
  35. package/src/common/app-layout/AppLayout.vue +84 -84
  36. package/src/common/app-layout/components/AppLayoutHeader.vue +273 -273
  37. package/src/common/app-layout/components/AppLayoutPage.vue +16 -16
  38. package/src/common/app-loader/index.vue +43 -43
  39. package/src/common/app-page-layout/AppPageLayout.vue +122 -122
  40. package/src/common/app-select/AppSelect.vue +157 -157
  41. package/src/common/app-sheet/AppSheet.vue +120 -120
  42. package/src/common/app-sidebar/AppSidebar.vue +168 -168
  43. package/src/common/app-sidebar/components/SidebarMenu.vue +37 -37
  44. package/src/common/app-sidebar/components/SidebarMenuItem.vue +148 -148
  45. package/src/common/app-table/components/TablePagination.vue +152 -152
  46. package/src/common/app-table/controllers/useColumnSelector.ts +38 -38
  47. package/src/common/app-table/controllers/useTableModel.ts +93 -93
  48. package/src/common/app-toggle/AppToggle.vue +24 -24
  49. package/src/common/app-wrapper/AppWrapper.vue +28 -28
  50. package/src/global.d.ts +1 -1
  51. package/src/icons/components/arrow-down-icon.vue +25 -25
  52. package/src/icons/components/arrow-frame-icon.vue +19 -19
  53. package/src/icons/components/arrow-square.vue +22 -22
  54. package/src/icons/components/table-filter-icon.vue +30 -30
  55. package/src/icons/dialogs/RemoveIcon.vue +12 -12
  56. package/src/icons/dialogs/SafetyIcon.vue +12 -12
  57. package/src/icons/header/NotificationIcon.vue +18 -18
  58. package/src/icons/header/PersonIcon.vue +11 -11
  59. package/src/icons/header/SettingIcon.vue +14 -14
  60. package/src/icons/header/flashIcon.vue +24 -24
  61. package/src/icons/header/searchStatusIcon.vue +24 -24
  62. package/src/icons/header/smallCapsIcon.vue +34 -34
  63. package/src/icons/sidebar/assign-module-icon.vue +36 -36
  64. package/src/icons/sidebar/instrument-history-icon.vue +32 -32
  65. package/src/icons/sidebar/instrument-order-icon.vue +38 -38
  66. package/src/icons/sidebar/instrument-work-zone-icon.vue +18 -18
  67. package/src/icons/sidebar/instruments-icon.vue +45 -45
  68. package/src/icons/sidebar/logo-icon.vue +15 -15
  69. package/src/icons/sidebar/logout-icon.vue +13 -13
  70. package/src/icons/sidebar/modules-icon.vue +16 -16
  71. package/src/icons/sidebar/notifications-icon.vue +24 -24
  72. package/src/icons/sidebar/order-icon.vue +44 -44
  73. package/src/icons/sidebar/pass-icon.vue +38 -38
  74. package/src/icons/sidebar/positions-icon.vue +42 -42
  75. package/src/icons/sidebar/preorder-icon.vue +19 -19
  76. package/src/icons/sidebar/projects-icon.vue +31 -31
  77. package/src/icons/sidebar/repair-object-icon.vue +18 -18
  78. package/src/icons/sidebar/repairs-icon.vue +20 -20
  79. package/src/icons/sidebar/roles-icon.vue +26 -26
  80. package/src/icons/sidebar/status-history-icon.vue +24 -24
  81. package/src/icons/sidebar/tasks-icon.vue +28 -28
  82. package/src/icons/sidebar/tasks_tasks-icon.vue +39 -39
  83. package/src/icons/sidebar/tasks_today-icon.vue +27 -27
  84. package/src/icons/sidebar/teams-icon.vue +32 -32
  85. package/src/icons/sidebar/user-icon.vue +18 -18
  86. package/src/icons/sidebar/users-icon.vue +46 -46
  87. package/src/icons/sidebar/videosources-icon.vue +19 -19
  88. package/src/icons/sidebar/videowall-icon.vue +13 -13
  89. package/src/icons/sidebar/videozones-icon.vue +21 -21
  90. package/src/icons/sidebar/warehouses-icon.vue +43 -43
  91. package/src/icons/sidebar/workshop-icon.vue +100 -100
  92. package/src/icons/sidebar/workzones-icon.vue +22 -22
  93. package/src/icons/task/attention-icon.vue +13 -13
  94. package/src/icons/task/clock-icon.vue +10 -10
  95. package/src/icons/task/delete-icon.vue +10 -10
  96. package/src/icons/task/fire-icon.vue +16 -16
  97. package/src/index.ts +123 -123
  98. package/src/main.ts +28 -28
  99. package/src/quasar-user-options.ts +17 -17
  100. package/src/router/index.ts +10 -10
  101. package/src/shared/styles/general.css +124 -124
  102. package/src/shims-vue.d.ts +5 -5
  103. package/src/utils/confirm.ts +12 -12
  104. package/src/utils/faceApiHelper.ts +132 -137
  105. package/src/utils/helpers.ts +59 -59
  106. package/src/utils/notification.ts +9 -9
  107. package/dist/types/api/services/ComentsServise.d.ts +0 -10
  108. package/dist/types/api/services/PhotoService.d.ts +0 -53
  109. package/dist/types/api/types/Api_Users.d.ts +0 -43
package/src/main.ts CHANGED
@@ -1,28 +1,28 @@
1
- import { createApp } from 'vue'
2
- import { Quasar, quasarUserOptions } from './quasar-user-options'
3
- import router from './router/index'
4
-
5
- import '@quasar/extras/material-icons/material-icons.css'
6
- import 'quasar/src/css/index.sass'
7
-
8
- import '@/shared/styles/general.css'
9
-
10
- import App from './App.vue'
11
-
12
- const app = createApp(App)
13
-
14
- //@ts-ignore
15
- app.use(Quasar, quasarUserOptions)
16
-
17
- app.use(router)
18
- app.mount('#app')
19
-
20
- const observerErrRe = /^ResizeObserver loop completed/
21
-
22
- const originalConsoleError = console.error
23
- console.error = (...args) => {
24
- if (typeof args[0] === 'string' && observerErrRe.test(args[0])) {
25
- return
26
- }
27
- originalConsoleError(...args)
28
- }
1
+ import { createApp } from 'vue'
2
+ import { Quasar, quasarUserOptions } from './quasar-user-options'
3
+ import router from './router/index'
4
+
5
+ import '@quasar/extras/material-icons/material-icons.css'
6
+ import 'quasar/src/css/index.sass'
7
+
8
+ import '@/shared/styles/general.css'
9
+
10
+ import App from './App.vue'
11
+
12
+ const app = createApp(App)
13
+
14
+ //@ts-ignore
15
+ app.use(Quasar, quasarUserOptions)
16
+
17
+ app.use(router)
18
+ app.mount('#app')
19
+
20
+ const observerErrRe = /^ResizeObserver loop completed/
21
+
22
+ const originalConsoleError = console.error
23
+ console.error = (...args) => {
24
+ if (typeof args[0] === 'string' && observerErrRe.test(args[0])) {
25
+ return
26
+ }
27
+ originalConsoleError(...args)
28
+ }
@@ -1,17 +1,17 @@
1
- import { Quasar, Notify, Loading, Dialog } from 'quasar'
2
-
3
- import 'quasar/src/css/index.sass'
4
- import '@quasar/extras/roboto-font/roboto-font.css'
5
- import '@quasar/extras/material-icons/material-icons.css'
6
- import '@quasar/extras/material-icons-outlined/material-icons-outlined.css'
7
- import '@quasar/extras/mdi-v7/mdi-v7.css'
8
-
9
- const quasarUserOptions = {
10
- plugins: {
11
- Notify,
12
- Loading,
13
- Dialog,
14
- },
15
- }
16
-
17
- export { Quasar, quasarUserOptions }
1
+ import { Quasar, Notify, Loading, Dialog } from 'quasar'
2
+
3
+ import 'quasar/src/css/index.sass'
4
+ import '@quasar/extras/roboto-font/roboto-font.css'
5
+ import '@quasar/extras/material-icons/material-icons.css'
6
+ import '@quasar/extras/material-icons-outlined/material-icons-outlined.css'
7
+ import '@quasar/extras/mdi-v7/mdi-v7.css'
8
+
9
+ const quasarUserOptions = {
10
+ plugins: {
11
+ Notify,
12
+ Loading,
13
+ Dialog,
14
+ },
15
+ }
16
+
17
+ export { Quasar, quasarUserOptions }
@@ -1,10 +1,10 @@
1
- import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
2
-
3
- const routes: RouteRecordRaw[] = []
4
-
5
- const router = createRouter({
6
- history: createWebHistory(),
7
- routes,
8
- })
9
-
10
- export default router
1
+ import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
2
+
3
+ const routes: RouteRecordRaw[] = []
4
+
5
+ const router = createRouter({
6
+ history: createWebHistory(),
7
+ routes,
8
+ })
9
+
10
+ export default router
@@ -1,124 +1,124 @@
1
- :root {
2
- --main-header-height: 73px;
3
- --main-footer-height: 66px;
4
- --sidebar-width-max: 250px;
5
- --sidebar-width-min: 66px;
6
- }
7
-
8
- /*border-radius*/
9
- :root {
10
- --border-radius-xxs: 4px;
11
- --border-radius-xs: 8px;
12
- --border-radius-s: 12px;
13
- --border-radius-m: 16px;
14
- }
15
-
16
- /*color*/
17
- :root {
18
- --g-blue: #3f8cff;
19
- --g-blue-light: #e4efff;
20
- --g-blue-dark: #1c75ff;
21
- --g-green: #00d097;
22
- --g-green-light: #e0f9f2;
23
- --g-green-dark: #b8f8e7;
24
- --g-red: #ff192d;
25
- --g-red-light: #fdecee;
26
- --g-red-dark: #ffdcde;
27
- --g-grey-100: #d8e0f0;
28
-
29
- --g-font-color: #0a1629;
30
- --g-font-grey-color: #b9c0c7;
31
- --g-font-secondary-color: #7d8592;
32
-
33
- --g-grey-background: #ced5e0;
34
- --g-grey-hover-background: #9fa5af;
35
- --g-secondary-background: #f4f9fd;
36
- --g-thirty-background: #c8cbcf;
37
-
38
- --g-fire-color-1: #fee7e7;
39
- --g-fire-color-2: #fed4d5;
40
- --g-fire-color-3: #fcc0c0;
41
- --g-fire-color-4: #f9a2a2;
42
- --g-fire-color-5: #f97d7e;
43
- --g-fire-color-6: #f65160;
44
- --g-fire-color-7: #ff192d;
45
- --g-fire-color-8: #ab0514;
46
- --g-fire-color-9: #6e000a;
47
- }
48
-
49
- * {
50
- margin: 0;
51
- padding: 0;
52
- }
53
-
54
- button:active,
55
- button:focus {
56
- outline: none !important;
57
- }
58
-
59
- html {
60
- font-family: 'NunitoSansFont', sans-serif !important;
61
- }
62
-
63
- .ant-dropdown {
64
- z-index: 10000;
65
- .content {
66
- z-index: 10000;
67
- }
68
- }
69
-
70
- @font-face {
71
- font-family: 'NunitoSansFont';
72
- src: local('NunitoSansFont-Regular'), url('../fonts/NunitoSansFont.ttf') format('truetype');
73
- font-weight: 400;
74
- font-style: normal;
75
- }
76
-
77
- @font-face {
78
- font-family: 'NunitoSansFont';
79
- src: local('NunitoSansFont-Bold'), url('../fonts/NunitoSans_7pt-Bold.ttf') format('truetype');
80
- font-weight: 700;
81
- font-style: normal;
82
- }
83
-
84
- @font-face {
85
- font-family: 'Montserrat';
86
- src: local('Montserrat-Regular'), url('../fonts/Montserrat.ttf') format('truetype');
87
- font-weight: 400;
88
- font-style: normal;
89
- }
90
-
91
- @font-face {
92
- font-family: 'Montserrat';
93
- src: local('Montserrat-Bold'), url('../fonts/Montserrat-Bold.ttf') format('truetype');
94
- font-weight: 700;
95
- font-style: normal;
96
- }
97
-
98
- @font-face {
99
- font-family: 'Inter';
100
- src: local('Inter-Regular'), url('../fonts/Inter_18pt-Regular.ttf') format('truetype');
101
- font-weight: 400;
102
- font-style: normal;
103
- }
104
-
105
- @font-face {
106
- font-family: 'Inter';
107
- src: local('Inter-SemiBold'), url('../fonts/Inter_18pt-SemiBold.ttf') format('truetype');
108
- font-weight: 600;
109
- font-style: normal;
110
- }
111
-
112
- @font-face {
113
- font-family: 'Inter';
114
- src: local('Inter-Bold'), url('../fonts/Inter_18pt-Bold.ttf') format('truetype');
115
- font-weight: 700;
116
- font-style: normal;
117
- }
118
-
119
- @font-face {
120
- font-family: 'Inter';
121
- src: local('Inter-Black'), url('../fonts/Inter_18pt-Black.ttf') format('truetype');
122
- font-weight: 900;
123
- font-style: normal;
124
- }
1
+ :root {
2
+ --main-header-height: 73px;
3
+ --main-footer-height: 66px;
4
+ --sidebar-width-max: 250px;
5
+ --sidebar-width-min: 66px;
6
+ }
7
+
8
+ /*border-radius*/
9
+ :root {
10
+ --border-radius-xxs: 4px;
11
+ --border-radius-xs: 8px;
12
+ --border-radius-s: 12px;
13
+ --border-radius-m: 16px;
14
+ }
15
+
16
+ /*color*/
17
+ :root {
18
+ --g-blue: #3f8cff;
19
+ --g-blue-light: #e4efff;
20
+ --g-blue-dark: #1c75ff;
21
+ --g-green: #00d097;
22
+ --g-green-light: #e0f9f2;
23
+ --g-green-dark: #b8f8e7;
24
+ --g-red: #ff192d;
25
+ --g-red-light: #fdecee;
26
+ --g-red-dark: #ffdcde;
27
+ --g-grey-100: #d8e0f0;
28
+
29
+ --g-font-color: #0a1629;
30
+ --g-font-grey-color: #b9c0c7;
31
+ --g-font-secondary-color: #7d8592;
32
+
33
+ --g-grey-background: #ced5e0;
34
+ --g-grey-hover-background: #9fa5af;
35
+ --g-secondary-background: #f4f9fd;
36
+ --g-thirty-background: #c8cbcf;
37
+
38
+ --g-fire-color-1: #fee7e7;
39
+ --g-fire-color-2: #fed4d5;
40
+ --g-fire-color-3: #fcc0c0;
41
+ --g-fire-color-4: #f9a2a2;
42
+ --g-fire-color-5: #f97d7e;
43
+ --g-fire-color-6: #f65160;
44
+ --g-fire-color-7: #ff192d;
45
+ --g-fire-color-8: #ab0514;
46
+ --g-fire-color-9: #6e000a;
47
+ }
48
+
49
+ * {
50
+ margin: 0;
51
+ padding: 0;
52
+ }
53
+
54
+ button:active,
55
+ button:focus {
56
+ outline: none !important;
57
+ }
58
+
59
+ html {
60
+ font-family: 'NunitoSansFont', sans-serif !important;
61
+ }
62
+
63
+ .ant-dropdown {
64
+ z-index: 10000;
65
+ .content {
66
+ z-index: 10000;
67
+ }
68
+ }
69
+
70
+ @font-face {
71
+ font-family: 'NunitoSansFont';
72
+ src: local('NunitoSansFont-Regular'), url('../fonts/NunitoSansFont.ttf') format('truetype');
73
+ font-weight: 400;
74
+ font-style: normal;
75
+ }
76
+
77
+ @font-face {
78
+ font-family: 'NunitoSansFont';
79
+ src: local('NunitoSansFont-Bold'), url('../fonts/NunitoSans_7pt-Bold.ttf') format('truetype');
80
+ font-weight: 700;
81
+ font-style: normal;
82
+ }
83
+
84
+ @font-face {
85
+ font-family: 'Montserrat';
86
+ src: local('Montserrat-Regular'), url('../fonts/Montserrat.ttf') format('truetype');
87
+ font-weight: 400;
88
+ font-style: normal;
89
+ }
90
+
91
+ @font-face {
92
+ font-family: 'Montserrat';
93
+ src: local('Montserrat-Bold'), url('../fonts/Montserrat-Bold.ttf') format('truetype');
94
+ font-weight: 700;
95
+ font-style: normal;
96
+ }
97
+
98
+ @font-face {
99
+ font-family: 'Inter';
100
+ src: local('Inter-Regular'), url('../fonts/Inter_18pt-Regular.ttf') format('truetype');
101
+ font-weight: 400;
102
+ font-style: normal;
103
+ }
104
+
105
+ @font-face {
106
+ font-family: 'Inter';
107
+ src: local('Inter-SemiBold'), url('../fonts/Inter_18pt-SemiBold.ttf') format('truetype');
108
+ font-weight: 600;
109
+ font-style: normal;
110
+ }
111
+
112
+ @font-face {
113
+ font-family: 'Inter';
114
+ src: local('Inter-Bold'), url('../fonts/Inter_18pt-Bold.ttf') format('truetype');
115
+ font-weight: 700;
116
+ font-style: normal;
117
+ }
118
+
119
+ @font-face {
120
+ font-family: 'Inter';
121
+ src: local('Inter-Black'), url('../fonts/Inter_18pt-Black.ttf') format('truetype');
122
+ font-weight: 900;
123
+ font-style: normal;
124
+ }
@@ -1,5 +1,5 @@
1
- declare module '*.vue' {
2
- import { DefineComponent } from 'vue'
3
- const component: DefineComponent<{}, {}, any>
4
- export default component
5
- }
1
+ declare module '*.vue' {
2
+ import { DefineComponent } from 'vue'
3
+ const component: DefineComponent<{}, {}, any>
4
+ export default component
5
+ }
@@ -1,12 +1,12 @@
1
- import { defineAsyncComponent } from 'vue'
2
- import { useQuasar } from 'quasar'
3
- const $q = useQuasar()
4
-
5
- const AppConfirmDialog = defineAsyncComponent(() => import('@/common/app-dialogs/AppConfirmDialog.vue'))
6
-
7
- export const appConfirm = (content: string, type: 'delete' | 'edit') => {
8
- return $q.dialog({
9
- component: AppConfirmDialog,
10
- componentProps: { content, type },
11
- })
12
- }
1
+ import { defineAsyncComponent } from 'vue'
2
+ import { useQuasar } from 'quasar'
3
+ const $q = useQuasar()
4
+
5
+ const AppConfirmDialog = defineAsyncComponent(() => import('@/common/app-dialogs/AppConfirmDialog.vue'))
6
+
7
+ export const appConfirm = (content: string, type: 'delete' | 'edit') => {
8
+ return $q.dialog({
9
+ component: AppConfirmDialog,
10
+ componentProps: { content, type },
11
+ })
12
+ }
@@ -1,137 +1,132 @@
1
- import * as faceapi from 'face-api.js'
2
-
3
- class FaceApiHelper {
4
- // async getFaceSnapshot(inputImage: any, box: any) {
5
- // const regionsToExtract = [new faceapi.Rect(box.x, box.y, box.width, box.height)]
6
- // const faceImages = await faceapi.extractFaces(inputImage, regionsToExtract)
7
- // if (faceImages.length) {
8
- // const dataUrl = faceImages[0].toDataURL('image/jpeg')
9
- // photo.value = dataUrl.replace(/^data:image\/\w+;base64,/, '')
10
- // }
11
- // }
12
-
13
- // Метод настройки конфига для стрима
14
- getVideoStreamConfig(width: number, height: number) {
15
- return {
16
- audio: false,
17
- video: {
18
- width: { min: width, ideal: width },
19
- height: { min: height, ideal: height },
20
- facingMode: 'environment', // или 'user' для фронтальной камеры
21
- },
22
- }
23
- }
24
-
25
- // Метод для настройки рамки, где должно помещаться лицо
26
- getContourCoordinate(width: number, height: number) {
27
- return {
28
- x: width * 0.25,
29
- y: height * 0.05,
30
- width: width * 0.5,
31
- height: height * 0.9,
32
- }
33
- }
34
-
35
- getBoxData(box: any) {
36
- if (!box) return null
37
- return {
38
- x: box.x,
39
- y: box.y,
40
- width: box.width,
41
- height: box.height,
42
- }
43
- }
44
-
45
- setStylesForCanvas(canvasContainer: any) {
46
- canvasContainer.width = '100%'
47
- canvasContainer.height = '100%'
48
- canvasContainer.style.position = 'absolute'
49
- canvasContainer.style.top = '0'
50
- canvasContainer.style.left = '0'
51
- }
52
-
53
- // Метод для рассчёта того, что лицо полностью помещается в рамке
54
- checkFaceInclusion(frame: any, face: any) {
55
- if (!frame || !face) return false
56
-
57
- if (face.width > frame.width || face.height > frame.height) {
58
- return false
59
- }
60
-
61
- const faceXmin = face.x
62
- const faceXmax = face.x + face.width
63
- const faceYmin = face.y
64
- const faceYmax = face.y + face.height
65
-
66
- const frameXmin = frame.x
67
- const frameXmax = frame.x + frame.width
68
- const frameYmin = frame.y
69
- const frameYmax = frame.y + frame.height
70
-
71
- return faceXmin >= frameXmin && faceXmax <= frameXmax && faceYmin >= frameYmin && faceYmax <= frameYmax
72
- }
73
-
74
- async getFaceDetections(videoRef: any) {
75
- if (!videoRef) return []
76
- return faceapi
77
- .detectAllFaces(videoRef, new faceapi.TinyFaceDetectorOptions())
78
- .withFaceLandmarks()
79
- .withFaceExpressions()
80
- }
81
-
82
- getCanvas(videoRef: any) {
83
- return faceapi.createCanvasFromMedia(videoRef)
84
- }
85
-
86
- getResizedAndDetection(canvas: any, detections: any, ctx: any, videoWidth: number, videoHeight: number) {
87
- faceapi.matchDimensions(canvas, { width: videoWidth, height: videoHeight })
88
-
89
- const resized = faceapi.resizeResults(detections, {
90
- width: videoWidth,
91
- height: videoHeight,
92
- })
93
-
94
- ctx.clearRect(0, 0, videoWidth, videoHeight)
95
-
96
- faceapi.draw.drawDetections(canvas, resized)
97
- faceapi.draw.drawFaceLandmarks(canvas, resized)
98
- faceapi.draw.drawFaceExpressions(canvas, resized)
99
- }
100
-
101
- async getFaceSnapshot(inputImage: any, box: any) {
102
- const regionsToExtract = [new faceapi.Rect(box.x, box.y, box.width, box.height)]
103
- const faceImages = await faceapi.extractFaces(inputImage, regionsToExtract)
104
-
105
- if (faceImages.length) {
106
- const dataUrl = faceImages[0].toDataURL('image/jpeg')
107
- return dataUrl.replace(/^data:image\/\w+;base64,/, '')
108
- }
109
-
110
- return null
111
- }
112
-
113
- async initModels() {
114
- let date = new Date()
115
- console.log(date)
116
- try {
117
- await Promise.all([
118
- faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
119
- faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
120
- faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
121
- faceapi.nets.faceExpressionNet.loadFromUri('/models'),
122
- //faceapi.nets.ssdMobilenetv1.loadFromUri('/models'),
123
- ])
124
- } catch (error) {
125
- console.error(error)
126
- }
127
- date = new Date()
128
- console.log(date)
129
- }
130
- }
131
-
132
- let helper: FaceApiHelper
133
-
134
- export default function useFaceApiHelper() {
135
- if (!helper) helper = new FaceApiHelper()
136
- return helper
137
- }
1
+ import * as faceapi from 'face-api.js'
2
+
3
+ class FaceApiHelper {
4
+ // async getFaceSnapshot(inputImage: any, box: any) {
5
+ // const regionsToExtract = [new faceapi.Rect(box.x, box.y, box.width, box.height)]
6
+ // const faceImages = await faceapi.extractFaces(inputImage, regionsToExtract)
7
+ // if (faceImages.length) {
8
+ // const dataUrl = faceImages[0].toDataURL('image/jpeg')
9
+ // photo.value = dataUrl.replace(/^data:image\/\w+;base64,/, '')
10
+ // }
11
+ // }
12
+
13
+ // Метод настройки конфига для стрима
14
+ getVideoStreamConfig(width: number, height: number) {
15
+ return {
16
+ audio: false,
17
+ video: {
18
+ width: { min: width, ideal: width },
19
+ height: { min: height, ideal: height },
20
+ facingMode: 'environment', // или 'user' для фронтальной камеры
21
+ },
22
+ }
23
+ }
24
+
25
+ // Метод для настройки рамки, где должно помещаться лицо
26
+ getContourCoordinate(width: number, height: number) {
27
+ return {
28
+ x: width * 0.25,
29
+ y: height * 0.05,
30
+ width: width * 0.5,
31
+ height: height * 0.9,
32
+ }
33
+ }
34
+
35
+ getBoxData(box: any) {
36
+ if (!box) return null
37
+ return {
38
+ x: box.x,
39
+ y: box.y,
40
+ width: box.width,
41
+ height: box.height,
42
+ }
43
+ }
44
+
45
+ setStylesForCanvas(canvasContainer: any) {
46
+ canvasContainer.width = '100%'
47
+ canvasContainer.height = '100%'
48
+ canvasContainer.style.position = 'absolute'
49
+ canvasContainer.style.top = '0'
50
+ canvasContainer.style.left = '0'
51
+ }
52
+
53
+ // Метод для рассчёта того, что лицо полностью помещается в рамке
54
+ checkFaceInclusion(frame: any, face: any) {
55
+ if (!frame || !face) return false
56
+
57
+ if (face.width > frame.width || face.height > frame.height) {
58
+ return false
59
+ }
60
+
61
+ const faceXmin = face.x
62
+ const faceXmax = face.x + face.width
63
+ const faceYmin = face.y
64
+ const faceYmax = face.y + face.height
65
+
66
+ const frameXmin = frame.x
67
+ const frameXmax = frame.x + frame.width
68
+ const frameYmin = frame.y
69
+ const frameYmax = frame.y + frame.height
70
+
71
+ return faceXmin >= frameXmin && faceXmax <= frameXmax && faceYmin >= frameYmin && faceYmax <= frameYmax
72
+ }
73
+
74
+ async getFaceDetections(videoRef: any, inputSize: number) {
75
+ if (!videoRef) return []
76
+ const options = new faceapi.TinyFaceDetectorOptions({ inputSize })
77
+ return faceapi.detectSingleFace(videoRef, options).withFaceLandmarks(true)
78
+ }
79
+
80
+ getCanvas(videoRef: any) {
81
+ return faceapi.createCanvasFromMedia(videoRef)
82
+ }
83
+
84
+ getResizedAndDetection(canvas: any, detections: any, ctx: any, videoWidth: number, videoHeight: number) {
85
+ faceapi.matchDimensions(canvas, { width: videoWidth, height: videoHeight })
86
+
87
+ const resized = faceapi.resizeResults(detections, {
88
+ width: videoWidth,
89
+ height: videoHeight,
90
+ })
91
+
92
+ ctx.clearRect(0, 0, videoWidth, videoHeight)
93
+
94
+ faceapi.draw.drawDetections(canvas, resized)
95
+ faceapi.draw.drawFaceLandmarks(canvas, resized)
96
+ //faceapi.draw.drawFaceExpressions(canvas, resized)
97
+ }
98
+
99
+ async getFaceSnapshot(inputImage: any, box: any) {
100
+ const regionsToExtract = [new faceapi.Rect(box.x, box.y, box.width, box.height)]
101
+ const faceImages = await faceapi.extractFaces(inputImage, regionsToExtract)
102
+
103
+ if (faceImages.length) {
104
+ const dataUrl = faceImages[0].toDataURL('image/jpeg')
105
+ return dataUrl.replace(/^data:image\/\w+;base64,/, '')
106
+ }
107
+
108
+ return null
109
+ }
110
+
111
+ async initModels() {
112
+ let date = new Date()
113
+ console.log(date)
114
+ try {
115
+ await Promise.all([
116
+ faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
117
+ faceapi.nets.faceLandmark68TinyNet.loadFromUri('/models'),
118
+ ])
119
+ } catch (error) {
120
+ console.error(error)
121
+ }
122
+ date = new Date()
123
+ console.log(date)
124
+ }
125
+ }
126
+
127
+ let helper: FaceApiHelper
128
+
129
+ export default function useFaceApiHelper() {
130
+ if (!helper) helper = new FaceApiHelper()
131
+ return helper
132
+ }