Browse Source

[新增]第一次提交

非煤矿山灾害智能感知和预警系统
邵佳豪 3 years ago
commit
4e36bb60e3
  1. 16
      .browserslistrc
  2. 16
      .editorconfig
  3. 42
      .gitignore
  4. 4
      .vscode/extensions.json
  5. 20
      .vscode/launch.json
  6. 42
      .vscode/tasks.json
  7. 1
      README.md
  8. 117
      angular.json
  9. 44
      karma.conf.js
  10. 8256
      package-lock.json
  11. 42
      package.json
  12. 13
      proxy.config.json
  13. 58
      src/app/CustomReuseStrategy.ts
  14. 21
      src/app/app-routing.module.ts
  15. 1
      src/app/app.component.html
  16. 0
      src/app/app.component.scss
  17. 17
      src/app/app.component.ts
  18. 35
      src/app/app.module.ts
  19. 36
      src/app/auth.guard.ts
  20. 91
      src/app/http-interceptors/base-interceptor.ts
  21. 9
      src/app/http-interceptors/index.ts
  22. 46
      src/app/pages/login/login.component.html
  23. 93
      src/app/pages/login/login.component.scss
  24. 128
      src/app/pages/login/login.component.ts
  25. 44
      src/app/pages/pages.module.ts
  26. 16
      src/app/pages/pages.routing.module.ts
  27. 17
      src/app/pipe/cameraTypePipe.ts
  28. 45
      src/app/service/cache-token.service.ts
  29. 10
      src/app/service/configFormData.service.ts
  30. 38
      src/app/service/tree.service.ts
  31. 11
      src/app/system-management/analysis-of-the-host/addhost/addhost.component.html
  32. 3
      src/app/system-management/analysis-of-the-host/addhost/addhost.component.scss
  33. 21
      src/app/system-management/analysis-of-the-host/addhost/addhost.component.ts
  34. 73
      src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html
  35. 100
      src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.scss
  36. 204
      src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts
  37. 11
      src/app/system-management/analysis-of-the-host/edithost/edithost.component.html
  38. 0
      src/app/system-management/analysis-of-the-host/edithost/edithost.component.scss
  39. 23
      src/app/system-management/analysis-of-the-host/edithost/edithost.component.ts
  40. 182
      src/app/system-management/condition-monitoring/condition-monitoring.component.html
  41. 17
      src/app/system-management/condition-monitoring/condition-monitoring.component.scss
  42. 270
      src/app/system-management/condition-monitoring/condition-monitoring.component.ts
  43. 36
      src/app/system-management/condition-monitoring/file/file.component.html
  44. 0
      src/app/system-management/condition-monitoring/file/file.component.scss
  45. 27
      src/app/system-management/condition-monitoring/file/file.component.ts
  46. 18
      src/app/system-management/condition-monitoring/model/model.component.html
  47. 0
      src/app/system-management/condition-monitoring/model/model.component.scss
  48. 24
      src/app/system-management/condition-monitoring/model/model.component.ts
  49. 15
      src/app/system-management/config-form/config-form.component.html
  50. 29
      src/app/system-management/config-form/config-form.component.scss
  51. 76
      src/app/system-management/config-form/config-form.component.ts
  52. 75
      src/app/system-management/host-config/addcamera/addcamera.component.html
  53. 0
      src/app/system-management/host-config/addcamera/addcamera.component.scss
  54. 50
      src/app/system-management/host-config/addcamera/addcamera.component.ts
  55. 75
      src/app/system-management/host-config/editcamera/editcamera.component.html
  56. 0
      src/app/system-management/host-config/editcamera/editcamera.component.scss
  57. 32
      src/app/system-management/host-config/editcamera/editcamera.component.ts
  58. 66
      src/app/system-management/host-config/host-config.component.html
  59. 43
      src/app/system-management/host-config/host-config.component.scss
  60. 593
      src/app/system-management/host-config/host-config.component.ts
  61. 5
      src/app/system-management/host-config/send-file/send-file.component.html
  62. 20
      src/app/system-management/host-config/send-file/send-file.component.scss
  63. 23
      src/app/system-management/host-config/send-file/send-file.component.ts
  64. 12
      src/app/system-management/image-label/image-label.component.html
  65. 26
      src/app/system-management/image-label/image-label.component.scss
  66. 216
      src/app/system-management/image-label/image-label.component.ts
  67. 37
      src/app/system-management/image-label2/image-label2.component.html
  68. 38
      src/app/system-management/image-label2/image-label2.component.scss
  69. 647
      src/app/system-management/image-label2/image-label2.component.ts
  70. 19
      src/app/system-management/image-list/image-list.component.html
  71. 48
      src/app/system-management/image-list/image-list.component.scss
  72. 50
      src/app/system-management/image-list/image-list.component.ts
  73. 1
      src/app/system-management/kafka/kafka.component.html
  74. 0
      src/app/system-management/kafka/kafka.component.scss
  75. 15
      src/app/system-management/kafka/kafka.component.ts
  76. 47
      src/app/system-management/navigation/navigation.component.html
  77. 79
      src/app/system-management/navigation/navigation.component.scss
  78. 20
      src/app/system-management/navigation/navigation.component.ts
  79. 23
      src/app/system-management/organization/addor/addor.component.html
  80. 0
      src/app/system-management/organization/addor/addor.component.scss
  81. 26
      src/app/system-management/organization/addor/addor.component.ts
  82. 23
      src/app/system-management/organization/editor/editor.component.html
  83. 0
      src/app/system-management/organization/editor/editor.component.scss
  84. 30
      src/app/system-management/organization/editor/editor.component.ts
  85. 42
      src/app/system-management/organization/organization.component.html
  86. 78
      src/app/system-management/organization/organization.component.scss
  87. 314
      src/app/system-management/organization/organization.component.ts
  88. 3
      src/app/system-management/plotting-image/plotting-image.component.html
  89. 7
      src/app/system-management/plotting-image/plotting-image.component.scss
  90. 171
      src/app/system-management/plotting-image/plotting-image.component.ts
  91. 12
      src/app/system-management/status-monitoring/script/script.component.html
  92. 0
      src/app/system-management/status-monitoring/script/script.component.scss
  93. 25
      src/app/system-management/status-monitoring/script/script.component.ts
  94. 96
      src/app/system-management/status-monitoring/status-monitoring.component.html
  95. 17
      src/app/system-management/status-monitoring/status-monitoring.component.scss
  96. 221
      src/app/system-management/status-monitoring/status-monitoring.component.ts
  97. 34
      src/app/system-management/system-management-routing.module.ts
  98. 76
      src/app/system-management/system-management.module.ts
  99. 116
      src/app/system-management/video-streaming/video-streaming.component.html
  100. 17
      src/app/system-management/video-streaming/video-streaming.component.scss
  101. Some files were not shown because too many files have changed in this diff Show More

16
.browserslistrc

@ -0,0 +1,16 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

16
.editorconfig

@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

42
.gitignore vendored

@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

4
.vscode/extensions.json vendored

@ -0,0 +1,4 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

20
.vscode/launch.json vendored

@ -0,0 +1,20 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "pwa-chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
}
]
}

42
.vscode/tasks.json vendored

@ -0,0 +1,42 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

1
README.md

@ -0,0 +1 @@
# 济南项目

117
angular.json

@ -0,0 +1,117 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"EdgeHostMaintenance": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/edge-host-maintenance",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}
],
"styles": [
"src/styles.scss",
"node_modules/ng-zorro-antd/ng-zorro-antd.min.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "EdgeHostMaintenance:build:production"
},
"development": {
"browserTarget": "EdgeHostMaintenance:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "EdgeHostMaintenance:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"defaultProject": "EdgeHostMaintenance"
}

44
karma.conf.js

@ -0,0 +1,44 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/edge-host-maintenance'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

8256
package-lock.json generated

File diff suppressed because it is too large Load Diff

42
package.json

@ -0,0 +1,42 @@
{
"name": "edge-host-maintenance",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.config.json --open --port 4000 ",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.1.0",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"js-base64": "^3.7.2",
"ng-zorro-antd": "^13.0.1",
"ngx-cookie-service": "^13.1.2",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~13.1.4",
"@angular/cli": "~13.1.4",
"@angular/compiler-cli": "~13.1.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~3.10.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.5.2"
}
}

13
proxy.config.json

@ -0,0 +1,13 @@
{
"/api": {
"target": "http://39.106.78.171:8920",
"secure": false,
"changeOrigin": true
},
"/signalr": {
"target": "http://39.106.78.171:8920",
"secure": false,
"ws": true,
"logLevel": "debug"
}
}

58
src/app/CustomReuseStrategy.ts

@ -0,0 +1,58 @@
import { RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
/** 删除缓存路由快照的方法 */
public static deleteRouteSnapshot(path: string): void {
const name = path.replace(/\//g, '_');
if (CustomReuseStrategy.handlers[name]) {
delete CustomReuseStrategy.handlers[name];
}
}
/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.log('shouldDetach======>', route);
return true;
}
/** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
console.log('store======>', route, handle);
if(route.routeConfig.path == 'host'){
CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle;
}
}
/** 若 path 在缓存中有的都认为允许还原路由 */
shouldAttach(route: ActivatedRouteSnapshot): boolean {
// console.debug('shouldAttach======>', route);
return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)];
}
/** 从缓存中获取快照,若无则返回nul */
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
// console.debug('retrieve======>', route);
if (!CustomReuseStrategy.handlers[this.getRouteUrl(route)]) {
return null;
}
return CustomReuseStrategy.handlers[this.getRouteUrl(route)];
}
/** 进入路由触发,判断是否同一路由 */
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
// console.debug('shouldReuseRoute======>', future, curr);
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params);
}
/** 使用route的path作为快照的key */
getRouteUrl(route: ActivatedRouteSnapshot) {
const path = route['_routerState'].url.replace(/\//g, '_');
return path;
}
}

21
src/app/app-routing.module.ts

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth.guard';
import { LoginComponent } from './pages/login/login.component';
import { NavigationComponent } from './system-management/navigation/navigation.component';
const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent, },
{
path: '', component: NavigationComponent, canActivate: [AuthGuard], children: [
{ path: 'system', loadChildren: () => import('./system-management/system-management.module').then(m => m.SystemManagementModule) }
]
}//系统管理
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

1
src/app/app.component.html

@ -0,0 +1 @@
<router-outlet></router-outlet>

0
src/app/app.component.scss

17
src/app/app.component.ts

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { CacheTokenService } from './service/cache-token.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor(public token: CacheTokenService) { }
ngOnInit() {
if (sessionStorage.getItem('token') && !this.token.timer) {
//调用服务中的function刷新token
this.token.startUp()
}
}
}

35
src/app/app.module.ts

@ -0,0 +1,35 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PagesModule } from './pages/pages.module';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { httpInterceptorProviders } from './http-interceptors/index'
import { CacheTokenService } from './service/cache-token.service'
import { NzNotificationModule } from 'ng-zorro-antd/notification';
import { NzMessageModule } from 'ng-zorro-antd/message';
import { TreeService } from './service/tree.service';
import { RouteReuseStrategy } from '@angular/router';
import { CustomReuseStrategy } from './CustomReuseStrategy';
import { ConfigFormDataService } from './service/configFormData.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
PagesModule,
FormsModule,
HttpClientModule,
NzNotificationModule,
NzMessageModule
],
providers: [httpInterceptorProviders, CacheTokenService, TreeService, ConfigFormDataService,
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }],
bootstrap: [AppComponent]
})
export class AppModule { }

36
src/app/auth.guard.ts

@ -0,0 +1,36 @@
import { Component, OnInit, Inject } from '@angular/core';
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {
}
// 路由守卫
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
// console.log('路由守卫',next.data)
// if(next.data.permission == 'xxxx'){
// return true;
// }
return this.checkLogin();
}
checkLogin(): boolean {
// console.log('xxxxxxxxxxxx')
// 判断本地有没有token
const token = sessionStorage.getItem('token');
// 如果有token,允许访问
if (token) { return true; }
//如果没有token,跳转登录页
this.router.navigate(['/login']);
return false;
}
}

91
src/app/http-interceptors/base-interceptor.ts

@ -0,0 +1,91 @@
import { Injectable } from '@angular/core';
import {
HttpClient, HttpInterceptor, HttpHandler, HttpRequest,
HttpErrorResponse
} from '@angular/common/http';
import { throwError } from 'rxjs'
import { catchError } from 'rxjs/operators';
import { Router } from '@angular/router'
import { CacheTokenService } from '../service/cache-token.service'
import { NzMessageService } from 'ng-zorro-antd/message';
//baseurl
// const baseurl = 'http://39.106.78.171:8008';
@Injectable()
export class BaseInterceptor implements HttpInterceptor {
constructor(private router: Router, public token: CacheTokenService, private message: NzMessageService) { }
intercept(req: any, next: HttpHandler) {
let params = req.params;
for (const key of req.params.keys()) {
if (params.get(key) === undefined || params.get(key) === null) {
params = params.delete(key, undefined);
}
}
req = req.clone({ params });
// debugger
// console.log('xxxxxx',req)
let newReq = req.clone({
url: req.hadBaseurl ? `${req.url}` : `${req.url}`,
});
if (!req.cancelToken) {
/*获取token*/
let token = sessionStorage.getItem('token')
/*此处设置额外请求头,token令牌*/
newReq.headers =
newReq.headers.set('Authorization', `Bearer ${token}`)
}
// 携带请求头发送下一次请求
return next.handle(newReq)
.pipe(
//箭头函数,注意this指向
catchError((err) => this.handleError(err))
)
}
// 捕获错误
//401 token过期 403没权限!!! 400参数错误 404未找到 614刷新令牌过期!!!
private handleError(error: HttpErrorResponse) {
console.log('http错误', error)
// 用户认证失败返回登录页
if (error.status === 401) {
this.token.delete()
sessionStorage.clear()
localStorage.removeItem("isautologin")
this.message.create('error', `用户认证信息过期,请重新登录!`);
this.router.navigate(['/login'])
return
}
if (error.status === 403) {
this.message.create('error', `对不起,您无此权限!`);
return
}
if (error.status === 400) {
this.message.create('error', error.error);
return
}
if (error.status === 503) {
this.message.create('error', error.error.detail);
return
}
if (error.error instanceof ErrorEvent) {
// 发生客户端或网络错误。相应处理。
console.error('An error occurred:', error.error.message);
} else {
// 服务端返回http状态码
// 服务端返回错误信息
console.error(
`状态码${error.status}, ` +
`错误内容:${error.error}`);
this.message.create('error', error.error);
}
// 返回带有面向用户的错误信息
return throwError(() => {
new Error('error')
});
};
}

9
src/app/http-interceptors/index.ts

@ -0,0 +1,9 @@
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { BaseInterceptor } from './base-interceptor';
/** Http interceptor providers in outside-in order */
export const httpInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: BaseInterceptor, multi: true },
];

46
src/app/pages/login/login.component.html

@ -0,0 +1,46 @@
<div class="login" id="login">
<div class="card">
<h1 class="cardheader">欢迎登录</h1>
<h1 class="cardheader">济南管理系统</h1>
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-control nzErrorTip="请输入账号!">
<nz-input-group nzPrefixIcon="user">
<input required nz-input type="text" formControlName="userName" placeholder="请输入账号"/>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control nzErrorTip="请输入密码!">
<nz-input-group nzPrefixIcon="lock">
<input required nz-input type="password" formControlName="password" placeholder="请输入密码"/>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<div class="hint">
<nz-form-item style="margin-bottom: 0;">
<nz-form-control>
<label nz-checkbox formControlName="remember" [(ngModel)]="remember">记住密码</label>
</nz-form-control>
</nz-form-item>
<span class="forget" (click)="forget()">忘记密码?</span>
</div>
<nz-form-item style="margin-bottom: 0;">
<nz-form-control>
<label class="autologin" formControlName="autologin" nz-checkbox [(ngModel)]="autologin">自动登录</label>
</nz-form-control>
</nz-form-item>
<button [nzLoading]="isLoading" nz-button class="login-form-button login-form-margin"
[nzType]="'primary'">登录</button>
</form>
<p class="company">北京安信科创软件有限公司 版权所有</p>
</div>
<div class="name">
</div>
</div>

93
src/app/pages/login/login.component.scss

@ -0,0 +1,93 @@
.login {
width: 100%;
height: 100%;
background: url('../../../assets/images/bgImg.png');
background-size: 100% 100%;
position: relative;
}
.card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background-color: rgba(0, 13, 33, 0.24);
border-radius: 16px;
width: 468px;
height: 548px;
box-sizing: border-box;
padding: 79px 45px 42px 45px;
color: rgba(255, 255, 255, 1);
}
.cardheader {
font-size: 22px;
color: rgba(255, 255, 255, 1);
}
.cardheader:nth-child(2) {
margin-bottom: 40px;
}
label {
color: #fff;
}
.hint {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
align-items: center;
.forget {
cursor: pointer;
color: #2399FF;
}
}
.autologin {
margin-bottom: 40px;
}
button {
width: 100%;
height: 42px;
font-size: 16px;
border-radius: 4px;
}
p {
text-align: center;
}
.role {
color: #2399FF;
margin-top: 38px;
font-size: 15px;
}
.company {
color: #666262;
margin-top: 25px;
font-size: 14px;
}
.name {
position: absolute;
left:40px;
top:40px;
img {
// margin-bottom: 32px;
width: 254px;
height: 56px;
}
h1 {
font-size: 63px;
color: #feffff;
font-weight: 600;
text-shadow: 0px 2px 8px #2399FF;
letter-spacing: 5px;
margin-bottom: 0px;
}
}

128
src/app/pages/login/login.component.ts

