shared-ritm 1.2.80 → 1.2.82
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/README.md +103 -103
- package/dist/index.css +1 -1
- package/dist/shared-ritm.es.js +9412 -8849
- package/dist/shared-ritm.umd.js +450 -450
- package/dist/types/api/services/UserService.d.ts +10 -1
- package/dist/types/api/types/Api_Service.d.ts +1 -1
- package/dist/types/api/types/Api_User.d.ts +11 -0
- package/dist/types/common/app-table/controllers/useTableModel.d.ts +1 -1
- package/dist/types/index.d.ts +41 -40
- package/package.json +64 -64
- package/src/api/services/PhotoService.ts +137 -137
- package/src/api/services/RepairsService.ts +119 -119
- package/src/api/services/UserService.ts +32 -19
- package/src/api/types/Api_Controls.ts +72 -72
- package/src/api/types/Api_Files.ts +1 -1
- package/src/api/types/Api_Instruments.ts +98 -98
- package/src/api/types/Api_Projects.ts +55 -55
- package/src/api/types/Api_Repairs.ts +115 -115
- package/src/api/types/Api_Service.ts +1 -1
- package/src/api/types/Api_User.ts +57 -44
- package/src/common/app-checkbox/AppCheckbox.vue +26 -26
- package/src/common/app-datepicker/AppDatepicker.vue +165 -165
- package/src/common/app-dialogs/AppConfirmDialog.vue +99 -99
- package/src/common/app-dropdown/AppDropdown.vue +31 -31
- package/src/common/app-input/AppInput.vue +148 -148
- package/src/common/app-input-new/AppInputNew.vue +152 -152
- package/src/common/app-select/AppSelect.vue +157 -157
- package/src/common/app-sheet/AppSheet.vue +120 -120
- package/src/common/app-sheet-new/AppSheetNew.vue +256 -0
- package/src/common/app-sidebar/components/SidebarMenuItem.vue +148 -148
- package/src/common/app-table/AppTable.vue +301 -297
- package/src/common/app-table/AppTableLayout.vue +126 -111
- package/src/common/app-table/components/ModalSelect.vue +270 -270
- package/src/common/app-table/components/TableModal.vue +329 -329
- package/src/common/app-table/components/TablePagination.vue +152 -152
- package/src/common/app-table/components/TableSearch.vue +76 -76
- package/src/common/app-table/controllers/useBaseTable.ts +42 -42
- package/src/common/app-table/controllers/useColumnSelector.ts +38 -38
- package/src/common/app-table/controllers/useTableModel.ts +93 -93
- package/src/common/app-toggle/AppToggle.vue +24 -24
- package/src/common/app-wrapper/AppWrapper.vue +28 -28
- package/src/icons/components/table-filter-icon.vue +30 -30
- package/src/icons/dialogs/RemoveIcon.vue +12 -12
- package/src/icons/dialogs/SafetyIcon.vue +12 -12
- package/src/icons/task/attention-icon.vue +13 -13
- package/src/icons/task/clock-icon.vue +10 -10
- package/src/icons/task/delete-icon.vue +10 -10
- package/src/icons/task/fire-icon.vue +16 -16
- package/src/index.ts +41 -39
- package/src/main.ts +28 -28
- package/src/shared/styles/general.css +125 -125
- package/src/styles/variables.sass +12 -12
- package/src/utils/confirm.ts +12 -12
- package/src/utils/helpers.ts +58 -58
- package/src/utils/notification.ts +9 -9
- package/dist/types/api/types/Api_Users.d.ts +0 -43
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import ApiService from '@/api/settings/ApiService';
|
|
2
|
-
import { Api_User } from '@/api/types/Api_User';
|
|
2
|
+
import { Api_User, Api_User_Role } from '@/api/types/Api_User';
|
|
3
|
+
import { ResponseApi } from '@/api/types/Api_Service';
|
|
3
4
|
declare class UserService extends ApiService {
|
|
4
5
|
editUser({ id, model }: {
|
|
5
6
|
id: string;
|
|
6
7
|
model: any;
|
|
7
8
|
}): Promise<Api_User>;
|
|
8
9
|
getUser(id: string): Promise<Api_User>;
|
|
10
|
+
createUser(model: Partial<Api_User>): Promise<Api_User>;
|
|
11
|
+
deleteUser(id: string): Promise<{
|
|
12
|
+
data: boolean;
|
|
13
|
+
status: number;
|
|
14
|
+
}>;
|
|
15
|
+
getRoles(params?: {
|
|
16
|
+
per_page?: number;
|
|
17
|
+
}): Promise<ResponseApi<Api_User_Role[]>>;
|
|
9
18
|
}
|
|
10
19
|
export default function useUserService(): UserService;
|
|
11
20
|
export {};
|
|
@@ -40,3 +40,14 @@ export type Api_User = {
|
|
|
40
40
|
teams: Api_User_Team[];
|
|
41
41
|
photos: Api_User_Photo[];
|
|
42
42
|
};
|
|
43
|
+
export type Api_User_Permission = {
|
|
44
|
+
id: string;
|
|
45
|
+
name: string;
|
|
46
|
+
display_name: string;
|
|
47
|
+
};
|
|
48
|
+
export type Api_User_Role = {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
display_name: string;
|
|
52
|
+
permissions?: Api_User_Permission[];
|
|
53
|
+
};
|
|
@@ -4,7 +4,7 @@ export interface TableColumn {
|
|
|
4
4
|
label: string;
|
|
5
5
|
style?: string;
|
|
6
6
|
headerStyle?: string;
|
|
7
|
-
field
|
|
7
|
+
field?: string | ((row: any) => any);
|
|
8
8
|
sortable?: boolean;
|
|
9
9
|
filterType?: 'single' | 'multi' | null;
|
|
10
10
|
align?: 'left' | 'center' | 'right';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
import '
|
|
2
|
-
import AppButton from '
|
|
3
|
-
import AppCheckbox from '
|
|
4
|
-
import AppDatePicker from '
|
|
5
|
-
import AppDatepicker from '
|
|
6
|
-
import AppInput from '
|
|
7
|
-
import AppInputNew from '
|
|
8
|
-
import AppInputSearch from '
|
|
9
|
-
import AppLayout from '
|
|
10
|
-
import AppLayoutHeader from '
|
|
11
|
-
import AppLayoutPage from '
|
|
12
|
-
import AppLoader from '
|
|
13
|
-
import AppSelect from '
|
|
14
|
-
import AppSheet from '
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import
|
|
31
|
-
import
|
|
32
|
-
import
|
|
33
|
-
import
|
|
34
|
-
import
|
|
35
|
-
import
|
|
36
|
-
import
|
|
37
|
-
import
|
|
38
|
-
import
|
|
39
|
-
import
|
|
40
|
-
|
|
1
|
+
import '@/shared/styles/general.css';
|
|
2
|
+
import AppButton from '@/common/app-button/AppButton.vue';
|
|
3
|
+
import AppCheckbox from '@/common/app-checkbox/AppCheckbox.vue';
|
|
4
|
+
import AppDatePicker from '@/common/app-date-picker/AppDatePicker.vue';
|
|
5
|
+
import AppDatepicker from '@/common/app-datepicker/AppDatepicker.vue';
|
|
6
|
+
import AppInput from '@/common/app-input/AppInput.vue';
|
|
7
|
+
import AppInputNew from '@/common/app-input-new/AppInputNew.vue';
|
|
8
|
+
import AppInputSearch from '@/common/app-input-search/AppInputSearch.vue';
|
|
9
|
+
import AppLayout from '@/common/app-layout/AppLayout.vue';
|
|
10
|
+
import AppLayoutHeader from '@/common/app-layout/components/AppLayoutHeader.vue';
|
|
11
|
+
import AppLayoutPage from '@/common/app-layout/components/AppLayoutPage.vue';
|
|
12
|
+
import AppLoader from '@/common/app-loader/index.vue';
|
|
13
|
+
import AppSelect from '@/common/app-select/AppSelect.vue';
|
|
14
|
+
import AppSheet from '@/common/app-sheet/AppSheet.vue';
|
|
15
|
+
import AppSheetNew from '@/common/app-sheet-new/AppSheetNew.vue';
|
|
16
|
+
import AppSidebar from '@/common/app-sidebar/AppSidebar.vue';
|
|
17
|
+
import AppToggle from '@/common/app-toggle/AppToggle.vue';
|
|
18
|
+
import AppWrapper from '@/common/app-wrapper/AppWrapper.vue';
|
|
19
|
+
import AppConfirmDialog from '@/common/app-dialogs/AppConfirmDialog.vue';
|
|
20
|
+
import AppDropdown from '@/common/app-dropdown/AppDropdown.vue';
|
|
21
|
+
import AppTablePagination from '@/common/app-table/components/TablePagination.vue';
|
|
22
|
+
import AppTableSearch from '@/common/app-table/components/TableSearch.vue';
|
|
23
|
+
import AppTableModal from '@/common/app-table/components/TableModal.vue';
|
|
24
|
+
import AppTable from '@/common/app-table/AppTable.vue';
|
|
25
|
+
import AppTableLayout from '@/common/app-table/AppTableLayout.vue';
|
|
26
|
+
import AppModalSelect from '@/common/app-table/components/ModalSelect.vue';
|
|
27
|
+
import ApiService from '@/api/settings/ApiService';
|
|
28
|
+
import useGanttService from '@/api/services/GanttService';
|
|
29
|
+
import useMetricsService from '@/api/services/MetricsService';
|
|
30
|
+
import useProjectsService from '@/api/services/ProjectsService';
|
|
31
|
+
import useRepairsService from '@/api/services/RepairsService';
|
|
32
|
+
import useTasksService from '@/api/services/TasksService';
|
|
33
|
+
import useAuthService from '@/api/services/AuthService';
|
|
34
|
+
import useFileService from '@/api/services/FileService';
|
|
35
|
+
import useVideoService from '@/api/services/VideoService';
|
|
36
|
+
import useUserService from '@/api/services/UserService';
|
|
37
|
+
import usePhotoService from '@/api/services/PhotoService';
|
|
38
|
+
import useInstrumentsService from '@/api/services/InstrumentsService';
|
|
39
|
+
import useControlsService from '@/api/services/ControlsService';
|
|
40
|
+
import useSearchService from '@/api/services/SearchService';
|
|
41
|
+
export { AppButton, AppCheckbox, AppDatepicker, AppDatePicker, AppInput, AppInputNew, AppInputSearch, AppLayout, AppLayoutHeader, AppLayoutPage, AppLoader, AppSelect, AppSheet, AppSheetNew, AppSidebar, AppToggle, AppWrapper, AppConfirmDialog, AppDropdown, AppTablePagination, AppTableSearch, AppTableModal, AppTable, AppTableLayout, AppModalSelect, };
|
|
41
42
|
export { ApiService, useAuthService, useGanttService, useMetricsService, useProjectsService, useRepairsService, useTasksService, useFileService, useControlsService, useVideoService, useUserService, usePhotoService, useInstrumentsService, useSearchService, };
|
|
42
43
|
export { useBaseTable } from './common/app-table/controllers/useBaseTable';
|
|
43
44
|
export { useTableModel } from './common/app-table/controllers/useTableModel';
|
package/package.json
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "shared-ritm",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"private": false,
|
|
5
|
-
"files": [
|
|
6
|
-
"dist",
|
|
7
|
-
"src"
|
|
8
|
-
],
|
|
9
|
-
"main": "dist/shared-ritm.umd.js",
|
|
10
|
-
"type": "module",
|
|
11
|
-
"module": "./dist/shared-ritm.es.js",
|
|
12
|
-
"types": "./dist/types/index.d.ts",
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"import": "./dist/shared-ritm.es.js",
|
|
16
|
-
"require": "./dist/shared-ritm.umd.js",
|
|
17
|
-
"default": "./dist/shared-ritm.es.js",
|
|
18
|
-
"types": "./dist/types/index.d.ts"
|
|
19
|
-
},
|
|
20
|
-
"./style": "./dist/index.css"
|
|
21
|
-
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"dev": "vite",
|
|
24
|
-
"build": "vite build && tsc --emitDeclarationOnly",
|
|
25
|
-
"typecheck": "vue-tsc --noEmit",
|
|
26
|
-
"lint": "eslint --fix",
|
|
27
|
-
"format": "prettier -w -u ."
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@quasar/extras": "^1.16.17",
|
|
31
|
-
"@vueuse/core": "^10.1.2",
|
|
32
|
-
"face-api.js": "^0.22.2",
|
|
33
|
-
"axios": "^1.7.7",
|
|
34
|
-
"vue": "^3.5.12",
|
|
35
|
-
"vue-router": "^4.0.3"
|
|
36
|
-
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"quasar": "^2.18.1"
|
|
39
|
-
},
|
|
40
|
-
"devDependencies": {
|
|
41
|
-
"@quasar/vite-plugin": "^1.9.0",
|
|
42
|
-
"@rollup/pluginutils": "^5.1.3",
|
|
43
|
-
"@types/node": "^22.7.9",
|
|
44
|
-
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
|
45
|
-
"@typescript-eslint/parser": "^4.25.0",
|
|
46
|
-
"@vitejs/plugin-vue": "^5.1.4",
|
|
47
|
-
"@vue/compiler-sfc": "^3.0.5",
|
|
48
|
-
"@vue/eslint-config-prettier": "^6.0.0",
|
|
49
|
-
"@vue/eslint-config-typescript": "^7.0.0",
|
|
50
|
-
"eslint": "^7.27.0",
|
|
51
|
-
"eslint-plugin-prettier": "^3.4.0",
|
|
52
|
-
"eslint-plugin-vue": "^7.10.0",
|
|
53
|
-
"install": "^0.13.0",
|
|
54
|
-
"npm": "^11.4.0",
|
|
55
|
-
"prettier": "^2.3.0",
|
|
56
|
-
"quasar": "^2.18.1",
|
|
57
|
-
"rollup-plugin-visualizer": "^5.14.0",
|
|
58
|
-
"sass": "^1.80.4",
|
|
59
|
-
"typescript": "^5.6.3",
|
|
60
|
-
"vite": "^5.4.9",
|
|
61
|
-
"vite-plugin-css-modules": "^0.0.1",
|
|
62
|
-
"vue-tsc": "^2.1.6"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "shared-ritm",
|
|
3
|
+
"version": "1.2.82",
|
|
4
|
+
"private": false,
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"main": "dist/shared-ritm.umd.js",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"module": "./dist/shared-ritm.es.js",
|
|
12
|
+
"types": "./dist/types/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/shared-ritm.es.js",
|
|
16
|
+
"require": "./dist/shared-ritm.umd.js",
|
|
17
|
+
"default": "./dist/shared-ritm.es.js",
|
|
18
|
+
"types": "./dist/types/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./style": "./dist/index.css"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev": "vite",
|
|
24
|
+
"build": "vite build && tsc --emitDeclarationOnly",
|
|
25
|
+
"typecheck": "vue-tsc --noEmit",
|
|
26
|
+
"lint": "eslint --fix",
|
|
27
|
+
"format": "prettier -w -u ."
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@quasar/extras": "^1.16.17",
|
|
31
|
+
"@vueuse/core": "^10.1.2",
|
|
32
|
+
"face-api.js": "^0.22.2",
|
|
33
|
+
"axios": "^1.7.7",
|
|
34
|
+
"vue": "^3.5.12",
|
|
35
|
+
"vue-router": "^4.0.3"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"quasar": "^2.18.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@quasar/vite-plugin": "^1.9.0",
|
|
42
|
+
"@rollup/pluginutils": "^5.1.3",
|
|
43
|
+
"@types/node": "^22.7.9",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
|
45
|
+
"@typescript-eslint/parser": "^4.25.0",
|
|
46
|
+
"@vitejs/plugin-vue": "^5.1.4",
|
|
47
|
+
"@vue/compiler-sfc": "^3.0.5",
|
|
48
|
+
"@vue/eslint-config-prettier": "^6.0.0",
|
|
49
|
+
"@vue/eslint-config-typescript": "^7.0.0",
|
|
50
|
+
"eslint": "^7.27.0",
|
|
51
|
+
"eslint-plugin-prettier": "^3.4.0",
|
|
52
|
+
"eslint-plugin-vue": "^7.10.0",
|
|
53
|
+
"install": "^0.13.0",
|
|
54
|
+
"npm": "^11.4.0",
|
|
55
|
+
"prettier": "^2.3.0",
|
|
56
|
+
"quasar": "^2.18.1",
|
|
57
|
+
"rollup-plugin-visualizer": "^5.14.0",
|
|
58
|
+
"sass": "^1.80.4",
|
|
59
|
+
"typescript": "^5.6.3",
|
|
60
|
+
"vite": "^5.4.9",
|
|
61
|
+
"vite-plugin-css-modules": "^0.0.1",
|
|
62
|
+
"vue-tsc": "^2.1.6"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import * as faceapi from 'face-api.js'
|
|
2
|
-
|
|
3
|
-
class PhotoService {
|
|
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 api: PhotoService
|
|
133
|
-
|
|
134
|
-
export default function usePhotoService() {
|
|
135
|
-
if (!api) api = new PhotoService()
|
|
136
|
-
return api
|
|
137
|
-
}
|
|
1
|
+
import * as faceapi from 'face-api.js'
|
|
2
|
+
|
|
3
|
+
class PhotoService {
|
|
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 api: PhotoService
|
|
133
|
+
|
|
134
|
+
export default function usePhotoService() {
|
|
135
|
+
if (!api) api = new PhotoService()
|
|
136
|
+
return api
|
|
137
|
+
}
|