@ -0,0 +1,128 @@
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http'
import { Router, ActivatedRoute } from '@angular/router'
import { CacheTokenService } from '../../service/cache-token.service'//引入服务
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { Base64 } from 'js-base64';
import { NzNotificationService } from 'ng-zorro-antd/notification';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
})
export class LoginComponent implements OnInit {
validateForm!: FormGroup;
constructor(private http: HttpClient, private router: Router, public token: CacheTokenService, private fb: FormBuilder, private message: NzMessageService) { }
ngOnInit() {
this.validateForm = this.fb.group({
userName: [null, [Validators.required]],
password: [null, [Validators.required]],
remember: [null],
autologin: [null],
});
//如果本地储存了账号密码信息,那就回显在输入框
let account = localStorage.getItem('account')
let password = localStorage.getItem('password')
if (account && password) {
this.validateForm.patchValue({
userName: Base64.decode(localStorage.getItem('account')),
password: Base64.decode(localStorage.getItem('password'))
});
this.remember = true //这一步是回显后让勾选框为选中状态
}
//自动登录
if (localStorage.getItem('isautologin') == 'true') {
this.submitForm()
this.autologin = true //这一步是回显后让勾选框为选中状态
}
}
errmsg: string = ''; //错误信息
// //跳转注册页面
// toRegister() {
// this.router.navigate(['/register'])
// }
//记住密码
rememberInfo() {
// 判断用户是否勾选记住密码,如果勾选,在本地储存中储存登录信息
if (this.remember) {
localStorage.setItem("account", Base64.encode(this.validateForm.value.userName))
localStorage.setItem("password", Base64.encode(this.validateForm.value.password))
}
}
//自动登录
autoLogin() {
if (this.autologin) {
localStorage.setItem("isautologin", 'true')
}
}
remember: any//记住密码
autologin: any//自动登录
isLoading = false;
messages: any
encryptedAccessToken: any
submitForm(): void {
if (!this.remember) {
localStorage.removeItem("account")
localStorage.removeItem("password")
}
if (!this.autologin) {
localStorage.removeItem("isautologin")
}
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
if (!this.validateForm.valid) {
this.message.create('error', `请输入账号密码`);
return
}
this.isLoading = true;
this.http.post('/api/Accounts/SignIn', {
username: this.validateForm.value.userName,
password: this.validateForm.value.password
}).subscribe({
next: (data: any) => {
// this.isLoading = false;
console.log('登录信息', data)
this.rememberInfo()
this.autoLogin()
sessionStorage.setItem("token", data.token);
sessionStorage.setItem("refreshToken", data.refreshToken);
this.router.navigate(['/system/organization'])
this.message.create('success', `登录成功`);
//调用服务中的function刷新token
this.token.startUp()
},
error: (err) => {
this.isLoading = false;
console.log(err)
}
}
)
}
forget() {
this.message.create('warning', `请联系管理员`);
}
}

44
src/app/pages/pages.module.ts

@ -0,0 +1,44 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { A11yModule } from '@angular/cdk/a11y';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { PortalModule } from '@angular/cdk/portal';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { CdkStepperModule } from '@angular/cdk/stepper';
import { CdkTableModule } from '@angular/cdk/table';
import { CdkTreeModule } from '@angular/cdk/tree';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzSelectModule } from 'ng-zorro-antd/select';
import { LoginComponent } from './login/login.component';
import { NzMessageModule } from 'ng-zorro-antd/message';
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
@NgModule({
declarations: [
LoginComponent
],
imports: [
CommonModule,
A11yModule,
DragDropModule,
PortalModule,
ScrollingModule,
CdkStepperModule,
CdkTableModule,
CdkTreeModule,
FormsModule,
ReactiveFormsModule,
RouterModule,
NzFormModule,
NzButtonModule,
NzInputModule,
NzSelectModule,
NzMessageModule,
NzCheckboxModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class PagesModule { }

16
src/app/pages/pages.routing.module.ts

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class pagesRoutingModule { }

17
src/app/pipe/cameraTypePipe.ts

@ -0,0 +1,17 @@
import { Pipe, PipeTransform } from '@angular/core';
/*
* Raise the value exponentially
* Takes an exponent argument that defaults to 1.
* Usage:
* value | exponentialStrength:exponent
* Example:
* {{ 2 | exponentialStrength:10 }}
* formats to: 1024
*/
@Pipe({ name: 'cameraType' })
export class cameraType implements PipeTransform {
transform(value: number): string {
let arr = ['进出口', '加油区', '卸油区', '便利店']
return arr[value]
}
}

45
src/app/service/cache-token.service.ts

@ -0,0 +1,45 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'
@Injectable({
providedIn: 'root'
})
export class CacheTokenService {
constructor(private http: HttpClient) { }
public timer: number | undefined;
//刷新token令牌定时器
startUp = (): void => {
window.clearInterval(this.timer)
this.timer = window.setInterval(() => {
var token = sessionStorage.getItem("token");
var refreshToken = sessionStorage.getItem("refreshToken");
this.http.post('/api/Accounts/RefreshToken', {
token: token,
refreshToken: refreshToken
}).subscribe((data: any) => {
console.log('定时刷新token成功',data)
sessionStorage.setItem("token", data.token);
sessionStorage.setItem("refreshToken", data.refreshToken);
})
}, 18 * 60 * 1000)
console.log('启动定时刷新token')
}
//删除定时器
delete = (): void => {
window.clearInterval(this.timer)
}
createTime = (time: string) => {
var newtime = time.substr(0, 4) + '年' + time.substr(5, 2) + '月' + time.substr(8, 2) + '日' + time.substr(11, 8)
}
}

10
src/app/service/configFormData.service.ts

@ -0,0 +1,10 @@
import { Injectable } from '@angular/core';
@Injectable()
export class ConfigFormDataService {
tableData: any//摄像头列表数据
config1: any//配置文件
config2: any//配置文件
config3: any//配置文件
config4: any//配置文件
}

38
src/app/service/tree.service.ts

@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
@Injectable()
export class TreeService {
toTree(olddata) {
let newdata = []
function getparentNode(parentId) {
return olddata.find((item) => {
return item.id == parentId
})
}
olddata.forEach(item => {
var parentNode = getparentNode(item.parentId);
if (parentNode) {
if (!parentNode.children) {
parentNode.children = []
}
// if (parentNode.children.length == 0) {
// item.isTop = true;
// } else {
// item.isTop = false;
// parentNode.children[parentNode.children.length -1].isBottom = false;
// }
// item.isBottom = true;
parentNode.children.push(item)
} else {
if (!item.parentId) {//如果parentId为null
newdata.push(item)
}
}
});
return newdata;
}
}

11
src/app/system-management/analysis-of-the-host/addhost/addhost.component.html

@ -0,0 +1,11 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="ip" placeholder="请输入ip" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
</form>
</div>

3
src/app/system-management/analysis-of-the-host/addhost/addhost.component.scss

@ -0,0 +1,3 @@
.ant-form-item{
margin-bottom: 0;
}

21
src/app/system-management/analysis-of-the-host/addhost/addhost.component.ts

@ -0,0 +1,21 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-addhost',
templateUrl: './addhost.component.html',
styleUrls: ['./addhost.component.scss']
})
export class AddhostComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
ip: [null, [Validators.required]]
});
}
}

73
src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.html

@ -0,0 +1,73 @@
<div class="bigbox" id="hostbox">
<div class="orbox">
<div class="topbox">
<div class="lefttop">
<span>组织机构列表</span>
</div>
<div class="righttop">
<nz-input-group nzPrefixIcon="search">
<input type="text" nz-input placeholder="请输入机构名称" [(ngModel)]="searchValue" />
</nz-input-group>
</div>
</div>
<div class="treeTitle">
<span>组织机构</span>
</div>
<div class="treebox">
<nz-tree [nzSearchValue]="searchValue" #nzTreeComponent [nzData]="nodes" [nzExpandAll]="nzExpandAll"
[nzExpandedKeys]="defaultExpandedKeys" [nzSelectedKeys]='nzSelectedKeys' (nzClick)="nzClick($event)"
[nzTreeTemplate]="nzTreeTemplate" [nzExpandedIcon]="multiExpandedIconTpl">
</nz-tree>
<ng-template #nzTreeTemplate let-node let-origin="origin">
<div class="nodebox">
<span class="name">{{ node.title }}</span>
</div>
</ng-template>
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<ng-container *ngIf="node.children.length == 0; else elseTemplate">
</ng-container>
<ng-template #elseTemplate>
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'" class="ant-tree-switcher-line-icon"></i>
</ng-template>
</ng-template>
</div>
</div>
<div class="hostListbox">
<div class="topbox">
<div class="lefttop">
<span>{{selectedOilStation ? selectedOilStation.displayName : '加油站'}} 边缘盒子列表
<span class="yellowspan">(请从左侧选择加油站)</span>
</span>
</div>
<div class="righttop" *ngIf="selectedOilStation">
<button nz-button nzType="primary" (click)="addHost()"><i nz-icon nzType="plus-circle"
nzTheme="outline"></i>新增边缘盒子</button>
</div>
</div>
<div class="tablebox">
<nz-table #basicTable [nzData]="listOfData" [nzShowPagination]='false' [nzPageSize]='16' [nzLoading]="isLoading">
<thead>
<tr>
<th>ip</th>
<th>配置状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{data.hostIPAddress}}</td>
<td>!配置状态!</td>
<td class="operation">
<a (click)="edit(data)" style="margin-right: 12px;">编辑</a>
<a (click)="config(data)" style="margin-right: 12px;">配置</a>
<a (click)="download(data)" style="margin-right: 12px;">下载设备编号</a>
<a class="red" (click)="delete(data)">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</div>
</div>
</div>

100
src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.scss

@ -0,0 +1,100 @@
.bigbox {
width: 100%;
height: 100%;
display: flex;
background: #fff;
box-sizing: border-box;
padding: 20px;
font-size: 15px;
}
.orbox {
width: 375px;
height: 100%;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.topbox {
width: 100%;
height: 36px;
display: flex;
align-items: center;
justify-content: space-between;
.lefttop {
span {
color: #000D21;
margin-right: 16px;
}
.yellowspan {
color: rgb(240, 176, 37);
}
}
.righttop {
height: 36px;
display: flex;
button {
margin-left: 16px;
}
nz-input-group {
height: 32px;
}
}
}
.treeTitle {
width: 100%;
height: 36px;
line-height: 36px;
display: flex;
justify-content: space-between;
color: #000D21;
box-sizing: border-box;
padding-left: 30px;
padding-right: 180px;
background: rgba(145, 204, 255, 0.2);
border: 1px solid rgba(145, 204, 255, 0.2);
}
.treebox {
flex: 1;
overflow-y: auto;
border: 1px solid rgba(145, 204, 255, 0.2);
border-top: 0px;
box-sizing: border-box;
padding: 10px 6px;
tr {
th,
td {
text-align: center !important;
}
}
}
.nodebox {
font-size: 15px;
}
.hostListbox {
flex: 1;
margin-left: 26px;
overflow-y: auto;
}
.tablebox {
margin-top: 16px;
}
.red:hover{
color: red;
}

204
src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts

@ -0,0 +1,204 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, AfterViewInit, ViewChild, ViewContainerRef } from '@angular/core';
import { TreeService } from 'src/app/service/tree.service';
import { NzFormatEmitEvent, NzTreeComponent, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
import { AddhostComponent } from './addhost/addhost.component';
import { EdithostComponent } from './edithost/edithost.component';
import { Router } from '@angular/router';
@Component({
selector: 'app-analysis-of-the-host',
templateUrl: './analysis-of-the-host.component.html',
styleUrls: ['./analysis-of-the-host.component.scss']
})
export class AnalysisOfTheHostComponent implements OnInit {
constructor(private router: Router, private fb: FormBuilder, private http: HttpClient, private toTree: TreeService, private modal: NzModalService, private message: NzMessageService, private viewContainerRef: ViewContainerRef) { }
ngOnInit(): void {
this.getAllOrganization()
}
//获取所有组织机构
searchValue = '';
nzExpandAll = false;
totalCount: string
getAllOrganization() {
let params = {
ContainsChildren: true,
PageSize: 9999
}
this.http.get('/api/Organizations', {
params: params
}).subscribe((data: any) => {
this.totalCount = data.totalCount
data.items.forEach(element => {
element.key = element.id
element.title = element.name
element.selectable = false
});
this.nodes = [...this.toTree.toTree(data.items)]
this.defaultExpandedKeys = [this.nodes[0].id]
this.defaultExpandedKeys = [...this.defaultExpandedKeys]
})
}
@ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent;
defaultExpandedKeys = [];
nodes: any[] = []
nzSelectedKeys: any[] = []
selectedOilStation: any
nzClick(event: NzFormatEmitEvent): void {
if (event.node.origin['isGasStation']) {//如果点击的是加油站才生效
this.nzSelectedKeys[0] = event.node.origin.id
this.nzSelectedKeys = [...this.nzSelectedKeys]
this.selectedOilStation = event.node.origin
console.log(this.selectedOilStation)
this.getHost()
} else {
this.message.info('只有加油站才可以增加主机');
}
}
//获得加油站的主机
listOfData: any[] = [];
isLoading = false
getHost() {
this.isLoading = true
this.http.get('/api/EdgeDevices', {
params: {
ContainsChildren: true,
OrganizationId: this.selectedOilStation.id,
PageSize: 999
}
}).subscribe((data: any) => {
console.log('主机列表', data.items)
this.isLoading = false
this.listOfData = data.items
})
}
ngAfterViewInit(): void {
}
//新增边缘盒子
addHost() {
console.log(this.selectedOilStation)
const modal = this.modal.create({
nzTitle: '新增边缘盒子',
nzContent: AddhostComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise(resolve => {
console.log('表单信息', instance.validateForm)
let body = {
hostIPAddress: instance.validateForm.value.ip,
OrganizationId: this.selectedOilStation.id
}
this.http.post('/api/EdgeDevices', body).subscribe(data => {
resolve(data)
this.message.create('success', '创建成功!');
this.getHost()
return true
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
edit(data) {
console.log(data)
const modal = this.modal.create({
nzTitle: '编辑边缘盒子',
nzContent: EdithostComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {
ip: data.hostIPAddress
},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise(resolve => {
console.log('表单信息', instance.validateForm)
data.hostIPAddress = instance.validateForm.value.ip,
this.http.put(`/api/EdgeDevices/${data.id}`, data).subscribe(data => {
resolve(data)
this.message.create('success', '修改成功!');
this.getHost()
return true
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
delete(item) {
console.log(item)
this.modal.confirm({
nzTitle: `确定要删除${item.name}这个主机吗?`,
nzOkText: '确定',
nzOkType: 'primary',
nzOnOk: () => {
this.http.delete(`/api/EdgeDevices/${item.id}`).subscribe(data => {
this.message.create('success', '删除成功!');
this.getHost()
})
},
nzCancelText: '取消'
});
}
config(data) {
this.router.navigate([`/system/host/camera`], { queryParams: { 'hostId': data.id, 'orId': this.selectedOilStation.id } })
}
download(data) {
console.log(data)
let params = {
edgeDeviceId: data.id
}
const httpOptions = {
responseType: 'blob' as 'json',
params: params
};
this.http.get(`/api/EdgeDevices/IdentityDigest/File`, httpOptions).subscribe({
next: (data: any) => {
console.log('文件',data)
// 文件名中有中文 则对文件名进行转码
const link = document.createElement('a');
const blob = new Blob([data], { type: 'application/octet-stream' });
link.setAttribute('href', window.URL.createObjectURL(blob));
link.setAttribute('download', `.deviceid`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
error: (err) => {
console.log(err)
}
})
}
}

11
src/app/system-management/analysis-of-the-host/edithost/edithost.component.html

@ -0,0 +1,11 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control>
<nz-input-group>
<input [(ngModel)]="ip" nz-input type="text" formControlName="ip" placeholder="请输入ip" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/analysis-of-the-host/edithost/edithost.component.scss

23
src/app/system-management/analysis-of-the-host/edithost/edithost.component.ts

@ -0,0 +1,23 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-edithost',
templateUrl: './edithost.component.html',
styleUrls: ['./edithost.component.scss']
})
export class EdithostComponent implements OnInit {
@Input() ip: any
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
ip: [null, [Validators.required]]
});
}
}

182
src/app/system-management/condition-monitoring/condition-monitoring.component.html

@ -0,0 +1,182 @@
<div class="box">
<div class="topbox">
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
<nz-form-item class="searchParams">
<nz-form-control>
<nz-tree-select [nzAllowClear]="false" [nzDropdownClassName]="'maxHeightTreeSelect'" nzShowSearch
formControlName="organization" [nzNodes]="nodes" nzPlaceHolder="请选择所属机构" [(ngModel)]="defaultOrId"
[nzExpandedIcon]="multiExpandedIconTpl">
</nz-tree-select>
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<ng-container *ngIf="node.children.length == 0; else elseTemplate">
</ng-container>
<ng-template #elseTemplate>
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'"
class="ant-tree-switcher-line-icon"></i>
</ng-template>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<!-- <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="state">设备状态</nz-form-label> -->
<nz-form-control>
<nz-select formControlName="state" nzPlaceHolder="请选择设备状态">
<nz-option [nzValue]="0" nzLabel="离线"></nz-option>
<nz-option [nzValue]="1" nzLabel="在线"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button nzType="primary" type="submit" class="submit"><i nz-icon [nzType]="'search'"></i>查询</button>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button type="button" class="reset" (click)="resetForm($event)"><i nz-icon
[nzType]="'sync'"></i>重置</button>
</nz-form-control>
</nz-form-item>
<!-- <button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'UpdateStates'" (click)="sendRequest('UpdateStates')">
更新识别程序服务状态
</button> -->
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'UpdateApps'" (click)="sendRequest('UpdateApps')">
更新识别程序
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'primary'" (click)="sendRequest('UpdateImages')">
更新镜像
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'primary'" (click)="sendRequest('UpdateModels')">
更新模型
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'primary'" (click)="sendRequest('UpdateMonitors')">
更新监控程序
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'file'" (click)="file()">
更新监控程序配置文件
</button>
</form>
</div>
<nz-table #basicTable nzShowSizeChanger [nzData]="listOfData" [nzLoading]="isLoading"
(nzCurrentPageDataChange)="onCurrentPageDataChange($event)" [nzShowPagination]='false' [nzPageSize]='10'>
<thead>
<tr>
<th [nzChecked]="checked" [nzIndeterminate]="indeterminate" (nzCheckedChange)="onAllChecked($event)"></th>
<th>ip地址</th>
<th>所属油站</th>
<th>设备状态</th>
<th>识别程序更新状态</th>
<!-- <th>识别程序更新状态开始时间</th>
<th>识别程序更新状态结束时间</th> -->
<th>镜像更新状态</th>
<!-- <th>镜像更新状态开始时间</th>
<th>镜像更新状态结束时间</th> -->
<th>模型更新状态</th>
<th>监控程序更新状态</th>
<!-- <th>监控程序更新状态开始时间</th>
<th>监控程序更新状态结束时间</th> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td [nzChecked]="setOfCheckedId.has(data.id)" [nzDisabled]="data.disabled"
(nzCheckedChange)="onItemChecked(data.id, $event)"></td>
<td>{{ data.hostIPAddress }}</td>
<td>{{ data.gasStationName }}</td>
<td>
<ng-container *ngIf="data.hubConnectionState == 'Disconnected'; else elseTemplate">
<span style="color: red;">离线</span>
</ng-container>
<ng-template #elseTemplate>
<span style="color: rgb(52, 204, 52);">在线</span>
</ng-template>
</td>
<!-- 识别程序 -->
<td>
<p>
<span *ngIf="data.appUpdatingState == 'Never'">未更新</span>
<span *ngIf="data.appUpdatingState == 'Updating'">更新中</span>
<span *ngIf="data.appUpdatingState == 'Updated'">已更新</span>
</p>
<p>
开始时间:{{data.appUpdatingStartedTime ? (data.appUpdatingStartedTime | date:"yyyy-MM-dd HH:mm:ss") :'/'}}
</p>
<p>
结束时间:{{data.appUpdatingFinishedTime ? (data.appUpdatingFinishedTime | date:"yyyy-MM-dd HH:mm:ss") :'/'}}
</p>
</td>
<!-- 镜像 -->
<td>
<p>
<span *ngIf="data.imageUpdatingState == 'Never'">未更新</span>
<span *ngIf="data.imageUpdatingState == 'Updating'">更新中</span>
<span *ngIf="data.imageUpdatingState == 'Updated'">已更新</span>
</p>
<p>
{{data.imageUpdatingStartedTime ? (data.imageUpdatingStartedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
<p>
{{data.imageUpdatingFinishedTime ? (data.imageUpdatingFinishedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
</td>
<!-- 模型 -->
<td>
<p>
<span *ngIf="data.modelsUpdatingState == 'Never'">未更新</span>
<span *ngIf="data.modelsUpdatingState == 'Updating'">更新中</span>
<span *ngIf="data.modelsUpdatingState == 'Updated'">已更新</span>
</p>
<p>
{{data.modelsUpdatingStartedTime ? (data.modelsUpdatingStartedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
<p>
{{data.modelsUpdatingFinishedTime ? (data.modelsUpdatingFinishedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
</td>
<!-- 监控程序 -->
<td>
<p>
<span *ngIf="data.monitorUpdatingState == 'Never'">未更新</span>
<span *ngIf="data.monitorUpdatingState == 'Updating'">更新中</span>
<span *ngIf="data.monitorUpdatingState == 'Updated'">已更新</span>
<span *ngIf="data.monitorUpdatingState == 'UpdatingTimeout'">更新超时</span>
</p>
<p>
{{data.monitorUpdatingStartedTime ? (data.monitorUpdatingStartedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
<p>
{{data.monitorUpdatingFinishedTime ? (data.monitorUpdatingFinishedTime | date:"yyyy-MM-dd HH:mm:ss") :
'/'}}
</p>
</td>
</tr>
</tbody>
</nz-table>
<div class="pagination">
<nz-pagination [nzHideOnSinglePage]="false" [nzPageIndex]="1" [nzTotal]="num" [nzPageSize]="10"
[nzShowTotal]="totalTemplate" nzShowQuickJumper (nzPageIndexChange)="pageChange($event)">
</nz-pagination>
<ng-template #totalTemplate let-total> 10条/页,共{{num}}条 </ng-template>
</div>
</div>

17
src/app/system-management/condition-monitoring/condition-monitoring.component.scss

@ -0,0 +1,17 @@
.topbox {
form {
display: flex;
nz-form-item {
margin-right: 6px;
}
button {
margin-right: 6px;
}
}
.searchParams {
width: 250px;
}
}

270
src/app/system-management/condition-monitoring/condition-monitoring.component.ts

@ -0,0 +1,270 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { TreeService } from 'src/app/service/tree.service';
import { FileComponent } from './file/file.component';
import { ModelComponent } from './model/model.component';
@Component({
selector: 'app-condition-monitoring',
templateUrl: './condition-monitoring.component.html',
styleUrls: ['./condition-monitoring.component.scss']
})
export class ConditionMonitoringComponent implements OnInit {
constructor(private http: HttpClient, private fb: FormBuilder, private toTree: TreeService, private message: NzMessageService, private modal: NzModalService, private viewContainerRef: ViewContainerRef) { }
validateForm!: FormGroup;
ngOnInit(): void {
this.validateForm = this.fb.group({
organization: [null],
state: [null]
});
this.getAllOrganization()
}
//获取所有组织机构
nodes: any = []
defaultOrId: string
defaultExpandedKeys = [];
getAllOrganization() {
let params = {
ContainsChildren: true,
pageSize: 9999
}
this.http.get('/api/Organizations', {
params: params
}).subscribe((data: any) => {
console.log('组织机构列表', data)
data.items.forEach(element => {
element.key = element.id
element.title = element.name
// element.selectable = false
});
this.nodes = [...this.toTree.toTree(data.items)]
this.defaultOrId = this.nodes[0].id
this.validateForm.value.organization = this.defaultOrId
this.getConditionMonitoring()
})
}
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
this.getConditionMonitoring()
}
resetForm(e: MouseEvent): void {
e.preventDefault();
this.validateForm.reset();
for (const key in this.validateForm.controls) {
this.validateForm.controls[key].markAsPristine();
this.validateForm.controls[key].updateValueAndValidity();
}
this.validateForm.patchValue({
organization: this.nodes[0].id,
});
this.PageNumber = 1
this.getConditionMonitoring()
}
listOfData: any
num: string
PageNumber: number = 1
isLoading = false
//获取盒子状态
getConditionMonitoring() {
let params = {
ContainsChildren: true,
OrganizationId: this.defaultOrId,
PageNumber: this.PageNumber,
PageSize: 10,
HubConnectionState: this.validateForm.value.state
}
this.isLoading = true
this.http.get('/api/EdgeDevices/Statuses', { params: params }).subscribe(
(data: any) => {
console.log(data)
this.isLoading = false
this.listOfData = data.items
this.num = data.totalCount
}, err => {
}
)
}
pageChange($event) {
this.PageNumber = $event
this.getConditionMonitoring()
}
checked = false;
loading
indeterminate = false;
listOfCurrentPageData: readonly any[] = [];
setOfCheckedId = new Set<number>();
updateCheckedSet(id: number, checked: boolean): void {
if (checked) {
this.setOfCheckedId.add(id);
} else {
this.setOfCheckedId.delete(id);
}
}
onCurrentPageDataChange(listOfCurrentPageData: readonly any[]): void {
this.listOfCurrentPageData = listOfCurrentPageData;
this.refreshCheckedStatus();
}
refreshCheckedStatus(): void {
const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled);
this.checked = listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id));
this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked;
}
onItemChecked(id: number, checked: boolean): void {
this.updateCheckedSet(id, checked);
this.refreshCheckedStatus();
}
onAllChecked(checked: boolean): void {
this.listOfCurrentPageData
.filter(({ disabled }) => !disabled)
.forEach(({ id }) => this.updateCheckedSet(id, checked));
this.refreshCheckedStatus();
}
sendRequest(type): void {
const requestData = this.listOfData.filter(data => this.setOfCheckedId.has(data.id));
let strArr = []
requestData.forEach(element => {
strArr.push(element.id)
});
let body
if (type != 'UpdateModels') {
this.loading = type;
body = {
edgeDeviceIds: strArr
}
this.http.patch('/api/EdgeDevices/Commands', body, { params: { command: type } }).subscribe({
next: (data: any) => {
this.message.create('success', '通知边缘盒子成功,请过一段时间手动刷新尝试!');
console.log(data)
if (data.failedItems.length != 0) {
data.failedItems.forEach(element => {
this.message.create('info', element.detail);
});
}
this.setOfCheckedId.clear();
this.refreshCheckedStatus();
this.loading = null;
this.getConditionMonitoring()
},
error: (err) => {
this.loading = null;
}
})
} else {
const modal = this.modal.create({
nzTitle: '选择更新模型类型',
nzContent: ModelComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {},
nzOnOk: async () => {
// console.log(instance.validateForm.value.type)
if (instance.validateForm.valid) {
body = {
edgeDeviceIds: strArr,
modelNames: instance.validateForm.value.type
}
await new Promise(resolve => {
this.http.patch('/api/EdgeDevices/Commands', body, { params: { command: type } }).subscribe({
next: (data: any) => {
resolve(data)
this.message.create('success', '通知边缘盒子成功,请过一段时间手动刷新尝试!');
if (data.failedItems.length != 0) {
data.failedItems.forEach(element => {
this.message.create('info', element.detail);
});
}
this.setOfCheckedId.clear();
this.refreshCheckedStatus();
this.loading = null;
this.getConditionMonitoring()
return true
},
error: (err) => {
resolve(err)
this.loading = null;
return false
}
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
}
file() {
const requestData = this.listOfData.filter(data => this.setOfCheckedId.has(data.id));
let strArr = []
requestData.forEach(element => {
strArr.push(element.id)
});
const modal = this.modal.create({
nzTitle: '配置文件',
nzContent: FileComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 500,
nzComponentParams: {},
nzOnOk: async () => {
if (instance.validateForm.valid) {
let body = {
edgeDeviceIds: strArr,
scheme: instance.validateForm.value.scheme,
host: instance.validateForm.value.host,
port: instance.validateForm.value.port,
maxRetries: instance.validateForm.value.maxRetries
}
await new Promise(resolve => {
this.loading = 'file'
this.http.patch('/api/EdgeDevices/Commands/PushMonitorSettingsJson', body).subscribe({
next: (data: any) => {
this.message.create('success', '通知边缘盒子成功,请过一段时间手动刷新尝试!');
// console.log(data)
if (data.failedItems.length != 0) {
data.failedItems.forEach(element => {
this.message.create('info', element.detail);
});
}
this.setOfCheckedId.clear();
this.refreshCheckedStatus();
this.getConditionMonitoring()
this.loading = null;
},
error: (err) => {
this.loading = null;
}
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
}

36
src/app/system-management/condition-monitoring/file/file.component.html

@ -0,0 +1,36 @@
<div class="box">
<form nz-form [formGroup]="validateForm" class="formbox">
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="scheme">协议</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="scheme" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="host">主机/ip</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="host" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="port">端口</nz-form-label>
<nz-form-control>
<nz-input-group>
<input type="number" nz-input formControlName="port" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="maxRetries">最大重试次数</nz-form-label>
<nz-form-control>
<nz-input-group>
<input type="number" nz-input formControlName="maxRetries" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/condition-monitoring/file/file.component.scss

27
src/app/system-management/condition-monitoring/file/file.component.ts

@ -0,0 +1,27 @@
import { Component, OnInit } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-file',
templateUrl: './file.component.html',
styleUrls: ['./file.component.scss']
})
export class FileComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
scheme: [null, [Validators.required]],
host: [null, [Validators.required]],
port: [null, [Validators.required]],
maxRetries: [null, [Validators.required]]
});
}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
}
}

18
src/app/system-management/condition-monitoring/model/model.component.html

@ -0,0 +1,18 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control>
<nz-select nzMode="multiple" formControlName="type" nzPlaceHolder="请选择类型">
<nz-option [nzValue]="'peoplenet'" nzLabel="peoplenet"></nz-option>
<nz-option [nzValue]="'trafficcam'" nzLabel="trafficcam"></nz-option>
<nz-option [nzValue]="'actionnet'" nzLabel="actionnet"></nz-option>
<nz-option [nzValue]="'idnet'" nzLabel="idnet"></nz-option>
<nz-option [nzValue]="'oilnet'" nzLabel="oilnet"></nz-option>
<nz-option [nzValue]="'smoking_calling_net'" nzLabel="smoking_calling_net"></nz-option>
<nz-option [nzValue]="'connet'" nzLabel="connet"></nz-option>
<nz-option [nzValue]="'fire_smoke_net'" nzLabel="fire_smoke_net"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/condition-monitoring/model/model.component.scss

24
src/app/system-management/condition-monitoring/model/model.component.ts

@ -0,0 +1,24 @@
import { Component, OnInit } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-model',
templateUrl: './model.component.html',
styleUrls: ['./model.component.scss']
})
export class ModelComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
type: [null, [Validators.required]],
});
}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
}
}

15
src/app/system-management/config-form/config-form.component.html

@ -0,0 +1,15 @@
<div class="box">
<nz-page-header class="site-page-header" (nzBack)="goback()" nzBackIcon nzSubtitle="返回上一页"></nz-page-header>
<div class="content">
<nz-tabset>
<nz-tab nzTitle="config_nvdsanalytics.txt"><textarea name="config1" id="config1" [(ngModel)]="config1"></textarea>
</nz-tab>
<nz-tab nzTitle="config.yaml"> <textarea name="config2" id="config2" [(ngModel)]="config2"></textarea></nz-tab>
<nz-tab nzTitle="producer.yaml"> <textarea name="config3" id="config3" [(ngModel)]="config3"></textarea></nz-tab>
<!-- <nz-tab nzTitle="source.yaml"> <textarea name="config4" id="config4" [(ngModel)]="config4"></textarea></nz-tab> -->
</nz-tabset>
</div>
<div class="btnbox">
<button nz-button nzType="primary" (click)="putConfig()">下发算法配置</button>
</div>
</div>

29
src/app/system-management/config-form/config-form.component.scss

@ -0,0 +1,29 @@
.box {
width: 100%;
height: 100%;
background: #fff;
font-size: 15px;
color: black;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.content{
flex: 1;
box-sizing: border-box;
padding: 0 12px;
nz-tabset{
height: 100%;
}
textarea{
width: 100%;
height: 100%;
}
}
.btnbox{
display: flex;
justify-content: center;
align-items: center;
height: 52px;
}

76
src/app/system-management/config-form/config-form.component.ts

@ -0,0 +1,76 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ConfigFormDataService } from 'src/app/service/configFormData.service';
@Component({
selector: 'app-config-form',
templateUrl: './config-form.component.html',
styleUrls: ['./config-form.component.scss']
})
export class ConfigFormComponent implements OnInit {
constructor(public configFormData: ConfigFormDataService, private http: HttpClient, private route: ActivatedRoute, private message: NzMessageService) { }
config1: string
config2: string
config3: string
// config4: string
hostId//主机id
orId//加油站id
ngOnInit(): void {
this.hostId = this.route.snapshot.queryParams.hostId
this.orId = this.route.snapshot.queryParams.orId
this.config1 = sessionStorage.getItem('config1')
this.config2 = sessionStorage.getItem('config2')
this.config3 = sessionStorage.getItem('config3')
// this.config4 = sessionStorage.getItem('config4')
}
goback() {
history.go(-1)
}
putConfig() {
let body = {
configFiles: [
{ name: 'config_nvdsanalytics.txt', content: this.config1 },
{ name: 'config.yaml', content: this.config2 },
{ name: 'producer.yaml', content: this.config3 },
// { name: 'source.yaml', content: this.config4 }
]
}
this.http.put(`/api/EdgeDevices/${this.hostId}`, body).subscribe({
next: (data) => {
this.message.create('success', `文件保存成功`);
let promiseArr = []
body.configFiles.forEach(element => {
let params = {
edgeDeviceId: this.hostId,
fileName: element.name
}
promiseArr.push(
new Promise((resolve, reject) => {
this.http.put('/api/EdgeDevices/Commands/PushFile', '', { params: params }).subscribe({
next: (data) => {
resolve('成功了')
},
error: err => {
reject('失败了')
}
})
})
)
});
Promise.all(promiseArr).then((result) => {
this.message.create('success', `发送文件名成功`);
}).catch((error) => {
// this.message.create('error', `发送文件名失败`);
console.log('发送文件名失败', error)
})
},
error: (err) => {
this.message.create('error', `文件保存失败`);
}
})
}
}

75
src/app/system-management/host-config/addcamera/addcamera.component.html

@ -0,0 +1,75 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="name">名称</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="name" placeholder="请输入名称" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="user">用户名</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="user" placeholder="请输入用户名" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="password">密码</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="password" placeholder="请输入密码" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="uri">地址</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="uri" placeholder="请输入地址" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="type">类型</nz-form-label>
<nz-form-control>
<nz-select formControlName="type" nzPlaceHolder="请选择类型">
<nz-option [nzValue]="0" nzLabel="进出口"></nz-option>
<nz-option [nzValue]="1" nzLabel="加油区"></nz-option>
<nz-option [nzValue]="2" nzLabel="卸油区"></nz-option>
<nz-option [nzValue]="3" nzLabel="便利店"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="type">序号</nz-form-label>
<nz-form-control>
<nz-select formControlName="order" nzPlaceHolder="请选择序号">
<nz-option [nzValue]="0" nzLabel="0"></nz-option>
<nz-option [nzValue]="1" nzLabel="1"></nz-option>
<nz-option [nzValue]="2" nzLabel="2"></nz-option>
<nz-option [nzValue]="3" nzLabel="3"></nz-option>
<nz-option [nzValue]="4" nzLabel="4"></nz-option>
<nz-option [nzValue]="5" nzLabel="5"></nz-option>
<nz-option [nzValue]="6" nzLabel="6"></nz-option>
<nz-option [nzValue]="7" nzLabel="7"></nz-option>
<nz-option [nzValue]="8" nzLabel="8"></nz-option>
<nz-option [nzValue]="9" nzLabel="9"></nz-option>
<nz-option [nzValue]="10" nzLabel="10"></nz-option>
<nz-option [nzValue]="11" nzLabel="11"></nz-option>
<nz-option [nzValue]="12" nzLabel="12"></nz-option>
<nz-option [nzValue]="13" nzLabel="13"></nz-option>
<nz-option [nzValue]="14" nzLabel="14"></nz-option>
<nz-option [nzValue]="15" nzLabel="15"></nz-option>
<nz-option [nzValue]="16" nzLabel="16"></nz-option>
<nz-option [nzValue]="17" nzLabel="17"></nz-option>
<nz-option [nzValue]="18" nzLabel="18"></nz-option>
<nz-option [nzValue]="19" nzLabel="19"></nz-option>
<nz-option [nzValue]="20" nzLabel="20"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item> -->
</form>
</div>

0
src/app/system-management/host-config/addcamera/addcamera.component.scss

50
src/app/system-management/host-config/addcamera/addcamera.component.ts

@ -0,0 +1,50 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
@Component({
selector: 'app-addcamera',
templateUrl: './addcamera.component.html',
styleUrls: ['./addcamera.component.scss']
})
export class AddcameraComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
const { namevalidate } = MyValidators;
this.validateForm = this.fb.group({
name: [null, [Validators.required, namevalidate]],
user: [null, [Validators.required]],
password: [null, [Validators.required]],
uri: [null, [Validators.required]],
type: [null, [Validators.required]],
// order: [null, [Validators.required]],
});
}
}
export type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;
export type MyValidationErrors = Record<string, MyErrorsOptions>;
export class MyValidators extends Validators {
static namevalidate(control: AbstractControl): MyValidationErrors | null {
const value = control.value;
if (isEmptyInputValue(value)) {
return null;
}
return isPassword(value) ? null : { mobile: { 'zh-cn': `名称只能是汉字、大小写英文、数字,不能使用特殊字符`, en: `not valid` } };
}
}
function isEmptyInputValue(value: NzSafeAny): boolean {
return value == null || value.length === 0;
}
function isPassword(value: string): boolean {
return typeof value === 'string' && /^[\u4E00-\u9FA5A-Za-z0-9]+$/.test(value);
}

75
src/app/system-management/host-config/editcamera/editcamera.component.html

@ -0,0 +1,75 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="name">名称</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="name" placeholder="请输入名称" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="user">用户名</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="user" placeholder="请输入用户名" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="password">密码</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="password" placeholder="请输入密码" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="uri">地址</nz-form-label>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="uri" placeholder="请输入地址" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="type">类型</nz-form-label>
<nz-form-control>
<nz-select formControlName="type" nzPlaceHolder="请选择类型">
<nz-option [nzValue]="0" nzLabel="进出口"></nz-option>
<nz-option [nzValue]="1" nzLabel="加油区"></nz-option>
<nz-option [nzValue]="2" nzLabel="卸油区"></nz-option>
<nz-option [nzValue]="3" nzLabel="便利店"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="type">序号</nz-form-label>
<nz-form-control>
<nz-select formControlName="order" nzPlaceHolder="请选择序号">
<nz-option [nzValue]="0" nzLabel="0"></nz-option>
<nz-option [nzValue]="1" nzLabel="1"></nz-option>
<nz-option [nzValue]="2" nzLabel="2"></nz-option>
<nz-option [nzValue]="3" nzLabel="3"></nz-option>
<nz-option [nzValue]="4" nzLabel="4"></nz-option>
<nz-option [nzValue]="5" nzLabel="5"></nz-option>
<nz-option [nzValue]="6" nzLabel="6"></nz-option>
<nz-option [nzValue]="7" nzLabel="7"></nz-option>
<nz-option [nzValue]="8" nzLabel="8"></nz-option>
<nz-option [nzValue]="9" nzLabel="9"></nz-option>
<nz-option [nzValue]="10" nzLabel="10"></nz-option>
<nz-option [nzValue]="11" nzLabel="11"></nz-option>
<nz-option [nzValue]="12" nzLabel="12"></nz-option>
<nz-option [nzValue]="13" nzLabel="13"></nz-option>
<nz-option [nzValue]="14" nzLabel="14"></nz-option>
<nz-option [nzValue]="15" nzLabel="15"></nz-option>
<nz-option [nzValue]="16" nzLabel="16"></nz-option>
<nz-option [nzValue]="17" nzLabel="17"></nz-option>
<nz-option [nzValue]="18" nzLabel="18"></nz-option>
<nz-option [nzValue]="19" nzLabel="19"></nz-option>
<nz-option [nzValue]="20" nzLabel="20"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/host-config/editcamera/editcamera.component.scss

32
src/app/system-management/host-config/editcamera/editcamera.component.ts

@ -0,0 +1,32 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { MyValidators } from '../addcamera/addcamera.component';
@Component({
selector: 'app-editcamera',
templateUrl: './editcamera.component.html',
styleUrls: ['./editcamera.component.scss']
})
export class EditcameraComponent implements OnInit {
@Input() data: any
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
const { namevalidate } = MyValidators;
let datacopy = JSON.parse(JSON.stringify(this.data))
console.log('编辑数据', datacopy)
this.validateForm = this.fb.group({
name: [datacopy.name, [Validators.required,namevalidate]],
user: [datacopy.user, [Validators.required]],
password: [datacopy.password, [Validators.required]],
uri: [datacopy.uri, [Validators.required]],
type: [datacopy.type, [Validators.required]],
order: [datacopy.order, [Validators.required]]
});
}
}

66
src/app/system-management/host-config/host-config.component.html

@ -0,0 +1,66 @@
<div class="box">
<div class="leftbox">
<nz-page-header class="site-page-header" (nzBack)="goback()" nzBackIcon nzSubtitle="返回上一页"></nz-page-header>
<div class="cameraList">
<div class="title">
<span>摄像头列表</span>
<button nz-button nzType="primary" (click)="addCamera()">新增摄像头</button>
</div>
<nz-table #basicTable [nzData]="listOfData" [nzShowPagination]="false" [nzLoading]="isLoading">
<thead>
<tr>
<th>序号</th>
<th>名称</th>
<th>用户名</th>
<th>密码</th>
<th>地址</th>
<th>类型</th>
<th>标注情况</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of basicTable.data">
<td>{{ item.order }}</td>
<td>{{ item.name }}</td>
<td>{{ item.user }}</td>
<td>{{ item.password }}</td>
<td>{{ item.uri }}</td>
<td>{{ item.type | cameraType}}</td>
<td>
<ng-container *ngIf="item.type == 1; else elseTemplate">
不需要标注
</ng-container>
<ng-template #elseTemplate>
{{item.dimensionedPoints ? '已标注' : '未标注'}}
</ng-template>
</td>
<td>{{ item.isEnabled ? '已启用' : '已禁用'}}</td>
<td>
<span class="blue" style="margin-right: 12px;" (click)="editCamera(item)">编辑</span>
<span class="blue" style="margin-right: 12px;" [ngClass]="{'forbid': item.type == 1}"
(click)="label(item)">标注</span>
<ng-container *ngIf="item.isEnabled; else elseTemplate2">
<span class="red" style="margin-right: 12px;" (click)="forbidden(item)">禁用</span>
</ng-container>
<ng-template #elseTemplate2>
<span class="blue" style="margin-right: 12px;color: rgb(26, 173, 26);" (click)="forbidden(item)">启用</span>
</ng-template>
<span class="red" (click)="deleteCamera(item)">删除</span>
</td>
</tr>
</tbody>
</nz-table>
<div class="footer">
<button nz-button nzType="primary" (click)="sourceYaml()">下发source.yaml配置</button>
</div>
<div class="footer">
<button [disabled]="isSourceYaml === false" nz-button nzType="primary" (click)="connect()">下发算法配置</button>
</div>
</div>
</div>
<div class="rightbox">
</div>
</div>

43
src/app/system-management/host-config/host-config.component.scss

@ -0,0 +1,43 @@
.box {
width: 100%;
height: 100%;
display: flex;
background: #fff;
font-size: 15px;
color: black;
}
.leftbox {
width: 100%;
height: 100%;
border-right: 1px solid #F2F2F2;
box-sizing: border-box;
display: flex;
flex-direction: column;
.cameraList {
flex: 1;
padding: 0 20px;
.title {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.footer{
width: 100%;
display: flex;
justify-content: center;
margin: 12px 0;
}
}
}
.rightbox {
flex: 1;
box-sizing: border-box;
padding: 20px;
}

593
src/app/system-management/host-config/host-config.component.ts

@ -0,0 +1,593 @@
import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { ActivatedRoute, Route, Router } from '@angular/router';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { NzFormTooltipIcon } from 'ng-zorro-antd/form';
import { NzModalService } from 'ng-zorro-antd/modal';
import { AddcameraComponent } from './addcamera/addcamera.component';
import { NzMessageService } from 'ng-zorro-antd/message';
import { HttpClient, HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { EditcameraComponent } from './editcamera/editcamera.component';
import { catchError, tap } from 'rxjs/operators';
import { ConfigFormDataService } from 'src/app/service/configFormData.service';
import { SendFileComponent } from './send-file/send-file.component';
import { ImageLabel2Component } from '../image-label2/image-label2.component';
interface Camera {
name: string;
user: string;
password: string;
uri: string;
type: number;
order: number;
dimensionedPoints: string,
isEnabled: boolean
}
@Component({
selector: 'app-host-config',
templateUrl: './host-config.component.html',
styleUrls: ['./host-config.component.scss']
})
export class HostConfigComponent implements OnInit {
constructor(private router: Router, private route: ActivatedRoute, private fb: FormBuilder, private modal: NzModalService, private message: NzMessageService, private viewContainerRef: ViewContainerRef, private http: HttpClient, public configFormData: ConfigFormDataService,) { }
hostId//主机id
orId//加油站id
ngOnInit(): void {
this.hostId = this.route.snapshot.queryParams.hostId
this.orId = this.route.snapshot.queryParams.orId
this.getCamera()
this.http.get(`/api/EdgeDevices/${this.hostId}`).subscribe(
{
next: ((data: any) => {
console.log(data)
// let isExist = data.configFiles.find((item, index, arr) => {
// if (item.name == 'source.yaml') {
// console.log("存在", index)
// return item
// }
// })
if (data.configFiles && data.configFiles.length != 0) {
this.isSourceYaml = true
} else {
this.isSourceYaml = false
}
}),
error: (err) => {
// this.message.create('error', '请先下发source.yaml配置');
}
}
)
}
listOfData: Camera[] = [];
goback() {
history.go(-1)
}
//摄像头
isLoading = false
getCamera() {
let params = {
ContainsChildren: true,
EdgeDeviceId: this.hostId
}
this.isLoading = true
this.http.get('/api/Cameras', { params: params }).subscribe((data: any) => {
data.items.forEach(element => {
element.dimensionedPointsObj = JSON.parse(element.dimensionedPoints)
});
this.listOfData = data.items
this.isLoading = false
console.log('摄像头列表', data.items)
})
}
addCamera() {
const modal = this.modal.create({
nzTitle: '新增加油站摄像头',
nzContent: AddcameraComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 388,
nzComponentParams: {},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise((resolve, rejects) => {
console.log('表单信息', instance.validateForm)
let body = {
name: instance.validateForm.value.name,
user: instance.validateForm.value.user,
password: instance.validateForm.value.password,
uri: instance.validateForm.value.uri,
type: instance.validateForm.value.type,
organizationId: this.orId,
edgeDeviceId: this.hostId,
// order: instance.validateForm.value.order,
}
this.http.post('/api/Cameras', body).subscribe({
next: data => {
resolve(data)
this.message.create('success', '创建成功!');
this.getCamera()
this.isSourceYaml = false
return true
},
error: (err) => {
rejects(err)
return false
}
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
editCamera(data) {
console.log(data)
const modal = this.modal.create({
nzTitle: '编辑加油站摄像头',
nzContent: EditcameraComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 388,
nzComponentParams: {
data: data
},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise(resolve => {
console.log('表单信息', instance.validateForm)
let body = {
name: instance.validateForm.value.name,
user: instance.validateForm.value.user,
password: instance.validateForm.value.password,
uri: instance.validateForm.value.uri,
type: instance.validateForm.value.type,
organizationId: this.orId,
edgeDeviceId: this.hostId,
order: instance.validateForm.value.order,
}
this.http.put(`/api/Cameras/${data.id}`, body).subscribe(data => {
resolve(data)
this.message.create('success', '编辑成功!');
this.getCamera()
this.isSourceYaml = false
return true
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
deleteCamera(item) {
console.log(item)
this.modal.confirm({
nzTitle: `确定要删除${item.name}这个摄像头吗?`,
nzOkText: '确定',
nzOkType: 'default',
nzOnOk: () => {
this.http.delete(`/api/Cameras/${item.id}`).subscribe(data => {
this.message.create('success', '删除成功!');
this.getCamera()
this.isSourceYaml = false
})
},
nzCancelText: '取消'
});
}
isSourceYaml: boolean
label(item) {
this.http.get(`/api/EdgeDevices/${this.hostId}`).subscribe(
{
next: ((data: any) => {
if (data.configFiles) {
this.isSourceYaml = true
const element = document.documentElement
if (element.requestFullscreen) { //进入全屏
element.requestFullscreen();
}
const modal = this.modal.create({
nzContent: ImageLabel2Component,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 1920,
nzClosable: false,
nzFooter: null,
nzWrapClassName: 'canvasContentBox',
nzBodyStyle: {
'border-radius': '0px',
'padding': '0px',
'margin': '0px',
},
nzComponentParams: {
data: item.id
},
nzOnOk: async () => {
}
});
const instance = modal.getContentComponent();
modal.afterClose.subscribe(result => {
this.ngOnInit()
});
//this.router.navigate(['/system/host/camera/imageLabel'], { queryParams: { id: item.id } })
} else {
this.isSourceYaml = false
this.message.create('error', '请先下发source.yaml配置');
}
}),
error: (err) => {
// this.message.create('error', '请先下发source.yaml配置');
}
}
)
}
connect() {
// let isAllLabel = this.listOfData.find((item: any) => {
// if (item.type != 1 && !item.dimensionedPoints) {
// console.log('存在摄像头未标注的情况')
// return item
// }
// })
// if (isAllLabel) {
// this.message.create('error', '存在摄像头未标注的情况');
// return
// }
// let ids = []
// this.listOfData.forEach((item: any) => {
// ids.push(item.id)
// })
// this.http.get('/api/Cameras/Statuses', {
// params: { ids: ids }
// }).subscribe({
// next: (data) => {
// console.log('连接状态', data)
// },
// error: (err) => {
// console.log('连接失败', err)
// }
// })
this.disposalData()
this.router.navigate(['/system/host/camera/configForm'], { queryParams: { 'hostId': this.hostId, 'orId': this.orId } })
}
forbidden(item) {
console.log(item)
let body = {
isEnabled: !item.isEnabled,
}
this.http.put(`/api/Cameras/${item.id}`, body).subscribe(data => {
this.message.create('success', '修改成功!');
this.getCamera()
})
}
sourceYaml() {
let copyListOfData = JSON.parse(JSON.stringify(this.listOfData))
copyListOfData = copyListOfData.filter((item, i) => {
return item.isEnabled;
})
let config4 = `video_rate: 5
inference_buffer_second: 6
sources:`
copyListOfData.forEach((item: any, index) => {
config4 += `
- name: '${item.name}'
user: '${item.user}'
password: '${item.password}'
uri: '${item.uri}'
type: ${item.type}
`
})
const modal = this.modal.create({
nzTitle: '下发source.yaml配置',
nzContent: SendFileComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 1000,
nzBodyStyle: {
'border-radius': '0px',
'padding': '7px',
},
nzComponentParams: {
data: config4
},
nzOnOk: async () => {
await new Promise(resolve => {
console.log('表单信息', instance.validateForm)
let body = {
configFiles: [
{ name: 'source.yaml', content: instance.datacopy }
]
}
this.http.put(`/api/EdgeDevices/${this.hostId}`, body).subscribe({
next: (data) => {
this.message.create('success', `文件保存成功`);
resolve('成功了')
this.isSourceYaml = true
let params = {
edgeDeviceId: this.hostId,
fileName: 'source.yaml'
}
this.http.put('/api/EdgeDevices/Commands/PushFile', '', { params: params }).subscribe({
next: (data) => {
this.message.create('success', `发送文件名成功`);
},
error: err => {
// this.message.create('error', `发送文件名失败`);
// reject('失败了')
}
})
},
error: (err) => {
// this.message.create('error', `文件保存失败`);
}
})
})
}
});
const instance = modal.getContentComponent();
}
//整理配置文件数据
disposalData() {
let copyListOfData = JSON.parse(JSON.stringify(this.listOfData))
copyListOfData = copyListOfData.filter((item, i) => {
return item.isEnabled;
})
console.log(copyListOfData)
let config1 = `[property]
enable=1
#Width height used for configuration to which below configs are configured
config-width=1980
config-height=1080
#osd-mode 0: Dont display any lines, rois and text
# 1: Display only lines, rois and static text i.e. labels
# 2: Display all info from 1 plus information about counts
osd-mode=2
#Set OSD font size that has to be displayed
display-font-size=12
`
let config2 = ''
let config3 = `test_action: true
logging_interval : 600
`
let xieyouqu = []
let order
copyListOfData.forEach((item: any, index) => {
if (item.type == 2) {
xieyouqu.push(item)
order = item.order
}
if (item.type == 0 && item.dimensionedPointsObj && item.dimensionedPointsObj.polygon.length != 0) {
let str = ''
item.dimensionedPointsObj ? item.dimensionedPointsObj.polygon.forEach(element => {
str += element.x + ';'
str += element.y + ';'
}) : 0;
str = str.substring(0, str.lastIndexOf(';'))
console.log('进出口多边形', str)
config1 += `
## Per stream configuration
[roi-filtering-stream-${item.order}]
#shoushiyuan-out202
#enable or disable following feature
enable=1
#ROI to filter select objects, and remove from meta data
roi-RF=${str}
#remove objects in the ROI
inverse-roi=0
class-id=-1
`
}
if ((item.type == 2 || item.type == 3) && item.dimensionedPointsObj && item.dimensionedPointsObj.arrow.length != 0) {
let arrowArr = item.dimensionedPointsObj.arrow
let str = arrowArr[1].startX + ';' + arrowArr[1].startY + ';' + arrowArr[1].endX + ';' + arrowArr[1].endY + ';' + arrowArr[0].startX + ';' + arrowArr[0].startY + ';' + arrowArr[0].endX + ';' + arrowArr[0].endY
config1 += `
[line-crossing-stream-${item.order}]
enable=1
#Label;direction;lc
line-crossing-Entry=${str}
# line-crossing-Exit=789;672;1084;900;851;773;1203;732
class-id=0
#extended when 0- only counts crossing on the configured Line
# 1- assumes extended Line crossing counts all the crossing
extended=0
#LC modes supported:
#loose : counts all crossing without strong adherence to direction
#balanced: Strict direction adherence expected compared to mode=loose
#strict : Strict direction adherence expected compared to mode=balanced
mode=strict
`
}
})
//新增东南西北参数
copyListOfData.forEach(element => {
if (element.type == 2 || element.type == 3) {//卸油区
let obj = element.dimensionedPointsObj
let str1 = ''
if (obj && obj.arrow && obj.arrow.length == 2) {
str1 = `${obj.arrow[1].startX};${obj.arrow[1].startY};${obj.arrow[1].endX};${obj.arrow[1].endY}`
}
let str2 = ''
if (obj && obj.arrowOfWest && obj.arrowOfWest.length == 2) {
str2 = `${obj.arrowOfWest[1].startX};${obj.arrowOfWest[1].startY};${obj.arrowOfWest[1].endX};${obj.arrowOfWest[1].endY}`
}
if (str1 || str2) {
let arr = [
{ name: 'South', value: str1 },
{ name: 'West', value: str2 }
]
let newstr = ''
arr.forEach(item => {
if (item.value) {
newstr += `direction-${item.name}=${item.value}
`
}
});
config1 += `
[direction-detection-stream-${element.order}]
enable=1
#Label;direction;
${newstr}class-id=0
`
}
}
});
let xieyouguan = '';
let jingdian = '';
if (xieyouqu.length != 0 && xieyouqu[0].dimensionedPointsObj && xieyouqu[0].dimensionedPointsObj.rectangle.length != 0) {
xieyouqu[0].dimensionedPointsObj.rectangle.forEach(element => {
if (element.oilUnloadingArea) {
xieyouguan = element.x + ',' + element.y + ',' + element.width + ',' + element.height
} else {
jingdian = element.x + ',' + element.y + ',' + element.width + ',' + element.height
}
})
} else {
xieyouguan = '0,0,0,0'
jingdian = '0,0,0,0'
}
(order != undefined) ? null : order = copyListOfData[copyListOfData.length - 1].order + 1
console.log('泄油管区域', xieyouguan)
console.log('静电接地', jingdian)
config2 = `# The all in one config file.
# RTSP sources
# type
# 0 ViolateArea.ENTRANCE,
# 1 ViolateArea.GAS_AREA,
# 2 ViolateArea.FUEL_AREA,
# 3 ViolateArea.MART,
# don't change the key name.
debug: false #when the debug is on, osd.
video_record: 3 #time to record into the .ts video
sources:
config: 'config/source.yaml'
tracker:
config: 'config/dstest_tracker_config.txt'
analytics:
config: 'config/config_nvdsanalytics.txt'
peoplenet:
enable: true
apply_on: -1
interval: 1
batch_size: 16
topk: 5
roi-top-offset: 0
roi-bottom-offset: 0
detected-min-w: 20
detected-min-h: 200
trafficcam:
enable: true
apply_on: 0
interval: 1
batch_size: 16
topk: 5
roi-top-offset: 0
roi-bottom-offset: 0
detected-min-w: 100
detected-min-h: 100
actionnet:
enable: false
apply_on: 1
# roi:
# - 'fuel_island-4':
# - [200, 0, 450, 500]
# - 'fuel_island-5':
# - [930, 93, 940, 987]
# - 'fuel_island-6':
# - [1174, 151, 746, 929]
# - 'fuel_island-7':
# - [1450, 300, 460, 650]
interval: 1
batch_size: 32
idnet:
enable: true
apply_on: -1
interval: 1
batch_size: 32
oilnet:
enable: true
apply_on: 2
interval: 1
batch_size: 16
roi-top-offset: 0
roi-bottom-offset: 0
detected-min-w: 20
detected-min-h: 20
fire_smoke_net:
enable: true
apply_on: -1
interval: 1
batch_size: 16
smoking_calling_net:
enable: true
apply_on: -1
interval: 1
batch_size: 32
connet:
enable: true
apply_on: 2
roi:
- 'oil_tube-${order}':
- [${xieyouguan}]
- 'grounder-${order}':
- [${jingdian}]
interval: 1
batch_size: 2
#new field for rule threshold
rule_threshold:
object_occurence_interval_second: 3
object_disappear_interval_second: 10
on_car_parking_interval_second: 1800
on_fire_smoke_interval_second: 5
threshold_relying_sitting: 0.4 #rolling mean confidence
threshold_smoking_calling: 0.3 #rolling mean confidence
threshold_connecting: 0.667 #rolling mean confidence
threshold_identity: 0.5 #only to filter out people net error
`
sessionStorage.setItem('config1', config1)
sessionStorage.setItem('config2', config2)
sessionStorage.setItem('config3', config3)
}
}

5
src/app/system-management/host-config/send-file/send-file.component.html

@ -0,0 +1,5 @@
<div class="box">
<div class="content">
<textarea name="config" id="config" [(ngModel)]="datacopy"></textarea>
</div>
</div>

20
src/app/system-management/host-config/send-file/send-file.component.scss

@ -0,0 +1,20 @@
.box {
width: 100%;
height: 100%;
background: #fff;
font-size: 15px;
color: black;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.content {
flex: 1;
box-sizing: border-box;
textarea {
width: 100%;
height: 400px;
}
}

23
src/app/system-management/host-config/send-file/send-file.component.ts

@ -0,0 +1,23 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-send-file',
templateUrl: './send-file.component.html',
styleUrls: ['./send-file.component.scss']
})
export class SendFileComponent implements OnInit {
@Input() data: any
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
datacopy
ngOnInit(): void {
this.datacopy = JSON.parse(JSON.stringify(this.data))
console.log(this.datacopy)
}
putConfig() {
}
}

12
src/app/system-management/image-label/image-label.component.html

@ -0,0 +1,12 @@
<div class="box" id="canvasBox">
<div class="btnbox">
<button nz-button [ngClass]="{selectBtn: markType}" (click)="markType = true;">标注监控区域</button>
<button nz-button [ngClass]="{selectBtn: !markType}" (click)="markType = false;">标注禁止区域</button>
<button nz-button nzType="primary" nzDanger (click)="clearCanvas()">清空</button>
</div>
<div class="imgbox" [style]="heightCount()">
<div class="content">
<div class="center" id="canvasCenter"><canvas id="canvas" [width]="canvasWidth" [height]="canvasHeight"></canvas></div>
</div>
</div>
</div>

26
src/app/system-management/image-label/image-label.component.scss

@ -0,0 +1,26 @@
.box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.btnbox {
margin-bottom: 5px;
button {
margin-right: 15px;
}
}
.selectBtn { background-color: #1890ff; color: #fff; }
.imgbox {
width: 100%;
height:500px;
overflow: hidden;
canvas{ overflow: hidden; }
.content,.center{
width: 100%;
height: 100%;
overflow: hidden;
}
}

216
src/app/system-management/image-label/image-label.component.ts

@ -0,0 +1,216 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-image-label',
templateUrl: './image-label.component.html',
styleUrls: ['./image-label.component.scss']
})
export class ImageLabelComponent implements OnInit {
constructor() { }
imgItem: any;
canvasWidth: number = 0;
canvasHeight: number = 0;
copyCanvas: any;
markType: boolean = true; //标注type
ngOnInit(): void {
}
ngAfterContentInit(): void {
this.initBackgroundImg()
}
//初始化背景图
initBackgroundImg() {
let canvas = document.getElementById('canvas') as any;
canvas.oncontextmenu = () =>{ return false; };
let that = this
let ctx
// 检测canvas支持性
if (canvas.getContext) {
ctx = canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性
} else {
document.write("你的浏览器不支持canvas,请升级你的浏览器!");
return;
}
// 读取可视区域 宽高
let center = (document.getElementById('canvasCenter') as any).getBoundingClientRect();
// 图片加载完后,将其显示在canvas中
var img = new Image();
img.src = that.imgItem.url? that.imgItem.url : "../../../assets/images/bgImg.png";
img.onload = () => {
// 等比例缩放图片
var scale = 1;
if (img.width > center.width || img.height > center.height) {
if (img.width > img.height) {
scale = center.width / img.width;
}else {
scale = center.height / img.height;
}
}
that.canvasWidth = img.width * scale;
that.canvasHeight = img.height * scale; // 计算等比缩小后图片
window.setTimeout(()=>{ // 加载图片
ctx.drawImage(img, 0, 0, that.canvasWidth, that.canvasHeight);
this.copyCanvas = ctx.getImageData(0, 0, that.canvasWidth, that.canvasHeight)
that.initCanvasEvent(canvas)
}, 0)
}
}
//线段的点的集合
points = [];
points2 = [];
//可拖动圆圈的点的集合
circles = [];
circles2 = [];
//整体移动点位
allpoints = [];
allpoints2 = [];
isDragging = false
//是否在绘制区域内
isInOut = false
//记录鼠标点击位置
downx = 0
downy = 0
//清空画布
clearCanvas() {
this.points = [];
this.points2 = [];
this.circles = [];
this.circles2 = [];
this.allpoints = [];
this.allpoints2 = [];
let canvas = document.getElementById('canvas') as any;
let context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
this.copyCanvas?context.putImageData(this.copyCanvas, 0, 0) : null;
}
//初始化 canvas画布 点击事件
initCanvasEvent(canvas) {
let context = canvas.getContext('2d');
let html = document.documentElement
let boxDiv = document.getElementsByClassName("canvasDialog")[0]
canvas.onmousedown = (e)=>{
var clickX = e.pageX - canvas.offsetLeft - ((html.clientWidth - boxDiv.clientWidth) / 2);
var clickY = e.pageY - canvas.offsetTop - ((html.clientHeight - boxDiv.clientHeight) / 2);
this.downx = clickX
this.downy = clickY
if (this.isInt(clickX, clickY)) {
this.isInOut = true
return
} else {
this.isInOut = false
}
let index
let beforeCircles = this.markType? this.circles: this.circles2
//判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
for (var i = 0; i < beforeCircles.length; i++) {
let circle = beforeCircles[i];
//使用勾股定理计算这个点与圆心之间的距离
var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2));
// 如果是其他的点,则设置可以拖动
if (distanceFromCenter <= circle.radius) {
// 清除之前选择的圆圈
index = i;
this.isDragging = true;
//停止搜索
return;
}
}
//如果点击新的位置,则进入下面的代码,绘制点
//context.clearRect(0, 0, canvas.width, canvas.height);
//遍历数组画圆
var circle = {
x: clickX,
y: clickY,
radius: 10,
color: "blue",
isSelected: false, //拖拽点的标记
};
if (this.markType) {
this.circles.push(circle);
this.allpoints = JSON.parse(JSON.stringify(this.circles))
this.circles[0].color = "green";
} else {
this.circles2.push(circle);
this.allpoints2 = JSON.parse(JSON.stringify(this.circles2))
this.circles2[0].color = "red";
}
for (var i = 0; i < beforeCircles.length; i++) {
let circle = beforeCircles[i];
// 绘制圆圈
context.globalAlpha = 0.85;
context.beginPath();
context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
context.fillStyle = circle.color;
context.strokeStyle = "black";
context.fill();
context.stroke();
}
// 画线
var point = {
x: clickX,
y: clickY,
};
this.markType? this.points.push(point) : this.points2.push(point)
context.beginPath();
context.lineWidth = 3;
//从起始点开始绘制
let beforePoint = this.markType? this.points: this.points2
context.moveTo(beforePoint[0].x, beforePoint[0].y);
for (var i = 0; i < beforePoint.length; i++) {
context.lineTo(beforePoint[i].x, beforePoint[i].y);
}
context.closePath()
context.fillStyle = "rgb(2,100,30)";
context.fill();
context.strokeStyle = "#9d4dca";
context.stroke();
}
}
//判断点位是否在图形区域内
isInt(x, y) {
if (this.markType && !this.points[2]) {
return
}
if (!this.markType && !this.points2[2]) {
return
}
var pt = {
x: x,
y: y
}
var poly = this.markType? this.points : this.points2;
return this.PointInPoly(pt, poly)
}
//射线法判断点位
PointInPoly(pt, poly) {
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
&& (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
&& (c = !c);
return c;
}
//cneter height
heightCount() {
let style: any = {}
let height = document.documentElement.clientHeight
style.height = (height - 180) + 'px';
return style
}
}

37
src/app/system-management/image-label2/image-label2.component.html

@ -0,0 +1,37 @@
<div class="canvasBox">
<!-- <nz-page-header class="site-page-header" (nzBack)="goback()" nzBackIcon nzSubtitle="返回上一页"></nz-page-header> -->
<div class="btnbox">
<label class="leftTitle" *ngIf="markType === 0">进出口</label>
<label class="leftTitle" *ngIf="markType === 2">卸油区</label>
<label class="leftTitle" *ngIf="markType === 3">便利店</label>
<button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: isDrawArrow && !arrowDirection}"
(click)="isDrawArrow = true;arrowDirection=null">箭头方向标绘1</button>
<!-- <button nz-button *ngIf="markType === 2"
[ngClass]="{selectBtn:(isDrawArrow && arrowDirection=='South')}"
(click)="isDrawArrow = true;arrowDirection='South'">South</button> -->
<button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: (isDrawArrow && arrowDirection=='West')}"
(click)="isDrawArrow = true;arrowDirection='West'">箭头方向标绘2</button>
<!-- <button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: (isDrawArrow && arrowDirection=='East')}"
(click)="isDrawArrow = true;arrowDirection='East'">East</button>
<button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: (isDrawArrow && arrowDirection=='North')}"
(click)="isDrawArrow = true;arrowDirection='North'">North</button> -->
<button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: !isDrawArrow && oilUnloadingArea}"
(click)="isDrawArrow = false; oilUnloadingArea = true;">泄油管区域</button>
<button nz-button *ngIf="markType === 2" [ngClass]="{selectBtn: !isDrawArrow && !oilUnloadingArea}"
(click)="isDrawArrow = false; oilUnloadingArea = false;">静电接地仪</button>
<button nz-button nzType="primary" (click)="anewgetImg()">重新捕获摄像头图片</button>
<button nz-button nzType="primary" (click)="save()">保存</button>
<button nz-button nzType="primary" nzDanger nz-popconfirm nzPopconfirmTitle="您确定要清空吗?"
(nzOnConfirm)="clearCanvas()">清空</button>
<label *ngIf="camerasData" class="rightTitle">原始分辨率: {{camerasData.originalWeight}} ×
{{camerasData.originalHeight}}</label>
<!-- <label *ngIf="markType === 2 && !isDrawArrow" class="rightTitle">当前矩形框高度为:{{rectangleHeight}}px,请确保低于420px</label> -->
</div>
<div class="imgbox">
<div class="content">
<div class="center" id="canvasCenter"><canvas id="canvas" [width]="canvasWidth" [height]="canvasHeight"></canvas>
</div>
</div>
</div>
</div>

38
src/app/system-management/image-label2/image-label2.component.scss

@ -0,0 +1,38 @@
.canvasBox {
width: 100%;
height: 100%;
background: #fff;
font-size: 15px;
color: black;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
.imgbox{ flex: 1; overflow: hidden; }
canvas{ overflow: hidden; display: block; }
.content,.center{
width: 100%;
height: 100%;
overflow: hidden;
}
}
.btnbox {
display: flex;
position: fixed;
left: 1%;
top: 1%;
z-index: 10;
button {
margin-right: 6px;
}
.leftTitle{ line-height: 32px; margin-right: 10px; color: #fff; }
.rightTitle{ line-height: 32px; margin-left: 10px; color: #fff; }
}
.imgbox,
.btnbox {
box-sizing: border-box;
padding: 0;
}
.selectBtn { background-color: #1890ff; color: #fff; }

647
src/app/system-management/image-label2/image-label2.component.ts

@ -0,0 +1,647 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, Input, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
@Component({
selector: 'app-image-label2',
templateUrl: './image-label2.component.html',
styleUrls: ['./image-label2.component.scss']
})
export class ImageLabel2Component implements OnInit {
constructor(private http: HttpClient, private message: NzMessageService, private modal: NzModalService) { }
@Input() data: any; //传递id
camerasData: any; //摄像头Data
imgItem: any; //图片 URL
canvasWidth: number = 0;
canvasHeight: number = 0;
copyCanvas: any; //拷贝 canvas底图
//返回上一步路由
goback() {
history.go(-1)
}
ngOnInit(): void {
}
ngAfterContentInit(): void {
this.getImgMarkData().then((res: any) => {
this.imgItem = window.URL.createObjectURL(res)
window.setTimeout(() => {
this.initBackgroundImg()
}, 0)
}).catch(err => {
this.message.create('error', '获取图片失败!');
})
}
anewgetImg() {
let params = {
cameraId: this.data
}
this.http.put('/api/Cameras/Commands/CaptureImages', '', { params: params }).subscribe(
{
next: (value: Object) => {
this.message.create('success', '向边缘设备发送请求成功,请过一段时间手动刷新页面!');
},
error: (error: HttpErrorResponse) => {
},
complete: () => {
}
}
)
}
//获取 摄像头图片/标注点位
getImgMarkData() {
let that = this
return new Promise((resolve, reject) => {
that.http.get(`/api/Cameras/${that.data}`).subscribe((info: any) => {
info.dimensionedPoints ? info.dimensionedPoints = JSON.parse(info.dimensionedPoints) : null;
that.camerasData = info;
that.markType = info.type;
console.log(that.camerasData, "摄像头数据")
const httpOptions = {
responseType: 'blob' as 'json',
params: { cameraId: that.data }
};
that.http.get(`/api/Cameras/Images`, httpOptions).subscribe({
next: (data) => {
resolve(data)
},
error: (err) => {
reject('error')
},
}) //get
}) //get
})
}
//保存
save() {
if (!this.camerasData.dimensionedPoints) {
this.camerasData.dimensionedPoints = {
polygon: [],
arrow: [],
arrowOfSouth: [],
arrowOfWest: [],
arrowOfEast: [],
arrowOfNorth: [],
rectangle: [],
}
}
if (this.markType === 0) {
if (!this.points.length) {
this.message.create('warning', '绘制完整后可保存!');
return
}
this.camerasData.dimensionedPoints.polygon = this.points
} else if (this.markType === 2) {
if (this.arrowPoints.length != 2 || this.oblongPoints.length != 2 || !this.oblongPoints.find(item => { return item.oilUnloadingArea }) || !this.oblongPoints.find(item => { return !item.oilUnloadingArea })) {
this.message.create('warning', '绘制完整后可保存!');
return
}
this.camerasData.dimensionedPoints.arrow = this.arrowPoints
this.camerasData.dimensionedPoints.arrowOfSouth = this.arrowPointsOfSouth
this.camerasData.dimensionedPoints.arrowOfWest = this.arrowPointsOfWest
this.camerasData.dimensionedPoints.arrowOfEast = this.arrowPointsOfEast
this.camerasData.dimensionedPoints.arrowOfNorth = this.arrowPointsOfNorth
this.camerasData.dimensionedPoints.rectangle = this.oblongPoints
} else if (this.markType === 3) {
if (this.arrowPoints.length != 2) {
this.message.create('warning', '绘制完整后可保存!');
return
}
this.camerasData.dimensionedPoints.arrow = this.arrowPoints
this.camerasData.dimensionedPoints.arrowOfSouth = this.arrowPointsOfSouth
}
let paramsData = JSON.parse(JSON.stringify(this.camerasData))
paramsData.dimensionedPoints = JSON.stringify(paramsData.dimensionedPoints)
console.log('标点结果', this.camerasData.dimensionedPoints)
this.http.put(`/api/Cameras/${this.camerasData.id}/DimensionedPoints`, paramsData).subscribe(data => {
this.message.create('success', '保存成功!');
const isFullScreen = document.fullscreenElement
if (document.exitFullscreen && isFullScreen) { //关闭全屏
document.exitFullscreen()
}
this.modal.closeAll();
})
}
//初始化背景图
initBackgroundImg() {
let canvas = document.getElementById('canvas') as any;
canvas.oncontextmenu = () => { return false; };
let that = this
let ctx
// 检测canvas支持性
if (canvas.getContext) {
ctx = canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性
} else {
document.write("你的浏览器不支持canvas,请升级你的浏览器!");
return;
}
// 读取可视区域 宽高
let center = document.getElementById('canvasCenter') as any;
// 图片加载完后,将其显示在canvas中
var img = new Image();
img.src = that.imgItem ? that.imgItem : "../../../assets/images/bgImg.png";
img.onload = () => {
// 等比例缩放图片
// var scale = 1;
// if (img.width > center.clientWidth || img.height > center.clientHeight) {
// let scaleOne = center.clientWidth / img.width;
// let scaleTwo = center.clientHeight / img.height;
// if (img.width * scaleOne <= center.clientWidth && img.height * scaleOne <= center.clientHeight) {
// scale = scaleOne;
// } else if (img.width * scaleTwo <= center.clientWidth && img.height * scaleTwo <= center.clientHeight) {
// scale = scaleTwo;
// } else {
// scale = 0.3;
// }
// }
// that.canvasWidth = img.width * scale;
// that.canvasHeight = img.height * scale; // 计算等比缩小后图片
that.canvasWidth = img.width;
that.canvasHeight = img.height;
console.log(img.width + "*" + img.height)
window.setTimeout(() => { // 加载图片
ctx.drawImage(img, 0, 0, that.canvasWidth, that.canvasHeight);
this.copyCanvas = ctx.getImageData(0, 0, that.canvasWidth, that.canvasHeight)
that.initCanvasEvent(canvas) //监听canvas事件
that.initMark(canvas, ctx) //初始化标绘图形
}, 0)
}
}
//初始化标绘图形
initMark(canvas, context) {
if (!this.camerasData.dimensionedPoints) {
return
}
if (this.markType === 0) {
this.camerasData.dimensionedPoints.polygon.forEach(element => {
this.drawPolygon(element.x, element.y, canvas, context); //绘制多边形
});
} else if (this.markType === 2) {
this.arrowPoints = this.camerasData.dimensionedPoints.arrow
if (this.camerasData.dimensionedPoints.arrowOfSouth && this.camerasData.dimensionedPoints.arrowOfSouth.length != 0) {
this.arrowPointsOfSouth = this.camerasData.dimensionedPoints.arrowOfSouth
}
if (this.camerasData.dimensionedPoints.arrowOfWest && this.camerasData.dimensionedPoints.arrowOfWest.length != 0) {
this.arrowPointsOfWest = this.camerasData.dimensionedPoints.arrowOfWest
}
if (this.camerasData.dimensionedPoints.arrowOfEast && this.camerasData.dimensionedPoints.arrowOfEast.length != 0) {
this.arrowPointsOfEast = this.camerasData.dimensionedPoints.arrowOfEast
}
if (this.camerasData.dimensionedPoints.arrowOfNorth && this.camerasData.dimensionedPoints.arrowOfNorth.length != 0) {
this.arrowPointsOfNorth = this.camerasData.dimensionedPoints.arrowOfNorth
}
this.oblongPoints = this.camerasData.dimensionedPoints.rectangle
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else if (this.markType === 3) {
this.arrowPoints = this.camerasData.dimensionedPoints.arrow
if (this.camerasData.dimensionedPoints.arrowOfSouth && this.camerasData.dimensionedPoints.arrowOfSouth.length != 0) {
this.arrowPointsOfSouth = this.camerasData.dimensionedPoints.arrowOfSouth
}
let arr = [this.arrowPoints, this.arrowPointsOfSouth]
this.drawLine(arr, context)
}
}
markType: number = 0; //0=进出口,2=卸油区,3=便利店,
isDrawArrow: boolean = true; //绘制type 箭头/矩形
arrowDirection = null
oilUnloadingArea: boolean = true; //卸油区type 泄油管区域/静电接地仪
//记录鼠标点击位置
downx = 0;
downy = 0;
//清空画布
clearCanvas() {
// 清空标绘箭头
this.arrowPoints = [];
this.arrowPointsOfSouth = []; //南 箭头的点的集合
this.arrowPointsOfWest = []; //西 箭头的点的集合
this.arrowPointsOfEast = []; //东 箭头的点的集合
this.arrowPointsOfNorth = []; //北 箭头的点的集合
// 清空标绘箭头
// 清空标绘矩形
this.oblongPoints = [];
// 清空标绘矩形
// 清空标绘多边形
this.points = [];
this.circles = [];
this.allpoints = [];
// 清空标绘多边形
let canvas = document.getElementById('canvas') as any;
let context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
}
//初始化 canvas画布 监听事件
initCanvasEvent(canvas) {
let context = canvas.getContext('2d');
canvas.onmousedown = (e) => { //鼠标按下事件
var clickX = e.pageX - canvas.offsetLeft;
var clickY = e.pageY - canvas.offsetTop;
this.downx = clickX
this.downy = clickY
if (this.markType === 0) { //进出口
this.drawPolygon(clickX, clickY, canvas, context); //绘制多边形
} else if (this.markType === 2 || this.markType === 3) { //卸油区/便利店
//开始绘制
context.beginPath();
context.moveTo(clickX, clickY);
context.strokeStyle = "green";
context.lineWidth = 3;
canvas.onmousemove = (ev) => { //鼠标移动事件
var moveX = ev.pageX - canvas.offsetLeft;
var moveY = ev.pageY - canvas.offsetTop;
if (this.isDrawArrow && !this.arrowDirection) { //绘制 箭头
if (this.arrowPoints.length === 2) { //限制数量
return
}
context.lineTo(moveX, moveY);
context.stroke();
} else if (this.isDrawArrow && this.arrowDirection == 'South') {
if (this.arrowPointsOfSouth.length === 2) { //限制数量
return
}
context.lineTo(moveX, moveY);
context.stroke();
} else if (this.isDrawArrow && this.arrowDirection == 'West') {
if (this.arrowPointsOfWest.length === 2) { //限制数量
return
}
context.lineTo(moveX, moveY);
context.stroke();
} else if (this.isDrawArrow && this.arrowDirection == 'East') {
if (this.arrowPointsOfEast.length === 2) { //限制数量
return
}
context.lineTo(moveX, moveY);
context.stroke();
} else if (this.isDrawArrow && this.arrowDirection == 'North') {
if (this.arrowPointsOfNorth.length === 2) { //限制数量
return
}
context.lineTo(moveX, moveY);
context.stroke();
} else { //绘制 矩形
if (this.oblongPoints.length === 2) { //限制数量
return
}
this.drawOblong(this.oblongPoints, context)
context.strokeStyle = this.oilUnloadingArea ? "green" : "red";
let element = this.getOblongInfo(this.downx, this.downy, moveX, moveY)
context.strokeRect(element.x, element.y, element.width, element.height);
context.font = '22px Arial';
context.fillText('高度:' + element.height, element.x + 3, element.y + 22);
}
}
}
}
canvas.onmouseup = (e) => { //鼠标松开事件
canvas.onmousemove = (ev) => { //鼠标移动事件
return false;
}
if (this.markType != 2 && this.markType != 3) {
return
}
var upX = e.pageX - canvas.offsetLeft;
var upY = e.pageY - canvas.offsetTop;
if (this.isDrawArrow && !this.arrowDirection) { //绘制 箭头
if (this.arrowPoints.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = {
startX: this.downx,
startY: this.downy,
endX: upX,
endY: upY,
}
this.arrowPoints.push(point);
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else if (this.isDrawArrow && this.arrowDirection == 'South') {
if (this.arrowPointsOfSouth.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = {
startX: this.downx,
startY: this.downy,
endX: upX,
endY: upY,
}
this.arrowPointsOfSouth.push(point);
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else if (this.isDrawArrow && this.arrowDirection == 'West') {
if (this.arrowPointsOfWest.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = {
startX: this.downx,
startY: this.downy,
endX: upX,
endY: upY,
}
this.arrowPointsOfWest.push(point);
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else if (this.isDrawArrow && this.arrowDirection == 'East') {
console.log('East')
if (this.arrowPointsOfEast.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = {
startX: this.downx,
startY: this.downy,
endX: upX,
endY: upY,
}
this.arrowPointsOfEast.push(point);
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else if (this.isDrawArrow && this.arrowDirection == 'North') {
console.log('North')
if (this.arrowPointsOfNorth.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = {
startX: this.downx,
startY: this.downy,
endX: upX,
endY: upY,
}
this.arrowPointsOfNorth.push(point);
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context)
} else { //绘制 矩形
if (this.oblongPoints.length === 2) { //限制数量
this.message.create('warning', '绘制数量已达上限!');
return
}
let point = this.getOblongInfo(this.downx, this.downy, upX, upY)
this.oblongPoints.push(point)
this.drawOblong(this.oblongPoints, context)
}
};
}
arrowPoints = []; //箭头的点的集合
arrowPointsOfSouth = []; //南 箭头的点的集合
arrowPointsOfWest = []; //西 箭头的点的集合
arrowPointsOfEast = []; //东 箭头的点的集合
arrowPointsOfNorth = []; //北 箭头的点的集合
//canvas 绘制直线
drawLine(pointsList, context, isRepeat: boolean = false) {
context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
if (this.markType === 2 && !isRepeat) { //同时绘制 矩形
this.oblongPoints.forEach(element => {
context.strokeStyle = element.oilUnloadingArea ? "green" : "red";
context.lineWidth = 3;
context.strokeRect(element.x, element.y, element.width, element.height);
context.font = '22px Arial';
context.fillText('高度:' + element.height, element.x + 3, element.y + 22);
});
}
// console.log(789, pointsList)
pointsList.forEach(element => {
if (element.length != 0) {
element.forEach((item, index) => {
if ((index + 1) % 2 === 0) {
this.drawArrow(item.startX, item.startY, item.endX, item.endY, 30, 10, 3, 'green', context)
} else {
context.beginPath();
context.moveTo(item.startX, item.startY);
context.strokeStyle = "green";
context.lineWidth = 3;
context.lineTo(item.endX, item.endY);
context.stroke();
}
})
}
});
}
//canvas 绘制箭头
drawArrow(fromX, fromY, toX, toY, theta, headlen, width, color, ctx) {
// fromX, fromY:起点坐标(也可以换成p1,只不过它是一个数组)
// toX, toY:终点坐标 (也可以换成p2,只不过它是一个数组)
// theta:三角斜边一直线夹角
// headlen:三角斜边长度
// width:箭头线宽度
// color:箭头颜色
theta = typeof (theta) != 'undefined' ? theta : 30;
headlen = typeof (theta) != 'undefined' ? headlen : 10;
width = typeof (width) != 'undefined' ? width : 1;
color = typeof (color) != 'undefined' ? color : '#000';
// 计算各角度和对应的P2,P3坐标
var angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,
angle1 = (angle + theta) * Math.PI / 180,
angle2 = (angle - theta) * Math.PI / 180,
topX = headlen * Math.cos(angle1),
topY = headlen * Math.sin(angle1),
botX = headlen * Math.cos(angle2),
botY = headlen * Math.sin(angle2);
ctx.save();
ctx.beginPath();
var arrowX = fromX - topX,
arrowY = fromY - topY;
ctx.moveTo(arrowX, arrowY);
ctx.moveTo(fromX, fromY);
ctx.lineTo(toX, toY);
arrowX = toX + topX;
arrowY = toY + topY;
ctx.moveTo(arrowX, arrowY);
ctx.lineTo(toX, toY);
arrowX = toX + botX;
arrowY = toY + botY;
ctx.lineTo(arrowX, arrowY);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.stroke();
ctx.restore();
}
oblongPoints = []; //矩形的点的集合
//获取 矩形左上角点位/宽高
getOblongInfo(startX, startY, endX, endY) {
let point = {
x: 0,
y: 0,
width: 0,
height: 0,
oilUnloadingArea: this.oilUnloadingArea,
}
if (startX > endX) {
point.x = endX
point.width = startX - endX
} else {
point.x = startX
point.width = endX - startX
}
if (startY > endY) {
point.y = endY
point.height = startY - endY
} else {
point.y = startY
point.height = endY - startY
}
return point
}
//canvas 绘制矩形
drawOblong(oblongList, context) {
context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
if (this.markType === 2) { //同时绘制 直线箭头
let arr = [this.arrowPoints, this.arrowPointsOfSouth, this.arrowPointsOfWest, this.arrowPointsOfEast, this.arrowPointsOfNorth]
this.drawLine(arr, context, true)
}
oblongList.forEach(element => {
context.strokeStyle = element.oilUnloadingArea ? "green" : "red";
context.lineWidth = 3;
context.strokeRect(element.x, element.y, element.width, element.height);
context.font = '22px Arial';
context.fillText('高度:' + element.height, element.x + 3, element.y + 22);
});
}
points = []; //线段的点的集合
circles = []; //可拖动圆圈的点的集合
allpoints = []; //整体移动点位
isDragging = false; //是否可拖拽
isInOut = false; //是否在绘制区域内
//canvas 绘制多边形
drawPolygon(clickX, clickY, canvas, context) {
if (this.isInt(clickX, clickY)) {
this.isInOut = true
return
} else {
this.isInOut = false
}
let index
//判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
for (var i = 0; i < this.circles.length; i++) {
let circle = this.circles[i];
//使用勾股定理计算这个点与圆心之间的距离
var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2));
// 如果是其他的点,则设置可以拖动
if (distanceFromCenter <= circle.radius) {
// 清除之前选择的圆圈
index = i;
this.isDragging = true;
//停止搜索
return;
}
}
//如果点击新的位置,则进入下面的代码,绘制点
context.clearRect(0, 0, canvas.width, canvas.height);
this.copyCanvas ? context.putImageData(this.copyCanvas, 0, 0) : null;
//遍历数组画圆
var circle = {
x: clickX,
y: clickY,
radius: 5,
color: "white",
isSelected: false, //拖拽点的标记
};
this.circles.push(circle);
this.allpoints = JSON.parse(JSON.stringify(this.circles))
this.circles[0].color = "white";
for (var i = 0; i < this.circles.length; i++) {
let circle = this.circles[i];
// 绘制圆圈
context.globalAlpha = 0.85;
context.beginPath();
context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
context.fillStyle = circle.color;
context.strokeStyle = "red";
context.fill();
context.stroke();
}
// 画线
var point = {
x: clickX,
y: clickY,
};
this.points.push(point)
context.beginPath();
context.lineWidth = 3;
//从起始点开始绘制
context.moveTo(this.points[0].x, this.points[0].y);
for (var i = 0; i < this.points.length; i++) {
context.lineTo(this.points[i].x, this.points[i].y);
}
context.closePath()
//ontext.fillStyle = "rgb(2,100,30)";
//context.fill();
context.strokeStyle = "green";
context.stroke();
}
//判断点位是否在图形区域内
isInt(x, y) {
if (!this.points[2]) {
return
}
var pt = {
x: x,
y: y
}
return this.PointInPoly(pt, this.points)
}
//射线法判断点位
PointInPoly(pt, poly) {
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
&& (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
&& (c = !c);
return c;
}
}

19
src/app/system-management/image-list/image-list.component.html

@ -0,0 +1,19 @@
<div class="box">
<nz-page-header class="site-page-header" (nzBack)="goback()" nzBackIcon nzSubtitle="返回上一页"></nz-page-header>
<div class="imgbox">
<div class="imageItemBox" *ngFor="let item of imgList">
<div class="imgbox">
<img [src]="item.url" alt="" (click)="label(item)">
</div>
<div class="coord">
监控坐标点:<span>{{item.showCoord}}</span>
</div>
<div class="coord">
禁止坐标点:<span>{{item.banCoord}}</span>
</div>
</div>
</div>
<div class="footer">
<button nz-button nzType="primary">提交</button>
</div>
</div>

48
src/app/system-management/image-list/image-list.component.scss

@ -0,0 +1,48 @@
.box {
width: 100%;
height: 100%;
background: #fff;
font-size: 15px;
color: black;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow-y: auto;
}
.imgbox {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
}
.imageItemBox {
display: flex;
flex-direction: column;
width: 220px;
border: 1px solid #F2F2F2;
margin: 6px;
.imgbox {
width: 100%;
height: 250px;
img {
display: block;
width: 100%;
height: 100%;
cursor: pointer;
}
}
.coord {
height: 25px;
display: flex;
align-items: center;
}
}
.footer{
margin: 6px 0;
display: flex;
justify-content: center;
}

50
src/app/system-management/image-list/image-list.component.ts

@ -0,0 +1,50 @@
import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd/modal';
import { ImageLabelComponent } from '../image-label/image-label.component';
@Component({
selector: 'app-image-list',
templateUrl: './image-list.component.html',
styleUrls: ['./image-list.component.scss']
})
export class ImageListComponent implements OnInit {
constructor(private modal: NzModalService, private viewContainerRef: ViewContainerRef) { }
imgList = [
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/bgImg.png', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' },
{ url: '../../../assets/images/test/dog.jpg', showCoord: '', banCoord: '' }
]
ngOnInit(): void {
}
goback() {
history.go(-1)
}
label(item) {
let width = document.documentElement.clientWidth
const modal = this.modal.create({
nzContent: ImageLabelComponent,
nzViewContainerRef: this.viewContainerRef,
nzComponentParams: {
imgItem: item,
},
nzClassName: "canvasDialog",
nzWidth: width - 100,
nzCentered: true,
nzOnOk: () => new Promise(resolve => {
item.showCoord = ''
item.banCoord = ''
resolve(1)
}),
});
const instance = modal.getContentComponent();
modal.afterOpen.subscribe(() => console.log('[afterOpen] emitted!'));
// Return a result when closed
modal.afterClose.subscribe(result => console.log('[afterClose] The result is:', result));
}
}

1
src/app/system-management/kafka/kafka.component.html

@ -0,0 +1 @@
<p>kafka works!</p>

0
src/app/system-management/kafka/kafka.component.scss

15
src/app/system-management/kafka/kafka.component.ts

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-kafka',
templateUrl: './kafka.component.html',
styleUrls: ['./kafka.component.scss']
})
export class KafkaComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

47
src/app/system-management/navigation/navigation.component.html

@ -0,0 +1,47 @@
<!-- <p>系统管理页面</p> -->
<nz-layout>
<nz-sider [nzWidth]='300'>
<div class="logo">
<img style="width: 154px;" src="../../../assets/images/logo2.png" alt="">
</div>
<div class="headPortrait">
<div class="photograph">
<img src="../../../assets/images/userbig.png" alt="">
</div>
<span>Administrator</span>
<span><img src="../../../assets/images/icon/admin.png" alt=""> 管理员</span>
</div>
<div class="nav">
<ul>
<li [routerLink]="['/system/organization']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/organization.png" alt="">组织机构管理</li>
<li [routerLink]="['/system/host']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/host.png" alt="">边缘设备管理</li>
<li [routerLink]="['/system/conditionMonitoring']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/push.png" alt="">边缘设备更新</li>
<li [routerLink]="['/system/statusMonitoring']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/push.png" alt="">边缘设备监控</li>
<li [routerLink]="['/system/videoStreaming']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/push.png" alt="">视频流监控</li>
<!-- <li [routerLink]="['/system/kafka']" routerLinkActive="router-link-active"><img
src="../../../assets/images/icon/push.png" alt="">kafka检查</li> -->
</ul>
</div>
</nz-sider>
<nz-layout>
<nz-header>
<span>Hey,欢迎登录加油站边缘主机管理系统</span>
<a nz-dropdown [nzDropdownMenu]="menu" [nzTrigger]="'click'" [nzBackdrop]='false'>
<i nz-icon nzType="setting"></i>
</a>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu nzSelectable>
<li nz-menu-item (click)="signOut()">退出</li>
</ul>
</nz-dropdown-menu>
</nz-header>
<nz-content>
<router-outlet></router-outlet>
</nz-content>
</nz-layout>
</nz-layout>

79
src/app/system-management/navigation/navigation.component.scss

@ -0,0 +1,79 @@
nz-layout {
width: 100%;
height: 100%;
color: #fff;
font-size: 16px !important;
}
nz-sider {
background: #001B3B;
display: flex;
flex-direction: column;
align-items: center;
overflow-y: auto;
.logo {
width: 100%;
display: flex;
justify-content: center;
margin-top: 40px;
}
.headPortrait {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 46px;
margin-bottom: 46px;
.photograph {
// width: 140px;
// height: 140px;
// border: 4px solid #FFFFFF;
// opacity: 1;
// border-radius: 32px;
}
span {
margin-top: 18px;
}
}
.nav {
ul {
li {
width: 300px;
height: 40px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: left;
margin-bottom: 16px;
box-sizing: border-box;
padding-left: 26%;
img {
margin-right: 8px;
}
}
.router-link-active {
background: linear-gradient(90deg, rgba(0, 13, 33, 0) 0%, #2399FF 52%, rgba(0, 13, 33, 0) 100%);
}
}
}
}
nz-header {
height: 56px;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
}
nz-content {
background: #F2F2F2;
box-sizing: border-box;
padding: 16px;
}

20
src/app/system-management/navigation/navigation.component.ts

@ -0,0 +1,20 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { CacheTokenService } from 'src/app/service/cache-token.service';
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent implements OnInit {
constructor(private router: Router, public token: CacheTokenService) { }
ngOnInit(): void {
}
signOut() {
this.token.delete()
this.router.navigate(['/login'])
}
}

23
src/app/system-management/organization/addor/addor.component.html

@ -0,0 +1,23 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="name" placeholder="请输入名称" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-control>
<nz-input-group>
<input nz-input type="text" formControlName="code" placeholder="请输入编码" />
</nz-input-group>
</nz-form-control>
</nz-form-item> -->
<nz-form-item>
<nz-form-control>
<label nz-checkbox formControlName="isGasStation">是否为加油站</label>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/organization/addor/addor.component.scss

26
src/app/system-management/organization/addor/addor.component.ts

@ -0,0 +1,26 @@
import { Component, OnInit } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-addor',
templateUrl: './addor.component.html',
styleUrls: ['./addor.component.scss']
})
export class AddorComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
name: [null, [Validators.required]],
// code: [null, [Validators.required]],
isGasStation: [false]
});
}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
}
}

23
src/app/system-management/organization/editor/editor.component.html

@ -0,0 +1,23 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control nzErrorTip="请输入名称">
<nz-input-group>
<input [(ngModel)]="datacopy.name" nz-input type="text" formControlName="name" placeholder="请输入名称" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<!-- <nz-form-item>
<nz-form-control>
<nz-input-group>
<input [(ngModel)]="datacopy.code" nz-input type="text" formControlName="code" placeholder="请输入编码" />
</nz-input-group>
</nz-form-control>
</nz-form-item> -->
<nz-form-item>
<nz-form-control>
<label [(ngModel)]="datacopy.isGasStation" nz-checkbox formControlName="isGasStation">是否为加油站</label>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/organization/editor/editor.component.scss

30
src/app/system-management/organization/editor/editor.component.ts

@ -0,0 +1,30 @@
import { Component, OnInit, Input } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-editor',
templateUrl: './editor.component.html',
styleUrls: ['./editor.component.scss']
})
export class EditorComponent implements OnInit {
@Input() data?: any;
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
datacopy:any
ngOnInit(): void {
this.validateForm = this.fb.group({
name: [null, [Validators.required]],
// code: [null, [Validators.required]],
isGasStation: []
});
this.datacopy = JSON.parse(JSON.stringify(this.data))
}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
}
}

42
src/app/system-management/organization/organization.component.html

@ -0,0 +1,42 @@
<div class="orbox" id="orbox">
<div class="topbox">
<div class="lefttop">
<span>组织机构列表</span>
<span><img style="vertical-align: top;" src="../../../assets/images/icon/orgrey.png" alt="">
{{totalCount}}个单位</span>
</div>
<div class="righttop">
<nz-input-group nzPrefixIcon="search">
<input type="text" nz-input placeholder="请输入单位" [(ngModel)]="searchValue" />
</nz-input-group>
<button nz-button nzType="primary" (click)="addOr()"><i nz-icon nzType="plus-circle"
nzTheme="outline"></i>新增</button>
</div>
</div>
<div class="treeTitle">
<span>组织机构</span>
<span>操作</span>
</div>
<nz-tree [nzHideUnMatched]='true' [nzSearchValue]="searchValue" #nzTreeComponent [nzData]="nodes"
[nzExpandAll]="nzExpandAll" [nzExpandedKeys]="defaultExpandedKeys" [nzTreeTemplate]="nzTreeTemplate" nzDraggable
nzBlockNode (nzOnDrop)="nzEvent($event)" [nzBeforeDrop]="beforeDrop" [nzExpandedIcon]="multiExpandedIconTpl">
</nz-tree>
<ng-template #nzTreeTemplate let-node let-origin="origin">
<div class="nodebox">
<span class="name">{{ node.title }}</span>
<span class="operation">
<span (click)="addOr(node)" *ngIf="!node.origin.isGasStation">新增</span>
<span (click)="editOr(node)">编辑</span>
<span (click)="deleteOr(node)">删除</span>
</span>
</div>
</ng-template>
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<ng-container *ngIf="node.children.length == 0; else elseTemplate">
</ng-container>
<ng-template #elseTemplate>
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'" class="ant-tree-switcher-line-icon"></i>
</ng-template>
</ng-template>
</div>

78
src/app/system-management/organization/organization.component.scss

@ -0,0 +1,78 @@
.orbox {
width: 100%;
height: 100%;
overflow-y: auto;
background: #fff;
box-sizing: border-box;
padding: 20px;
font-size: 15px;
}
.topbox {
width: 700px;
height: 36px;
display: flex;
align-items: center;
justify-content: space-between;
.lefttop {
span:nth-child(1) {
color: #000D21;
margin-right: 16px;
}
span:nth-child(2) {
color: rgba(36, 36, 36, 0.24);
}
}
.righttop {
height: 36px;
display: flex;
button {
margin-left: 16px;
}
nz-input-group {
height: 32px;
}
}
}
.treeTitle {
width: 100%;
height: 36px;
line-height: 36px;
display: flex;
justify-content: space-between;
color: #000D21;
box-sizing: border-box;
padding-left: 30px;
padding-right: 140px;
background: rgba(145, 204, 255, 0.2);
margin: 12px 0;
}
.nodebox {
font-size: 15px;
}
.operation {
position: absolute;
right: 0;
span {
margin-left: 40px;
}
span:nth-child(1),
span:nth-child(2) {
color: #2399FF;
}
span:nth-child(3) {
color: rgba(0, 13, 33, 0.48);
}
}

314
src/app/system-management/organization/organization.component.ts

@ -0,0 +1,314 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, AfterViewInit, ViewChild, ViewContainerRef } from '@angular/core';
import { TreeService } from 'src/app/service/tree.service';
import { NzFormatEmitEvent, NzTreeComponent, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
import { AddorComponent } from './addor/addor.component';
import { EditorComponent } from './editor/editor.component';
import { NzFormatBeforeDropEvent } from 'ng-zorro-antd/tree';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { CustomReuseStrategy } from 'src/app/CustomReuseStrategy';
@Component({
selector: 'app-organization',
templateUrl: './organization.component.html',
styleUrls: ['./organization.component.scss']
})
export class OrganizationComponent implements OnInit {
validateForm!: FormGroup;
constructor(private fb: FormBuilder, private http: HttpClient, private toTree: TreeService, private modal: NzModalService, private message: NzMessageService, private viewContainerRef: ViewContainerRef) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
search: [null]
});
this.getAllOrganization()
this.deleteRouteSnapshot();
}
deleteRouteSnapshot() {
CustomReuseStrategy.deleteRouteSnapshot('/system/host');
}
//搜索框提交
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
}
//获取所有组织机构
searchValue = '';
nzExpandAll = false;
totalCount: string
allOrList: any
getAllOrganization() {
let OrganizationUnitId = ''
let params = {
// OrganizationUnitId: OrganizationUnitId,
// IsContainsChildren: "true"
ContainsChildren: true,
pageSize: 9999
}
this.http.get('/api/Organizations', {
params: params
}).subscribe((data: any) => {
console.log('组织机构列表', data)
this.totalCount = data.totalCount
data.items.forEach(element => {
element.key = element.id
element.title = element.name
element.selectable = false
});
this.allOrList = data.items
this.nodes = [...this.toTree.toTree(data.items)]
this.defaultExpandedKeys = [this.nodes[0].id]
this.defaultExpandedKeys = [...this.defaultExpandedKeys]
})
}
@ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent;
defaultExpandedKeys = [];
nodes: any[] = []
addOr(node?: any) {
console.log(node)
const modal = this.modal.create({
nzTitle: node ? '新增组织机构' : '新增一级组织机构',
nzContent: AddorComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise(resolve => {
let body = {
name: instance.validateForm.value.name,
parentId: node ? Number(node.key) : null,
isGasStation: instance.validateForm.value.isGasStation
}
this.http.post('/api/Organizations', body).subscribe(data => {
resolve(data)
this.message.create('success', '创建成功!');
this.nzTreeComponent.getExpandedNodeList().forEach((item) => {
this.defaultExpandedKeys.push(item.key)
})
this.getAllOrganization()
return true
}, err => {
resolve(err)
this.message.create('warning', '创建失败');
return false
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
editOr(node) {
// console.log(node)
const modal = this.modal.create({
nzTitle: '编辑组织机构',
nzContent: EditorComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {
data: node.origin,
},
nzOnOk: async () => {
if (instance.validateForm.valid) {
await new Promise(resolve => {
let body = {
name: instance.validateForm.value.name,
isGasStation: instance.validateForm.value.isGasStation,
parentId: node.origin.parentId
}
this.http.put(`/api/Organizations/${node.origin.id}`, body).subscribe(data => {
resolve(data)
this.message.create('success', '编辑成功!');
this.nzTreeComponent.getExpandedNodeList().forEach((item) => {
this.defaultExpandedKeys.push(item.key)
})
this.getAllOrganization()
return true
}, err => {
resolve(err)
this.message.create('warning', '编辑失败');
return false
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
deleteOr(item) {
console.log(item)
if (item.origin.children && item.origin.children.length != 0) {
this.message.create('warning', '请先删除所有子节点');
} else {
this.modal.confirm({
nzTitle: `确定要删除${item.title}这个机构吗?`,
nzOkText: '确定',
nzOkType: 'primary',
nzOnOk: () => {
this.http.delete(`/api/Organizations/${item.origin.id}`).subscribe(data => {
this.nzTreeComponent.getExpandedNodeList().forEach((item) => {
this.defaultExpandedKeys.push(item.key)
})
this.getAllOrganization()
this.message.create('success', '删除成功!');
})
},
nzCancelText: '取消',
nzOnCancel: () => {
}
});
}
}
nzEvent(event: NzFormatEmitEvent): void {
console.log('event', event)
if (this.isDrag) {
let parentId
if (this.pos == 0) {//目标节点内部
parentId = event.node.key
} else {
if (event.node.level == 0) {
parentId = null
} else {
parentId = event.node.origin.parentId
}
}
let body = {
parentId: parentId,
name: event.dragNode.origin.name,
isGasStation: event.dragNode.origin.isGasStation
}
this.http.put(`/api/Organizations/${event.dragNode.origin.id}`, body).subscribe(data => {
this.message.create('success', '拖拽成功!');
this.nzTreeComponent.getExpandedNodeList().forEach((item) => {
this.defaultExpandedKeys.push(item.key)
})
this.getAllOrganization()
return true
}, err => {
this.message.create('warning', '拖拽失败');
return false
})
// console.log('this.allOrList', this.allOrList)
// let orders = {}
// let originalData = JSON.parse(JSON.stringify(this.allOrList || [])) //tree原始数据
// let targetNodeData = []//拖动移入节点的数据,用于遍历求出放在该数组的第几位
//找到需要重新排序的数组
// if (this.pos == 0) {
// originalData.forEach(item => {
// if (item.parentId == event.node.key) {
// targetNodeData.push(item)
// }
// })
// } else {
// if (event.node.origin.parentId) {//如果拖动目标为非一级节点
// originalData.forEach(item => {
// if (item.parentId == event.node.origin.parentId) {
// targetNodeData.push(item)
// }
// })
// } else {//如果拖动目标为一级节点
// originalData.forEach(item => {
// if (!item.parentId) {
// targetNodeData.push(item)
// }
// })
// }
// }
// let idArr = []
// targetNodeData.forEach(i => {
// idArr.push(i.id)
// })
// if (this.pos == 0 && event.node.origin.children.length == 1) {
// // console.log("移入,没有兄弟")
// let key = event.dragNode.key
// orders[key] = 0
// parentId = event.node.key
// } else {
// let array = []
// targetNodeData.forEach(item => {
// if (item.id != event.dragNode.key) { //将拖动项先移除掉
// array.push(item)
// }
// })
// if (event.dragNode.isEnd[event.dragNode.isEnd.length - 1]) { //如果移入到最后一个
// // console.log("最后")
// array.push(event.dragNode.origin)
// } else if (event.dragNode.isStart[event.dragNode.isStart.length - 1]) {//如果移入到第一个
// // console.log("第一")
// array.unshift(event.dragNode.origin)
// } else {//如果移入中间位置
// // console.log("中间")
// array.splice(event.node.origin.order, 0, event.dragNode.origin)
// }
// array.forEach((item, key) => {
// orders[item.id] = key
// })
// console.log("移入,多个兄弟",orders)
// }
// let obj = {
// id: event.dragNode.origin.id,
// parentId: parentId,
// orders: orders
// }
// this.http.put("/api/DisposalNodes/Sort", obj).subscribe(data => {
// const config = new MatSnackBarConfig();
// config.verticalPosition = 'top';
// config.duration = 3000
// this.snackBar.open('排序成功', '确定', config)
// this.refurbishTreeData()
// })
}
}
isDrag //是否可以拖动
pos//放置位置
beforeDrop = (arg: NzFormatBeforeDropEvent) => {
console.log('arg', arg)
if (arg.node.level === 0) {//如果为数据节点则不允许拖到一级节点
this.message.create('warning', '不允许拖拽到一级节点');
this.isDrag = false
return of(false);
} else {
this.isDrag = true
this.pos = arg.pos
return of(true)
}
}
}

3
src/app/system-management/plotting-image/plotting-image.component.html

@ -0,0 +1,3 @@
<div class="content">
<div class="center" id="center"><canvas id="canvas" [width]="canvasWidth" [height]="canvasHeight"></canvas></div>
</div>

7
src/app/system-management/plotting-image/plotting-image.component.scss

@ -0,0 +1,7 @@
.content{
width: 100%;
height: 100%;
overflow: hidden;
}
.center{ width: 100%; height: 100%; }

171
src/app/system-management/plotting-image/plotting-image.component.ts

@ -0,0 +1,171 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-plotting-image',
templateUrl: './plotting-image.component.html',
styleUrls: ['./plotting-image.component.scss']
})
export class PlottingImageComponent implements OnInit {
constructor() { }
canvasWidth: number = 0;
canvasHeight: number = 0;
ngOnInit(): void {
window.onload = () => {
this.initBackgroundImg()
}
}
//初始化背景图
initBackgroundImg() {
let canvas = document.getElementById('canvas') as any;
canvas.oncontextmenu = () =>{ return false; };
let ctx
// 检测canvas支持性
if (canvas.getContext) {
ctx = canvas.getContext('2d'); // 返回一个对象,该对象提供了用在画布上绘图的方法和属性
} else {
document.write("你的浏览器不支持canvas,请升级你的浏览器!");
return;
}
// 读取可视区域 宽高
let center = (document.getElementById('center') as any).getBoundingClientRect();
// 图片加载完后,将其显示在canvas中
var img = new Image();
img.src = "../../../assets/images/bgImg.png";
img.onload = () => {
// 等比例缩放图片
var scale = 1;
if (img.width > center.width || img.height > center.height) {
if (img.width > img.height) {
scale = center.width / img.width;
}else {
scale = center.height / img.height;
}
}
this.canvasWidth = img.width * scale;
this.canvasHeight = img.height * scale; // 计算等比缩小后图片
window.setTimeout(()=>{ // 加载图片
ctx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
this.initCanvasEvent(canvas)
}, 0)
}
}
//线段的点的集合
points = [];
//可拖动圆圈的点的集合
circles = [];
//整体移动点位
allpoints = []
isDragging = false
//是否在绘制区域内
isInOut = false
//记录鼠标点击位置
downx = 0
downy = 0
//初始化 canvas画布 点击事件
initCanvasEvent(canvas) {
let context = canvas.getContext('2d');
canvas.onmousedown = (e)=>{
console.log(e.pageX,e.pageY)
var clickX = e.pageX - canvas.offsetLeft;
var clickY = e.pageY - canvas.offsetTop;
this.downx = clickX
this.downy = clickY
if (this.isInt(clickX, clickY)) {
this.isInOut = true
return
} else {
this.isInOut = false
}
let index
//判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
for (var i = 0; i < this.circles.length; i++) {
let circle = this.circles[i];
//使用勾股定理计算这个点与圆心之间的距离
var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2));
// 如果是其他的点,则设置可以拖动
if (distanceFromCenter <= circle.radius) {
// 清除之前选择的圆圈
index = i;
this.isDragging = true;
//停止搜索
return;
}
}
//如果点击新的位置,则进入下面的代码,绘制点
//context.clearRect(0, 0, canvas.width, canvas.height);
//遍历数组画圆
var circle = {
x: clickX,
y: clickY,
radius: 10,
color: "blue",
isSelected: false, //拖拽点的标记
};
this.circles.push(circle);
this.allpoints = JSON.parse(JSON.stringify(this.circles))
this.circles[0].color = "green";
for (var i = 0; i < this.circles.length; i++) {
let circle = this.circles[i];
// 绘制圆圈
context.globalAlpha = 0.85;
context.beginPath();
context.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
context.fillStyle = circle.color;
context.strokeStyle = "black";
context.fill();
context.stroke();
}
// 画线
var point = {
x: clickX,
y: clickY,
};
this.points.push(point);
context.beginPath();
context.lineWidth = 3;
//从起始点开始绘制
context.moveTo(this.points[0].x, this.points[0].y);
for (var i = 0; i < this.points.length; i++) {
context.lineTo(this.points[i].x, this.points[i].y);
}
context.closePath()
context.fillStyle = "rgb(2,100,30)";
context.fill();
context.strokeStyle = "#9d4dca";
context.stroke();
}
}
//判断点位是否在图形区域内
isInt(x, y) {
if (!this.points[2]) {
return
}
var pt = {
x: x,
y: y
}
var poly = this.points
return this.PointInPoly(pt, poly)
}
//射线法判断点位
PointInPoly(pt, poly) {
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
&& (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
&& (c = !c);
return c;
}
}

12
src/app/system-management/status-monitoring/script/script.component.html

@ -0,0 +1,12 @@
<div class="box">
<form nz-form [formGroup]="validateForm">
<nz-form-item>
<nz-form-control>
<nz-select nzMode="multiple" formControlName="script" nzPlaceHolder="请选择脚本">
<nz-option [nzValue]="'restartContainer'" nzLabel="restartContainer"></nz-option>
<nz-option [nzValue]="'restartMonitor'" nzLabel="restartMonitor"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</form>
</div>

0
src/app/system-management/status-monitoring/script/script.component.scss

25
src/app/system-management/status-monitoring/script/script.component.ts

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-script',
templateUrl: './script.component.html',
styleUrls: ['./script.component.scss']
})
export class ScriptComponent implements OnInit {
validateForm!: FormGroup;
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { }
ngOnInit(): void {
this.validateForm = this.fb.group({
script: [null, [Validators.required]],
});
}
destroyModal(): void {
this.modal.destroy({ data: 'this the result data' });
}
}

96
src/app/system-management/status-monitoring/status-monitoring.component.html

@ -0,0 +1,96 @@
<div class="box">
<div class="topbox">
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
<nz-form-item class="searchParams">
<nz-form-control>
<nz-tree-select [nzAllowClear]="false" [nzDropdownClassName]="'maxHeightTreeSelect'" nzShowSearch
formControlName="organization" [nzNodes]="nodes" nzPlaceHolder="请选择所属机构"
[(ngModel)]="defaultOrId" [nzExpandedIcon]="multiExpandedIconTpl">
</nz-tree-select>
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<ng-container *ngIf="node.children.length == 0; else elseTemplate">
</ng-container>
<ng-template #elseTemplate>
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'"
class="ant-tree-switcher-line-icon"></i>
</ng-template>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<!-- <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="state">设备状态</nz-form-label> -->
<nz-form-control>
<nz-select formControlName="state" nzPlaceHolder="请选择设备状态">
<nz-option [nzValue]="0" nzLabel="离线"></nz-option>
<nz-option [nzValue]="1" nzLabel="在线"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button nzType="primary" type="submit" class="submit"><i nz-icon
[nzType]="'search'"></i>查询</button>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button type="button" class="reset" (click)="resetForm($event)"><i nz-icon
[nzType]="'sync'"></i>重置</button>
</nz-form-control>
</nz-form-item>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'RestartApps'" (click)="sendRequest('RestartApps')">
重启识别程序
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'RestartMonitors'" (click)="sendRequest('RestartMonitors')">
重启监控程序
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'RestartMonitors'" (click)="executeTheScript()">
执行脚本
</button>
</form>
</div>
<nz-table #basicTable nzShowSizeChanger [nzData]="listOfData" [nzLoading]="isLoading"
(nzCurrentPageDataChange)="onCurrentPageDataChange($event)" [nzShowPagination]='false' [nzPageSize]='10'>
<thead>
<tr>
<th [nzChecked]="checked" [nzIndeterminate]="indeterminate" (nzCheckedChange)="onAllChecked($event)">
</th>
<th>ip地址</th>
<th>所属油站</th>
<th>设备状态</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td [nzChecked]="setOfCheckedId.has(data.id)" [nzDisabled]="data.disabled"
(nzCheckedChange)="onItemChecked(data.id, $event)"></td>
<td>{{ data.hostIPAddress }}</td>
<td>{{ data.gasStationName }}</td>
<td>
<ng-container *ngIf="data.hubConnectionState == 'Disconnected'; else elseTemplate">
<span style="color: red;">离线</span>
</ng-container>
<ng-template #elseTemplate>
<span style="color: rgb(52, 204, 52);">在线</span>
</ng-template>
</td>
</tr>
</tbody>
</nz-table>
<div class="pagination">
<nz-pagination [nzHideOnSinglePage]="false" [nzPageIndex]="1" [nzTotal]="num" [nzPageSize]="10"
[nzShowTotal]="totalTemplate" nzShowQuickJumper (nzPageIndexChange)="pageChange($event)">
</nz-pagination>
<ng-template #totalTemplate let-total> 10条/页,共{{num}}条 </ng-template>
</div>
</div>

17
src/app/system-management/status-monitoring/status-monitoring.component.scss

@ -0,0 +1,17 @@
.topbox {
form {
display: flex;
nz-form-item {
margin-right: 6px;
}
button {
margin-right: 6px;
}
}
.searchParams {
width: 250px;
}
}

221
src/app/system-management/status-monitoring/status-monitoring.component.ts

@ -0,0 +1,221 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { TreeService } from 'src/app/service/tree.service';
import { ScriptComponent } from './script/script.component';
@Component({
selector: 'app-status-monitoring',
templateUrl: './status-monitoring.component.html',
styleUrls: ['./status-monitoring.component.scss']
})
export class StatusMonitoringComponent implements OnInit {
constructor(private http: HttpClient, private fb: FormBuilder, private toTree: TreeService, private message: NzMessageService, private modal: NzModalService, private viewContainerRef: ViewContainerRef) { }
validateForm!: FormGroup;
ngOnInit(): void {
this.validateForm = this.fb.group({
organization: [null],
state: [null]
});
this.getAllOrganization()
}
//获取所有组织机构
nodes: any = []
defaultOrId: string
defaultExpandedKeys = [];
getAllOrganization() {
let params = {
ContainsChildren: true,
pageSize: 9999
}
this.http.get('/api/Organizations', {
params: params
}).subscribe((data: any) => {
console.log('组织机构列表', data)
data.items.forEach(element => {
element.key = element.id
element.title = element.name
// element.selectable = false
});
this.nodes = [...this.toTree.toTree(data.items)]
this.defaultOrId = this.nodes[0].id
this.validateForm.value.organization = this.defaultOrId
this.getConditionMonitoring()
})
}
submitForm(): void {
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
this.getConditionMonitoring()
}
resetForm(e: MouseEvent): void {
e.preventDefault();
this.validateForm.reset();
for (const key in this.validateForm.controls) {
this.validateForm.controls[key].markAsPristine();
this.validateForm.controls[key].updateValueAndValidity();
}
this.validateForm.patchValue({
organization: this.nodes[0].id,
});
this.PageNumber = 1
this.getConditionMonitoring()
}
listOfData: any
num: string
PageNumber: number = 1
isLoading = false
//获取盒子状态
getConditionMonitoring() {
let params = {
ContainsChildren: true,
OrganizationId: this.defaultOrId,
PageNumber: this.PageNumber,
PageSize: 10,
HubConnectionState: this.validateForm.value.state
}
this.isLoading = true
this.http.get('/api/EdgeDevices/Statuses', { params: params }).subscribe(
(data: any) => {
console.log(data)
this.isLoading = false
this.listOfData = data.items
this.num = data.totalCount
}, err => {
}
)
}
pageChange($event) {
this.PageNumber = $event
this.getConditionMonitoring()
}
checked = false;
loading
indeterminate = false;
listOfCurrentPageData: readonly any[] = [];
setOfCheckedId = new Set<number>();
updateCheckedSet(id: number, checked: boolean): void {
if (checked) {
this.setOfCheckedId.add(id);
} else {
this.setOfCheckedId.delete(id);
}
}
onCurrentPageDataChange(listOfCurrentPageData: readonly any[]): void {
this.listOfCurrentPageData = listOfCurrentPageData;
this.refreshCheckedStatus();
}
refreshCheckedStatus(): void {
const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled);
this.checked = listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id));
this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked;
}
onItemChecked(id: number, checked: boolean): void {
this.updateCheckedSet(id, checked);
this.refreshCheckedStatus();
}
onAllChecked(checked: boolean): void {
this.listOfCurrentPageData
.filter(({ disabled }) => !disabled)
.forEach(({ id }) => this.updateCheckedSet(id, checked));
this.refreshCheckedStatus();
}
sendRequest(type): void {
const requestData = this.listOfData.filter(data => this.setOfCheckedId.has(data.id));
let strArr = []
requestData.forEach(element => {
strArr.push(element.id)
});
let body
this.loading = type;
body = {
edgeDeviceIds: strArr
}
this.http.patch('/api/EdgeDevices/Commands', body, { params: { command: type } }).subscribe({
next: (data: any) => {
this.message.create('success', '通知边缘盒子成功,请过一段时间手动刷新尝试!');
console.log(data)
if (data.failedItems.length != 0) {
data.failedItems.forEach(element => {
this.message.create('info', element.detail);
});
}
this.setOfCheckedId.clear();
this.refreshCheckedStatus();
this.loading = null;
this.getConditionMonitoring()
},
error: (err) => {
this.loading = null;
}
})
}
executeTheScript() {
const requestData = this.listOfData.filter(data => this.setOfCheckedId.has(data.id));
let strArr = []
requestData.forEach(element => {
strArr.push(element.id)
});
const modal = this.modal.create({
nzTitle: '选择执行脚本',
nzContent: ScriptComponent,
nzViewContainerRef: this.viewContainerRef,
nzWidth: 288,
nzComponentParams: {},
nzOnOk: async () => {
if (instance.validateForm.valid) {
let body = {
edgeDeviceIds: strArr
}
await new Promise(resolve => {
this.http.patch('/api/EdgeDevices/Commands/ExecuteScript', body, { params: { name: instance.validateForm.value.script } }).subscribe({
next: (data: any) => {
resolve(data)
this.message.create('success', '通知边缘盒子成功,请过一段时间手动刷新尝试!');
// if (data.failedItems && data.failedItems.length != 0) {
// data.failedItems.forEach(element => {
// this.message.create('info', element.detail);
// });
// }
this.setOfCheckedId.clear();
this.refreshCheckedStatus();
this.loading = null;
this.getConditionMonitoring()
return true
},
error: (err) => {
resolve(err)
this.loading = null;
return false
}
})
})
} else {
this.message.create('warning', '请填写完整!');
return false
}
}
});
const instance = modal.getContentComponent();
}
}

34
src/app/system-management/system-management-routing.module.ts

@ -0,0 +1,34 @@
import { Routes, RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { OrganizationComponent } from './organization/organization.component';
import { AnalysisOfTheHostComponent } from './analysis-of-the-host/analysis-of-the-host.component';
import { HostConfigComponent } from './host-config/host-config.component';
import { ImageListComponent } from './image-list/image-list.component';
import { PlottingImageComponent } from './plotting-image/plotting-image.component';
import { ImageLabel2Component } from './image-label2/image-label2.component';
import { ConfigFormComponent } from './config-form/config-form.component';
import { ConditionMonitoringComponent } from './condition-monitoring/condition-monitoring.component';
import { KafkaComponent } from './kafka/kafka.component';
import { StatusMonitoringComponent } from './status-monitoring/status-monitoring.component';
import { VideoStreamingComponent } from './video-streaming/video-streaming.component';
const routes: Routes = [
{ path: 'organization', component: OrganizationComponent },
{ path: 'host', component: AnalysisOfTheHostComponent },
{ path: 'host/camera', component: HostConfigComponent },
{ path: 'host/camera/imageList', component: ImageListComponent },
{ path: 'host/camera/imageLabel', component: ImageLabel2Component },
{ path: 'host/camera/configForm', component: ConfigFormComponent },
{ path: 'plottingImage', component: PlottingImageComponent },
{ path: 'conditionMonitoring', component: ConditionMonitoringComponent },
{ path: 'statusMonitoring', component: StatusMonitoringComponent },
{ path: 'kafka', component: KafkaComponent },
{ path: 'videoStreaming', component: VideoStreamingComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SystemRoutingModule { }

76
src/app/system-management/system-management.module.ts

@ -0,0 +1,76 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SystemRoutingModule } from './system-management-routing.module';
import { OrganizationComponent } from './organization/organization.component';
import { NavigationComponent } from './navigation/navigation.component';
import { NzLayoutModule } from 'ng-zorro-antd/layout';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
import { NzPaginationModule } from 'ng-zorro-antd/pagination';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzFormModule } from 'ng-zorro-antd/form';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzSelectModule } from 'ng-zorro-antd/select';
import { NzMessageModule } from 'ng-zorro-antd/message';
import { NzTreeModule } from 'ng-zorro-antd/tree';
import { NzSpinModule } from 'ng-zorro-antd/spin';
import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
import { AddorComponent } from './organization/addor/addor.component';
import { EditorComponent } from './organization/editor/editor.component';
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
import { AnalysisOfTheHostComponent } from './analysis-of-the-host/analysis-of-the-host.component';
import { AddhostComponent } from './analysis-of-the-host/addhost/addhost.component';
import { EdithostComponent } from './analysis-of-the-host/edithost/edithost.component';
import { AddcameraComponent } from './host-config/addcamera/addcamera.component';
import { EditcameraComponent } from './host-config/editcamera/editcamera.component';
import { HostConfigComponent } from './host-config/host-config.component';
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
import { PlottingImageComponent } from './plotting-image/plotting-image.component';
import { cameraType } from '../pipe/cameraTypePipe';
import { ImageListComponent } from './image-list/image-list.component';
import { ImageLabelComponent } from './image-label/image-label.component';
import { ImageLabel2Component } from './image-label2/image-label2.component';
import { ConfigFormComponent } from './config-form/config-form.component';
import { NzTabsModule } from 'ng-zorro-antd/tabs';
import { ConditionMonitoringComponent } from './condition-monitoring/condition-monitoring.component';
import { SendFileComponent } from './host-config/send-file/send-file.component';
import { ModelComponent } from './condition-monitoring/model/model.component';
import { KafkaComponent } from './kafka/kafka.component';
import { StatusMonitoringComponent } from './status-monitoring/status-monitoring.component';
import { FileComponent } from './condition-monitoring/file/file.component';
import { ScriptComponent } from './status-monitoring/script/script.component';
import { VideoStreamingComponent } from './video-streaming/video-streaming.component';
@NgModule({
declarations: [OrganizationComponent, NavigationComponent, AddorComponent, EditorComponent, AnalysisOfTheHostComponent, AddhostComponent, EdithostComponent, AddcameraComponent, EditcameraComponent, HostConfigComponent, ImageListComponent, ImageLabelComponent, PlottingImageComponent, cameraType, ImageLabel2Component, ConfigFormComponent, ConditionMonitoringComponent, SendFileComponent, ModelComponent, KafkaComponent, StatusMonitoringComponent, FileComponent, ScriptComponent, VideoStreamingComponent],
imports: [
CommonModule,
SystemRoutingModule,
NzLayoutModule,
NzIconModule,
NzTableModule,
NzDropDownModule,
NzPaginationModule,
NzInputModule,
NzButtonModule,
NzFormModule,
FormsModule,
ReactiveFormsModule,
NzModalModule,
NzSelectModule,
NzMessageModule,
NzTreeModule,
NzSpinModule,
NzTreeSelectModule,
NzCheckboxModule,
NzPageHeaderModule,
NzTabsModule,
NzPopconfirmModule
],
entryComponents: [AddorComponent, EditorComponent, AddhostComponent, EdithostComponent, AddcameraComponent, EditcameraComponent, SendFileComponent, ModelComponent, FileComponent,ScriptComponent]
})
export class SystemManagementModule { }

116
src/app/system-management/video-streaming/video-streaming.component.html

@ -0,0 +1,116 @@
<div class="box">
<div class="topbox">
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
<nz-form-item class="searchParams">
<nz-form-control>
<nz-tree-select [nzAllowClear]="false" [nzDropdownClassName]="'maxHeightTreeSelect'" nzShowSearch
formControlName="organization" [nzNodes]="nodes" nzPlaceHolder="请选择所属机构"
[(ngModel)]="defaultOrId" [nzExpandedIcon]="multiExpandedIconTpl">
</nz-tree-select>
<ng-template #multiExpandedIconTpl let-node let-origin="origin">
<ng-container *ngIf="node.children.length == 0; else elseTemplate">
</ng-container>
<ng-template #elseTemplate>
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'"
class="ant-tree-switcher-line-icon"></i>
</ng-template>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<!-- <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="state">设备状态</nz-form-label> -->
<nz-form-control>
<nz-select formControlName="state" nzPlaceHolder="请选择设备状态">
<nz-option [nzValue]="0" nzLabel="离线"></nz-option>
<nz-option [nzValue]="1" nzLabel="在线"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button nzType="primary" type="submit" class="submit"><i nz-icon
[nzType]="'search'"></i>查询</button>
</nz-form-control>
</nz-form-item>
<nz-form-item class="btn">
<nz-form-control>
<button nz-button type="button" class="reset" (click)="resetForm($event)"><i nz-icon
[nzType]="'sync'"></i>重置</button>
</nz-form-control>
</nz-form-item>
<!-- <button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'RestartApps'" (click)="sendRequest('RestartApps')">
重启识别程序
</button>
<button nz-button nzType="primary" type="button" [disabled]="setOfCheckedId.size === 0"
[nzLoading]="loading == 'RestartMonitors'" (click)="sendRequest('RestartMonitors')">
重启监控程序
</button> -->
</form>
</div>
<nz-table #basicTable nzShowSizeChanger [nzData]="listOfData" [nzLoading]="isLoading"
(nzCurrentPageDataChange)="onCurrentPageDataChange($event)" [nzShowPagination]='false' [nzPageSize]='10'>
<thead>
<tr>
<!-- <th [nzChecked]="checked" [nzIndeterminate]="indeterminate" (nzCheckedChange)="onAllChecked($event)">
</th> -->
<!-- <th>IP</th> -->
<th>所属油站</th>
<th>设备状态</th>
<th>报告时间</th>
<th>报告内容</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<!-- <td [nzChecked]="setOfCheckedId.has(data.id)" [nzDisabled]="data.disabled"
(nzCheckedChange)="onItemChecked(data.id, $event)"></td> -->
<!-- <td>{{ data.hostIPAddress }}</td> -->
<td>{{ data.gasStationName }}</td>
<td>
<ng-container *ngIf="data.hubConnectionState == 'Disconnected'; else elseTemplate">
<span style="color: red;">离线</span>
</ng-container>
<ng-template #elseTemplate>
<span style="color: rgb(52, 204, 52);">在线</span>
</ng-template>
</td>
<td>
<p>
开始时间:{{data.beginTime ? (data.beginTime | date:"yyyy-MM-dd HH:mm:ss")
:'/'}}
</p>
<p>
结束时间:{{data.endTime ? (data.endTime | date:"yyyy-MM-dd HH:mm:ss") :'/'}}
</p>
</td>
<td>
<span class="blue" (click)="showModal()">详情</span>
<nz-modal [(nzVisible)]="isVisible" nzTitle="详情" (nzOnCancel)="handleCancel()"
(nzOnOk)="handleOk()">
<ng-container *nzModalContent>
{{data.detail}}
</ng-container>
</nz-modal>
</td>
<td>
<span class="blue" (click)="dispose(data)">处置</span>
</td>
</tr>
</tbody>
</nz-table>
<div class="pagination">
<nz-pagination [nzHideOnSinglePage]="false" [nzPageIndex]="1" [nzTotal]="num" [nzPageSize]="10"
[nzShowTotal]="totalTemplate" nzShowQuickJumper (nzPageIndexChange)="pageChange($event)">
</nz-pagination>
<ng-template #totalTemplate let-total> 10条/页,共{{num}}条 </ng-template>
</div>
</div>

17
src/app/system-management/video-streaming/video-streaming.component.scss

@ -0,0 +1,17 @@
.topbox {
form {
display: flex;
nz-form-item {
margin-right: 6px;
}
button {
margin-right: 6px;
}
}
.searchParams {
width: 250px;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save