提交 e9e3f35f 编写于 作者: J Jason

删除冗余

上级 947de3d0
package dbus
import (
"git.zgwit.com/iot/beeq"
"git.zgwit.com/iot/beeq/packet"
"iot-master/db"
"iot-master/model"
"log"
)
var hive *beeq.Hive
func Start(addr string) error {
hive = beeq.NewHive()
hive.OnConnect(func(connect *packet.Connect, bee *beeq.Bee) bool {
// 验证插件 Key Secret
var plugin model.Plugin
has, err := db.Engine.Where("key=?", connect.UserName()).Get(&plugin)
if !has {
if plugin.Secret == string(connect.Password()) {
return true
} else {
return false
}
} else if err != nil {
log.Println(err)
return false
}
//TODO 验证浏览器
log.Println(bee.ClientId(), "connect", connect)
return true
})
//hive.OnPublish(func(publish *packet.Publish, bee *beeq.Bee) bool {
// log.Println(bee.ClientId(), "publish", publish)
// return true
//})
return hive.ListenAndServe(addr)
}
func Hive() *beeq.Hive {
return hive
}
# 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
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
# 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
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
# DtuAdmin
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.0.4.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"MyDTU": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss",
"skipTests": true
},
"@schematics/angular:class": {
"skipTests": true
},
"@schematics/angular:directive": {
"skipTests": true
},
"@schematics/angular:guard": {
"skipTests": true
},
"@schematics/angular:interceptor": {
"skipTests": true
},
"@schematics/angular:module": {
"skipTests": true
},
"@schematics/angular:pipe": {
"skipTests": true
},
"@schematics/angular:service": {
"skipTests": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "./dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/theme.less",
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "MyDTU:build"
},
"configurations": {
"production": {
"browserTarget": "MyDTU:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "MyDTU: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",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "MyDTU:serve"
},
"configurations": {
"production": {
"devServerTarget": "MyDTU:serve:production"
}
}
}
}
}
},
"defaultProject": "MyDTU"
}
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
browserName: 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY
}
}));
}
};
\ No newline at end of file
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('MyDTU app is running!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo(): Promise<unknown> {
return browser.get(browser.baseUrl) as Promise<unknown>;
}
getTitleText(): Promise<string> {
return element(by.css('app-root .content span')).getText() as Promise<string>;
}
}
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es2018",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
// 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-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/MyDTU'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
此差异已折叠。
{
"name": "MyDTU",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json -o",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^10.0.14",
"@angular/common": "~10.0.5",
"@angular/compiler": "~10.0.5",
"@angular/core": "~10.0.5",
"@angular/forms": "~10.0.5",
"@angular/platform-browser": "~10.0.5",
"@angular/platform-browser-dynamic": "~10.0.5",
"@angular/router": "~10.0.5",
"@ctrl/ngx-codemirror": "^4.0.2",
"codemirror": "^5.58.3",
"moment": "^2.27.0",
"mqtt": "^4.2.1",
"ng-zorro-antd": "^9.3.0",
"ngx-moment": "^5.0.0",
"ngx-mqtt": "^7.0.14",
"rxjs": "~6.5.5",
"tslib": "^2.0.0",
"zone.js": "~0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1000.4",
"@angular/cli": "~10.0.4",
"@angular/compiler-cli": "~10.0.5",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~3.3.0",
"karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~3.9.5"
}
}
{
"/api": {
"target": "http://localhost:8080",
"secure": false
}
}
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {NzMessageService} from 'ng-zorro-antd';
import {catchError, filter, map} from 'rxjs/operators';
import {Observable, of} from 'rxjs';
import {Router} from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class ApiService {
public base = '/api/'; // environment.host;
constructor(private http: HttpClient, private message: NzMessageService, private route: Router) {
}
request(method: string, uri: string, options: any): Observable<any> {
// 携带Cookie,保持session会话
options.withCredentials = true;
return this.http.request<any>(method, this.base + uri, options).pipe(
// 捕捉异常,数据转换
catchError(err => {
if (err.status === 404) {
return of({error: '无效接口 ' + method + ' ' + uri});
} else if (err.status === 401) {
// window.location.href = '/login';
this.route.navigate(['/login']);
return of({error: '未登录'});
}
return of({error: err.message});
}),
// 统一错误处理
map((ret: any) => {
if (ret && ret.error) {
// 有错误统一显示并不是好的做法
this.message.create('error', ret.error);
// throw new Error(ret.error); //会阻断 complete
}
return ret;
})
);
}
get(uri: string, params?: { [k: string]: any }): Observable<any> {
return this.request('GET', uri, {params});
}
put(uri: string, body: any | null, params?: { [k: string]: any }): Observable<any> {
return this.request('PUT', uri, {params, body});
}
post(uri: string, body: any | null, params?: { [k: string]: any }): Observable<any> {
return this.request('POST', uri, {params, body});
}
patch(uri: string, body: any | null, params?: { [k: string]: any }): Observable<any> {
return this.request('PATCH', uri, {params, body});
}
delete(uri: string, params?: { [k: string]: any }): Observable<any> {
return this.request('DELETE', uri, {params});
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {LoginComponent} from './login/login.component';
import {PageNotFoundComponent} from './page-not-found/page-not-found.component';
const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: '/admin' },
{ path: 'login', pathMatch: 'full', component: LoginComponent},
{ path: 'admin', loadChildren: () => import('./main/main.module').then(m => m.MainModule) },
{ path: '**', component: PageNotFoundComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
}
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {CommonModule} from '@angular/common';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {HttpClientModule} from '@angular/common/http';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {NZ_I18N} from 'ng-zorro-antd/i18n';
import {zh_CN} from 'ng-zorro-antd/i18n';
import {registerLocaleData} from '@angular/common';
import zh from '@angular/common/locales/zh';
import {LoginComponent} from './login/login.component';
import {
NzButtonModule,
NzCheckboxModule,
NzFormModule,
NzIconModule,
NzInputModule,
NzMessageModule
} from 'ng-zorro-antd';
import {IconsProviderModule} from './icons-provider.module';
import {PageNotFoundComponent} from './page-not-found/page-not-found.component';
registerLocaleData(zh);
@NgModule({
declarations: [
AppComponent,
LoginComponent,
PageNotFoundComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule,
BrowserAnimationsModule,
NzButtonModule,
NzFormModule,
NzInputModule,
NzCheckboxModule,
NzIconModule,
NzMessageModule,
IconsProviderModule,
],
providers: [{provide: NZ_I18N, useValue: zh_CN}],
bootstrap: [AppComponent]
})
export class AppModule {
}
import { NgModule } from '@angular/core';
import { NZ_ICONS, NzIconModule } from 'ng-zorro-antd/icon';
import {
UserOutline,
LockOutline,
} from '@ant-design/icons-angular/icons';
const icons = [UserOutline, LockOutline];
@NgModule({
imports: [NzIconModule],
exports: [NzIconModule],
providers: [
{ provide: NZ_ICONS, useValue: icons }
]
})
export class IconsProviderModule {
}
<div class="login">
<h1>IoT Admin</h1>
<div class="login-form" >
<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
<nz-form-item>
<nz-form-control nzErrorTip="请输入用户名!">
<nz-input-group nzPrefixIcon="user">
<input type="text" nz-input 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 type="password" nz-input formControlName="password" placeholder="密码" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<div nz-row class="login-form-margin">
<div nz-col [nzSpan]="12">
<label nz-checkbox formControlName="remember" nzDisabled>
<span>记住我</span>
</label>
</div>
<div nz-col [nzSpan]="12">
<a class="login-form-forgot">忘记密码</a>
</div>
</div>
<button nz-button class="login-form-button login-form-margin" [nzType]="'primary'">登 录</button>
</form>
</div>
</div>
:host{
display: flex;
justify-content: center;
align-content: center;
width: 100%;
height: 100%;
background-image: url("../../assets/bk.jpg");
background-size: cover;
background-position: center;
}
.login{
margin-top: 100px;
width: 300px;
max-width: 400px;
>h1{
color: white;
text-align: center;
}
}
.login-form {
background-color: white;
padding: 50px;
}
.login-form-margin {
margin-bottom: 16px;
}
.login-form-forgot {
float: right;
}
.login-form-button {
width: 100%;
}
import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {ApiService} from '../api.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
validateForm!: FormGroup;
constructor(private fb: FormBuilder, private ca: ApiService, private router: Router) {}
submitForm(): void {
console.log('submit form');
for (const i in this.validateForm.controls) {
this.validateForm.controls[i].markAsDirty();
this.validateForm.controls[i].updateValueAndValidity();
}
if (!this.validateForm.valid) {
return;
}
this.ca.post('login', this.validateForm.value).subscribe(res => {
console.log('res:', res);
this.router.navigate(['/admin/dash']);
}, err => {
console.log('err:', err);
});
}
ngOnInit(): void {
this.validateForm = this.fb.group({
username: [null, [Validators.required]],
password: [null, [Validators.required]],
remember: [false]
});
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.scss']
})
export class AlertComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-algorithm',
templateUrl: './algorithm.component.html',
styleUrls: ['./algorithm.component.scss']
})
export class AlgorithmComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
<nz-row [nzGutter]="16">
<nz-col [nzSpan]="12">
<nz-statistic [nzValue]="(4 | number)!" nzTitle="通道数量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="12">
<nz-statistic [nzValue]="(1620 | number)!" nzTitle="连接数量"></nz-statistic>
</nz-col>
</nz-row>
<!-- TODO 流量曲线,数据包曲线,实时 -->
import {Component, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {TabRef} from "../tabs/tabs.component";
@Component({
selector: 'app-dash',
templateUrl: './dash.component.html',
styleUrls: ['./dash.component.scss']
})
export class DashComponent implements OnInit {
constructor(private as: ApiService, private tab: TabRef) {
tab.name = '仪表盘';
}
ngOnInit(): void {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-device-detail',
templateUrl: './device-detail.component.html',
styleUrls: ['./device-detail.component.scss']
})
export class DeviceDetailComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-device-log',
templateUrl: './device-log.component.html',
styleUrls: ['./device-log.component.scss']
})
export class DeviceLogComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-device-map',
templateUrl: './device-map.component.html',
styleUrls: ['./device-map.component.scss']
})
export class DeviceMapComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-device',
templateUrl: './device.component.html',
styleUrls: ['./device.component.scss']
})
export class DeviceComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
<p>TODO:元件基本信息</p>
<nz-tabset>
<nz-tab nzTitle="变量">
</nz-tab>
<nz-tab nzTitle="批量">
</nz-tab>
</nz-tabset>
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
import {ApiService} from '../../api.service';
@Component({
selector: 'app-element-detail',
templateUrl: './element-detail.component.html',
styleUrls: ['./element-detail.component.scss']
})
export class ElementDetailComponent implements OnInit {
element: any = {};
id = 0;
constructor(private as: ApiService, private routeInfo: ActivatedRoute, private tab: TabRef) {
this.id = routeInfo.snapshot.params.id;
tab.name = '元件详情';
}
ngOnInit(): void {
this.as.get('element/' + this.id).subscribe(res => {
if (res.ok) {
this.element = res.data;
this.tab.name = '元件【' + this.element.name + '';
}
// console.log(res);
});
}
}
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
名称
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.name" placeholder="名称"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
说明
</div>
<div nz-col nzSpan="20">
<textarea nz-input [(ngModel)]="data.description" placeholder="说明"></textarea>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
来源
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.origin" placeholder="来源"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
生产厂商
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.manufacturer" placeholder="生产厂商"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
型号
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.model" placeholder="型号"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
版本号
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.version" placeholder="版本号"/>
</div>
</div>
<button nz-button nzType="primary" (click)="submit()">保存</button>
import {Component, Input, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {ActivatedRoute} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
import {NzMessageService, NzModalRef} from 'ng-zorro-antd';
@Component({
selector: 'app-element-edit',
templateUrl: './element-edit.component.html',
styleUrls: ['./element-edit.component.scss']
})
export class ElementEditComponent implements OnInit {
target = 'element';
@Input() id = 0;
data: any = {};
constructor(private as: ApiService, private mr: NzModalRef, private ms: NzMessageService) {
}
ngOnInit(): void {
if (this.id > 0) {
this.as.get(this.target + '/' + this.id).subscribe(res => {
this.data = res.data;
});
}
}
submit(): void {
let uri = this.target;
if (this.data.id) {
uri += '/' + this.data.id;
}
this.as.post(uri, this.data).subscribe(res => {
if (res.ok) {
this.ms.success('保存成功');
this.mr.close(res.data);
}
});
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-element-variable-edit',
templateUrl: './element-variable-edit.component.html',
styleUrls: ['./element-variable-edit.component.scss']
})
export class ElementVariableEditComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<button nz-button (click)="create()">
<i nz-icon nzType="plus"></i>
创建
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="variables" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="ProjectId" [nzSortFn]="true">项目ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="Slave" [nzSortFn]="true">站号</th>
<th nzColumnKey="Alias" [nzSortFn]="true">别名</th>
<th nzColumnKey="Created" [nzSortFn]="true">创建时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data">
<td>{{ data.id }}</td>
<td>{{ data.project_id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.slave }}</td>
<td>{{ data.alias }}</td>
<td>{{ data.created | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a (click)="edit(data)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
import {Component, Input, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {NzTableQueryParams} from 'ng-zorro-antd';
import {Router} from '@angular/router';
@Component({
selector: 'app-element-variable',
templateUrl: './element-variable.component.html',
styleUrls: ['./element-variable.component.scss']
})
export class ElementVariableComponent implements OnInit {
@Input() element: any = {};
inited = false;
tableQuery: any;
variables: [];
total = 0;
pageIndex = 1;
pageSize = 10;
sortField = null;
sortOrder = null;
filters = [];
keyword = '';
loading = false;
constructor(private as: ApiService, private router: Router) {
}
ngOnInit(): void {
this.inited = true;
if (this.tableQuery) {
this.onTableQuery(this.tableQuery)
}
}
reload(): void {
this.pageIndex = 1;
this.keyword = '';
this.load();
}
load(): void {
this.loading = true;
this.as.post('element/' + this.element.id + '/variables', {
offset: (this.pageIndex - 1) * this.pageSize,
length: this.pageSize,
sortKey: this.sortField,
sortOrder: this.sortOrder,
filters: this.filters,
keyword: this.keyword,
}).subscribe(res => {
this.variables = res.data;
this.total = res.total;
}, error => {
console.log('error', error);
}, () => {
this.loading = false;
});
}
create(): void {
this.router.navigate(['/admin/element/' + this.element.id + '/variable/create']);
}
edit(c): void {
this.router.navigate(['/admin/element/' + this.element.id + '/variable/' + c.id + '/edit']);
}
onTableQuery(params: NzTableQueryParams): void {
if (!this.inited) {
this.tableQuery = params;
return;
}
const {pageSize, pageIndex, sort, filter} = params;
this.pageSize = pageSize;
this.pageIndex = pageIndex;
const currentSort = sort.find(item => item.value !== null);
this.sortField = (currentSort && currentSort.key) || null;
this.sortOrder = (currentSort && currentSort.value) || null;
this.filters = filter;
this.load();
}
search(): void {
this.pageIndex = 1;
this.load();
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<button nz-button (click)="edit()">
<i nz-icon nzType="plus"></i>
创建
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="datum" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="UUID" [nzSortFn]="true">UUID</th>
<th nzColumnKey="Manufacturer" [nzSortFn]="true">状态</th>
<th nzColumnKey="Model" [nzSortFn]="true">型号</th>
<th nzColumnKey="Version" [nzSortFn]="true">版本号</th>
<th nzColumnKey="Created" [nzSortFn]="true">创建时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data" (dblclick)="detail(data)">
<td>{{ data.id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.uuid }}</td>
<td>{{ data.manufacturer }}</td>
<td>{{ data.model }}</td>
<td>{{ data.version }}</td>
<td>{{ data.created | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a (click)="detail(data)" title="详情">
<i nz-icon nzType="eye"></i>
</a>
<a (click)="edit(data.id)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
import {Component, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {NzModalService, NzTableQueryParams} from 'ng-zorro-antd';
import {Router} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
import {ElementEditComponent} from "../element-edit/element-edit.component";
@Component({
selector: 'app-element',
templateUrl: './element.component.html',
styleUrls: ['./element.component.scss']
})
export class ElementComponent implements OnInit {
datum: any[];
total = 0;
pageIndex = 1;
pageSize = 10;
sortField = null;
sortOrder = null;
filters = [];
keyword = '';
loading = false;
constructor(private as: ApiService, private router: Router, private tab: TabRef, private ms: NzModalService) {
tab.name = '元件管理';
}
ngOnInit(): void {
}
reload(): void {
this.pageIndex = 1;
this.keyword = '';
this.load();
}
load(): void {
this.loading = true;
this.as.post('elements', {
offset: (this.pageIndex - 1) * this.pageSize,
length: this.pageSize,
sortKey: this.sortField,
sortOrder: this.sortOrder,
filters: this.filters,
keywords: [
{key: 'Name', value: this.keyword},
]
}).subscribe(res => {
this.datum = res.data;
this.total = res.total;
}, error => {
console.log('error', error);
}, () => {
this.loading = false;
});
}
edit(id?): void {
const modal = this.ms.create({
nzTitle: id ? '编辑元件' : '创建元件',
nzContent: ElementEditComponent,
nzFooter: null,
nzMaskClosable: false,
// nzViewContainerRef: this.viewContainerRef,
nzComponentParams: {id},
});
// insert/update after close
modal.afterClose.subscribe(data => {
if (!data) {
return;
}
if (id) {
this.datum.forEach((c: any, i, a: any[]) => {
if (c.id === data.id) {
a[i] = data;
}
}
);
} else {
this.datum.unshift(data);
}
});
}
detail(c): void {
this.router.navigate(['/admin/element/' + c.id + '/detail']);
}
onTableQuery(params: NzTableQueryParams): void {
const {pageSize, pageIndex, sort, filter} = params;
this.pageSize = pageSize;
this.pageIndex = pageIndex;
const currentSort = sort.find(item => item.value !== null);
this.sortField = (currentSort && currentSort.key) || null;
this.sortOrder = (currentSort && currentSort.value) || null;
this.filters = filter;
this.load();
}
search(): void {
this.pageIndex = 1;
this.load();
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-history',
templateUrl: './history.component.html',
styleUrls: ['./history.component.scss']
})
export class HistoryComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
import {NgModule} from '@angular/core';
import {NZ_ICONS, NzIconModule} from 'ng-zorro-antd/icon';
import {
MenuFoldOutline,
MenuUnfoldOutline,
DashboardOutline,
SettingOutline,
LogoutOutline,
ApiOutline,
ReloadOutline,
PlusOutline,
DeleteOutline,
AppstoreOutline,
AimOutline,
SwapOutline,
ClusterOutline,
AlertOutline,
CloudUploadOutline,
ProjectOutline,
BlockOutline,
DatabaseOutline,
EyeOutline,
} from '@ant-design/icons-angular/icons';
import {CommonModule} from '@angular/common';
const icons = [
// 菜单相关
MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, ApiOutline, SettingOutline, AppstoreOutline,
// 表格操作
ReloadOutline, PlusOutline, DeleteOutline, AimOutline, SwapOutline,
LogoutOutline, ClusterOutline, AlertOutline, CloudUploadOutline, ProjectOutline, BlockOutline, DatabaseOutline, EyeOutline
];
@NgModule({
imports: [CommonModule, NzIconModule.forChild(icons)],
exports: [NzIconModule],
providers: [
{provide: NZ_ICONS, useValue: icons}
]
})
export class IconsProviderModule {
}
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
名称
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.name" placeholder="名称"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
序列号
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.serial" placeholder="序列号"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
禁用
</div>
<div nz-col nzSpan="20">
<nz-switch [(ngModel)]="data.disabled"></nz-switch>
</div>
</div>
<button nz-button nzType="primary" (click)="submit()">保存</button>
import {Component, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {ActivatedRoute, Router} from '@angular/router';
import {TabRef} from "../tabs/tabs.component";
@Component({
selector: 'app-link-edit',
templateUrl: './link-edit.component.html',
styleUrls: ['./link-edit.component.scss']
})
export class LinkEditComponent implements OnInit {
target = 'link';
id = 0;
data: any = {};
constructor(private as: ApiService, private routeInfo: ActivatedRoute, private tab: TabRef) {
tab.name = '链路编辑';
}
ngOnInit(): void {
this.id = this.routeInfo.snapshot.params.id || 0;
if (this.id > 0) {
this.as.get(this.target + '/' + this.id).subscribe(res => {
this.data = res.data;
});
}
}
submit(): void {
this.as.put(this.target + '/' + this.data.id, this.data).subscribe(res => {
console.log(res);
// TODO 修改成功
this.tab.Close();
});
}
}
<!-- TODO: 工作状态,数据收发量,速度-->
<div class="send-area">
<textarea [(ngModel)]="text" style="resize: vertical"></textarea>
<div class="submit">
<label nz-checkbox [(ngModel)]="isHex">十六进制</label>
<button nz-button nzType="primary" (click)="send()">发送</button>
</div>
</div>
<div nz-row [nzGutter]="10" class="monitor">
<div nz-col nzSpan="12" nzXs="24" nzSm="12">
<div class="title">
数据接收
</div>
<div class="content" #contentRecv>
<div *ngFor="let d of dataRecv">
{{d.time | amDateFormat: 'hh:mm:ss'}} -&gt; {{d.data}}
</div>
</div>
</div>
<div nz-col nzSpan="12" nzXs="24" nzSm="12">
<div class="title">
数据发送
</div>
<div class="content" #contentSend>
<div *ngFor="let d of dataSend">
{{d.time | amDateFormat: 'hh:mm:ss'}} -&gt; {{d.data}}
</div>
</div>
</div>
</div>
.monitor{
.title {
text-align: center;
padding: 5px;
}
.content {
min-height: 200px;
max-height: 400px;
border: 1px solid grey;
overflow-y: auto;
overflow-x: hidden;
word-break: break-all;
}
}
.send-area{
display: flex;
align-items: center;
justify-content: center;
textarea{
flex: 1;
min-height: 40px;
max-height: 100px;
}
.submit{
display: flex;
flex-direction: column;
width: 100px;
padding: 5px;
}
}
import {Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {ApiService} from '../../api.service';
import {MqttService} from '../../mqtt.service';
import {TabRef} from "../tabs/tabs.component";
@Component({
selector: 'app-link-monitor',
templateUrl: './link-monitor.component.html',
styleUrls: ['./link-monitor.component.scss']
})
export class LinkMonitorComponent implements OnInit, OnDestroy {
@ViewChild('contentRecv')
contentRecv: ElementRef;
@ViewChild('contentSend')
contentSend: ElementRef;
id: number;
link: any;
isHex = false;
text = '';
dataRecv = [];
dataSend = [];
cacheSizeRecv = 500;
cacheSizeSend = 500;
recvSub: any;
sendSub: any;
constructor(private routeInfo: ActivatedRoute, private as: ApiService, private tab: TabRef, private mqtt: MqttService) {
tab.name = '连接监控';
this.id = this.routeInfo.snapshot.params.id;
this.load();
}
ngOnInit(): void {
}
ngOnDestroy(): void {
this.recvSub.unsubscribe();
this.sendSub.unsubscribe();
}
hex_to_buffer(hex: string): Buffer {
hex = hex.replace(/\s*/g, '');
const arr = [];
for (let i = 0; i < hex.length; i += 2) {
arr.push(hex.substr(i, 2));
}
const hexes = arr.map(el => parseInt(el, 16));
return Buffer.from(new Uint8Array(hexes));
}
buffer_to_hex(buf): string {
const arr = Array.prototype.slice.call(buf);
return arr.map(el => Number(el).toString(16)).join(' ');
}
subscribe(): void {
this.recvSub = this.mqtt.subscribe('/link/' + this.link.channel_id + '/' + this.id + '/recv').subscribe(packet => {
this.dataRecv.push({
data: this.buffer_to_hex(packet.payload),
time: new Date(),
});
if (this.dataRecv.length > this.cacheSizeRecv) {
this.dataRecv.splice(0, 1);
}
this.contentRecv.nativeElement.scrollTo(0, this.contentRecv.nativeElement.scrollHeight);
});
this.sendSub = this.mqtt.subscribe('/link/' + this.link.channel_id + '/' + this.id + '/send').subscribe(packet => {
this.dataSend.push({
data: this.buffer_to_hex(packet.payload),
time: new Date(),
});
if (this.dataSend.length > this.cacheSizeSend) {
this.dataSend.splice(0, 1);
}
this.contentSend.nativeElement.scrollTo(0, this.contentSend.nativeElement.scrollHeight);
});
}
load(): void {
this.as.get('link/' + this.id).subscribe(res => {
this.link = res.data;
this.subscribe();
});
}
loadStatus(): void {
// 在线,monitor
}
send(): void {
//console.log('send', this.text);
let content: any = this.text;
// 转换十六进制
if (this.isHex) {
content = this.hex_to_buffer(this.text);
}
this.mqtt.publish('/link/' + this.link.channel_id + '/' + this.id + '/transfer', content);
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="links" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="ChannelId" [nzSortFn]="true">通道ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="Serial" [nzSortFn]="true">序列号</th>
<th nzColumnKey="Addr" [nzSortFn]="true">地址</th>
<th nzColumnKey="Active" nzShowFilter [nzFilterFn]="true" [nzFilters]="statusFilters">状态</th>
<th nzColumnKey="Online" [nzSortFn]="true">上线时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data">
<td>{{ data.id }}</td>
<td>{{ data.tunnel_id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.serial }}</td>
<td>{{ data.addr}}</td>
<td>
{{ data.active ? '活跃' : '-' }}
</td>
<td>{{ data.online | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a [routerLink]="'/admin/link-monitor/'+data.id" title="监控">
<i nz-icon nzType="aim"></i>
</a>
<nz-divider nzType="vertical"></nz-divider>
<a (click)="transfer(data)" title="透传">
<i nz-icon nzType="swap"></i>
</a>
<nz-divider nzType="vertical"></nz-divider>
<a (click)="edit(data)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
import {Component, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {NzTableQueryParams} from 'ng-zorro-antd';
import {Router} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
@Component({
selector: 'app-link',
templateUrl: './link.component.html',
styleUrls: ['./link.component.scss']
})
export class LinkComponent implements OnInit {
links: [];
total = 0;
pageIndex = 1;
pageSize = 10;
sortField = null;
sortOrder = null;
filters = [];
keyword = '';
loading = false;
statusFilters = [{text: '启动', value: true}];
constructor(private as: ApiService, private router: Router, private tab: TabRef) {
tab.name = '连接管理';
}
ngOnInit(): void {
this.loadFilters();
}
reload(): void {
this.pageIndex = 1;
this.keyword = '';
this.load();
}
load(): void {
this.loading = true;
this.as.post('links', {
offset: (this.pageIndex - 1) * this.pageSize,
length: this.pageSize,
sortKey: this.sortField,
sortOrder: this.sortOrder,
filters: this.filters,
keyword: this.keyword,
}).subscribe(res => {
this.links = res.data;
this.total = res.total;
}, error => {
console.log('error', error);
}, () => {
this.loading = false;
});
}
loadFilters(): void {
// this.as.get('distinct/copy/host').subscribe(res => {
// console.log('res', res);
// this.hosts = res.data.map(h => {
// return {
// text: h.host,
// value: h.host
// };
// });
// }, error => {
// console.log('error', error);
// });
}
edit(c): void {
this.router.navigate(['/admin/link/' + c.id + '/edit/']);
}
onTableQuery(params: NzTableQueryParams): void {
const {pageSize, pageIndex, sort, filter} = params;
this.pageSize = pageSize;
this.pageIndex = pageIndex;
const currentSort = sort.find(item => item.value !== null);
this.sortField = (currentSort && currentSort.key) || null;
this.sortOrder = (currentSort && currentSort.value) || null;
this.filters = filter;
this.load();
}
search(): void {
this.pageIndex = 1;
this.load();
}
}
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {DashComponent} from './dash/dash.component';
import {MainComponent} from './main.component';
import {TunnelComponent} from './tunnel/tunnel.component';
import {TunnelEditComponent} from './tunnel-edit/tunnel-edit.component';
import {LinkComponent} from './link/link.component';
import {LinkEditComponent} from './link-edit/link-edit.component';
import {LinkMonitorComponent} from './link-monitor/link-monitor.component';
import {PluginComponent} from './plugin/plugin.component';
import {PluginEditComponent} from './plugin-edit/plugin-edit.component';
import {ProjectComponent} from './project/project.component';
import {ProjectEditComponent} from './project-edit/project-edit.component';
import {ProjectDetailComponent} from './project-detail/project-detail.component';
import {ElementComponent} from './element/element.component';
import {ElementDetailComponent} from './element-detail/element-detail.component';
import {ElementEditComponent} from './element-edit/element-edit.component';
import {HistoryComponent} from './history/history.component';
import {AlgorithmComponent} from './algorithm/algorithm.component';
import {AlertComponent} from './alert/alert.component';
import {DeviceComponent} from './device/device.component';
import {DeviceMapComponent} from './device-map/device-map.component';
import {DeviceLogComponent} from './device-log/device-log.component';
import {DeviceDetailComponent} from './device-detail/device-detail.component';
const routes: Routes = [
{
path: '',
component: MainComponent,
children: [
{path: '', redirectTo: 'dash'},
{path: 'dash', component: DashComponent},
{path: 'device', component: DeviceComponent},
{path: 'device/map', component: DeviceMapComponent},
{path: 'device/log', component: DeviceLogComponent},
{path: 'device/:id/detail', component: DeviceDetailComponent},
{path: 'device/:id/log', component: DeviceLogComponent},
{path: 'history', component: HistoryComponent},
{path: 'algorithm', component: AlgorithmComponent},
{path: 'alert', component: AlertComponent},
{path: 'tunnel', component: TunnelComponent},
{path: 'tunnel/create', component: TunnelEditComponent},
{path: 'tunnel/:id/edit', component: TunnelEditComponent},
{path: 'tunnel/:id/link', component: LinkComponent},
{path: 'link', component: LinkComponent},
{path: 'link/:id/edit', component: LinkEditComponent},
{path: 'link/:id/monitor', component: LinkMonitorComponent},
{path: 'project', component: ProjectComponent},
{path: 'project/create', component: ProjectEditComponent},
{path: 'project/:id/edit', component: ProjectEditComponent},
{path: 'project/:id/detail', component: ProjectDetailComponent},
{path: 'element', component: ElementComponent},
{path: 'element/create', component: ElementEditComponent},
{path: 'element/:id/edit', component: ElementEditComponent},
{path: 'element/:id/detail', component: ElementDetailComponent},
{path: 'plugin', component: PluginComponent},
{path: 'plugin/create', component: PluginEditComponent},
{path: 'plugin/:id/edit', component: PluginEditComponent},
{path: '**', redirectTo: 'dash'},
]
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MainRoutingModule {
}
<nz-layout class="app-layout">
<nz-sider class="menu-sidebar"
nzCollapsible
nzWidth="180px"
nzBreakpoint="md"
[(nzCollapsed)]="isCollapsed"
[nzTrigger]="null">
<div class="sidebar-logo">
<a href="https://github.com/zgwit/MyDTU" target="_blank">
<img src="assets/logo.svg" alt="logo">
<h1>IoT Admin</h1>
</a>
</div>
<ul nz-menu nzTheme="dark" nzMode="inline" [nzInlineCollapsed]="isCollapsed">
<li nz-submenu *ngFor="let menu of menus" [nzTitle]="menu.title" [nzIcon]="menu.icon" [nzOpen]="menu.open" [nzDisabled]="menu.disabled">
<ul>
<li nz-menu-item *ngFor="let m of menu.children" [routerLink]="m.router" [nzDisabled]="m.disabled" nzMatchRouter nzMatchRouterExact>
<i nz-icon [nzType]="m.icon" nzTheme="outline" *ngIf="m.icon"></i>
{{m.title}}
</li>
</ul>
</li>
</ul>
</nz-sider>
<nz-layout>
<nz-header>
<div class="app-header">
<span class="header-trigger" (click)="isCollapsed = !isCollapsed">
<i class="trigger"
nz-icon
[nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"
></i>
</span>
</div>
</nz-header>
<nz-content>
<app-tabs></app-tabs>
</nz-content>
</nz-layout>
</nz-layout>
:host {
display: flex;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.app-layout {
height: 100vh;
}
.menu-sidebar {
position: relative;
z-index: 10;
min-height: 100vh;
overflow-y: auto;
box-shadow: 2px 0 6px rgba(0,21,41,.35);
a{
color: inherit;
}
}
.header-trigger {
height: 64px;
padding: 20px 24px;
font-size: 20px;
cursor: pointer;
transition: all .3s,padding 0s;
}
.trigger:hover {
color: #1890ff;
}
.sidebar-logo {
position: relative;
height: 64px;
padding-left: 24px;
overflow: hidden;
line-height: 64px;
background: #001529;
transition: all .3s;
}
.sidebar-logo img {
display: inline-block;
height: 32px;
width: 32px;
vertical-align: middle;
}
.sidebar-logo h1 {
display: inline-block;
margin: 0 0 0 20px;
color: #fff;
font-weight: 600;
font-size: 14px;
font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;
vertical-align: middle;
}
nz-header {
padding: 0;
width: 100%;
z-index: 2;
}
.app-header {
position: relative;
height: 64px;
padding: 0;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
}
nz-content {
margin: 10px;
}
.inner-content {
padding: 10px;
background: #fff;
height: 100%;
}
import {
Component,
OnInit,
} from '@angular/core';
@Component({
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit {
isCollapsed = false;
menus = [
{
title: '控制台',
icon: 'dashboard',
open: true,
children: [
{
title: '仪表盘',
router: 'dash'
},
]
},
{
title: '设备中心',
icon: 'block',
children: [
{
title: '设备管理',
router: 'device'
},
{
title: '地图模式',
router: 'device/map'
},
{
title: '操作日志',
router: 'device/log'
},
]
},
{
title: '通道管理',
icon: 'api',
children: [
{
title: '通道管理',
router: 'tunnel'
},
{
title: '连接管理',
router: 'link'
}
]
},
{
title: '项目管理',
icon: 'block',
open: false,
children: [
{
title: '项目管理',
router: 'project'
},
{
title: '模板管理',
router: 'template'
},
{
title: '元件管理',
router: 'element'
},
]
},
{
title: '数据中心',
icon: 'database',
children: [
{
title: '历史记录',
router: 'history'
},
{
title: '算法分析',
router: 'algorithm'
},
]
},
{
title: '报警中心',
icon: 'alert',
children: [
{
title: '报警记录',
router: 'alert'
},
{
title: '微信通知',
router: 'alert-wechat'
},
{
title: '邮件通知',
router: 'alert-email'
},
{
title: '短信通知',
router: 'alert-sms'
}
]
},
{
title: 'OTA升级',
icon: 'cloud-upload',
open: false,
disabled: true,
children: [
{
title: '固件管理',
router: 'firmware'
},
{
title: '升级日志',
router: 'upgrade-log'
},
]
},
{
title: '设置',
icon: 'setting',
open: false,
children: [
{
title: '设置',
router: 'setting'
},
{
title: '邮件发件箱',
router: 'email'
},
{
title: '数据备份',
router: 'backup'
},
{
title: '系统日志',
router: 'logs'
},
]
}
];
constructor() {
}
ngOnInit(): void {
}
}
import {NgModule} from '@angular/core';
import {IconsProviderModule} from './icons-provider.module';
import {NzLayoutModule} from 'ng-zorro-antd/layout';
import {NzMenuModule} from 'ng-zorro-antd/menu';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {CommonModule} from '@angular/common';
import {HttpClientModule} from '@angular/common/http';
import {MainRoutingModule} from './main-routing.module';
import {MainComponent} from './main.component';
import {
NzButtonModule,
NzCheckboxModule, NzCollapseModule, NzDividerModule, NzDrawerModule,
NzFormModule,
NzIconModule,
NzInputModule, NzInputNumberModule,
NzModalModule, NzPopconfirmModule, NzSelectModule, NzStatisticModule, NzSwitchModule,
NzTableModule, NzTabsModule,
NzToolTipModule
} from 'ng-zorro-antd';
import {DashComponent} from './dash/dash.component';
import {MomentModule} from 'ngx-moment';
import {UiModule} from '../ui/ui.module';
import {TabsComponent} from './tabs/tabs.component';
import {TunnelComponent} from './tunnel/tunnel.component';
import {TunnelEditComponent} from './tunnel-edit/tunnel-edit.component';
import {LinkComponent} from './link/link.component';
import {LinkEditComponent} from './link-edit/link-edit.component';
import {LinkMonitorComponent} from './link-monitor/link-monitor.component';
import {PluginComponent} from './plugin/plugin.component';
import {PluginEditComponent} from './plugin-edit/plugin-edit.component';
import {ProjectComponent} from './project/project.component';
import {ProjectEditComponent} from './project-edit/project-edit.component';
import {ProjectDetailComponent} from './project-detail/project-detail.component';
import {TemplateComponent} from './template/template.component';
import {TemplateEditComponent} from './template-edit/template-edit.component';
import {TemplateDetailComponent} from './template-detail/template-detail.component';
import {ElementComponent} from './element/element.component';
import {ElementEditComponent} from './element-edit/element-edit.component';
import {ElementDetailComponent} from './element-detail/element-detail.component';
import {NzSpaceModule} from 'ng-zorro-antd/space';
import {ProjectElementComponent} from './project-element/project-element.component';
import {ProjectElementEditComponent} from './project-element-edit/project-element-edit.component';
import {ProjectJobComponent} from './project-job/project-job.component';
import {ProjectJobEditComponent} from './project-job-edit/project-job-edit.component';
import {ProjectStrategyComponent} from './project-strategy/project-strategy.component';
import {ProjectStrategyEditComponent} from './project-strategy-edit/project-strategy-edit.component';
import {ElementVariableComponent} from './element-variable/element-variable.component';
import {ElementVariableEditComponent} from './element-variable-edit/element-variable-edit.component';
import {ProjectLinkComponent} from './project-link/project-link.component';
import {ProjectLinkEditComponent} from './project-link-edit/project-link-edit.component';
import {ProjectFunctionComponent} from './project-function/project-function.component';
import {ProjectFunctionEditComponent} from './project-function-edit/project-function-edit.component';
import {CodemirrorModule} from "@ctrl/ngx-codemirror";
@NgModule({
declarations: [MainComponent, TabsComponent, DashComponent,
TunnelComponent, TunnelEditComponent,
LinkComponent, LinkEditComponent, LinkMonitorComponent,
PluginComponent, PluginEditComponent,
ProjectComponent, ProjectEditComponent, ProjectDetailComponent,
ProjectElementComponent, ProjectElementEditComponent,
ProjectJobComponent, ProjectJobEditComponent,
ProjectStrategyComponent, ProjectStrategyEditComponent,
ProjectLinkComponent, ProjectLinkEditComponent,
ProjectFunctionComponent, ProjectFunctionEditComponent,
ElementComponent, ElementEditComponent, ElementDetailComponent,
ElementVariableComponent, ElementVariableEditComponent,
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
MomentModule,
UiModule,
// IconsProviderModule,
// BrowserModule,
NzIconModule,
NzLayoutModule,
NzMenuModule,
HttpClientModule,
MainRoutingModule,
NzToolTipModule,
NzTableModule,
NzModalModule,
NzFormModule,
NzButtonModule,
NzInputModule,
NzCheckboxModule,
NzSwitchModule,
NzPopconfirmModule,
IconsProviderModule,
NzDividerModule,
NzDrawerModule,
NzSelectModule,
NzSpaceModule,
NzInputNumberModule,
NzStatisticModule,
NzTabsModule,
NzCollapseModule,
CodemirrorModule,
],
bootstrap: [MainComponent]
})
export class MainModule {
}
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
名称
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.name" placeholder="名称"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
密钥
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.key" placeholder="密钥"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
密码
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.secret" placeholder="密码"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
禁用
</div>
<div nz-col nzSpan="20">
<nz-switch [(ngModel)]="data.disabled"></nz-switch>
</div>
</div>
<button nz-button nzType="primary" (click)="submit()">保存</button>
import {Component, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {ActivatedRoute, Router} from '@angular/router';
import {TabRef} from "../tabs/tabs.component";
@Component({
selector: 'app-plugin-edit',
templateUrl: './plugin-edit.component.html',
styleUrls: ['./plugin-edit.component.scss']
})
export class PluginEditComponent implements OnInit {
target = 'plugin';
id = 0;
data: any = {};
constructor(private as: ApiService, private routeInfo: ActivatedRoute, private tab: TabRef) {
tab.name = '插件创建';
}
ngOnInit(): void {
this.id = this.routeInfo.snapshot.params.id || 0;
if (this.id > 0) {
this.as.get(this.target + '/' + this.id).subscribe(res => {
this.data = res.data;
});
}
}
submit(): void {
if (this.data.id) {
this.as.put(this.target + '/' + this.data.id, this.data).subscribe(res => {
console.log(res);
// TODO 修改成功
this.tab.Close();
});
} else {
this.as.post(this.target, this.data).subscribe(res => {
console.log(res);
// TODO 保存成功
this.tab.Close();
});
}
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<button nz-button (click)="create()">
<i nz-icon nzType="plus"></i>
创建
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="plugins" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="Key" [nzSortFn]="true">密钥</th>
<th nzColumnKey="Secret" [nzSortFn]="true">密码</th>
<th nzColumnKey="Status" nzShowFilter [nzFilterFn]="true" [nzFilters]="statusFilters">状态</th>
<th nzColumnKey="Created" [nzSortFn]="true">创建时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data">
<td>{{ data.id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.key }}</td>
<td>{{data.secret}}</td>
<td>
{{data.disabled ? '禁用' : ''}}
</td>
<td>{{ data.created | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a (click)="edit(data)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
import { Component, OnInit } from '@angular/core';
import {ApiService} from '../../api.service';
import {PluginEditComponent} from '../plugin-edit/plugin-edit.component';
import {NzTableQueryParams} from 'ng-zorro-antd';
import {Router} from "@angular/router";
import {TabRef} from "../tabs/tabs.component";
@Component({
selector: 'app-plugin',
templateUrl: './plugin.component.html',
styleUrls: ['./plugin.component.scss']
})
export class PluginComponent implements OnInit {
plugins: [];
total = 0;
pageIndex = 1;
pageSize = 10;
sortField = null;
sortOrder = null;
filters = [];
keyword = '';
loading = false;
statusFilters = [{text: '启动', value: 1}];
constructor(private as: ApiService, private router: Router, private tab: TabRef) {
tab.name = '插件管理';
}
ngOnInit(): void {
}
reload(): void {
this.pageIndex = 1;
this.keyword = '';
this.load();
}
load(): void {
this.loading = true;
this.as.post('plugins', {
offset: (this.pageIndex - 1) * this.pageSize,
length: this.pageSize,
sortKey: this.sortField,
sortOrder: this.sortOrder,
filters: this.filters,
keyword: this.keyword,
}).subscribe(res => {
this.plugins = res.data;
this.total = res.total;
}, error => {
console.log('error', error);
}, () => {
this.loading = false;
});
}
create(): void {
this.router.navigate(['/admin/plugin-create']);
}
edit(c): void {
this.router.navigate(['/admin/plugin-edit/' + c.id]);
}
onTableQuery(params: NzTableQueryParams): void {
const {pageSize, pageIndex, sort, filter} = params;
this.pageSize = pageSize;
this.pageIndex = pageIndex;
const currentSort = sort.find(item => item.value !== null);
this.sortField = (currentSort && currentSort.key) || null;
this.sortOrder = (currentSort && currentSort.value) || null;
this.filters = filter;
this.load();
}
search(): void {
this.pageIndex = 1;
this.load();
}
}
<p>TODO:项目基本信息</p>
<p>TODO:链接平铺,包含元件, </p>
<app-project-link [project]="project"></app-project-link>
<app-project-element [project]="project"></app-project-element>
<nz-tabset>
<nz-tab nzTitle="功能脚本">
<app-project-function [project]="project"></app-project-function>
</nz-tab>
<nz-tab nzTitle="定时任务">
<app-project-job [project]="project"></app-project-job>
</nz-tab>
<nz-tab nzTitle="自动策略">
<app-project-strategy [project]="project"></app-project-strategy>
</nz-tab>
</nz-tabset>
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
import {ApiService} from '../../api.service';
@Component({
selector: 'app-project-detail',
templateUrl: './project-detail.component.html',
styleUrls: ['./project-detail.component.scss']
})
export class ProjectDetailComponent implements OnInit {
project: any = {};
id = 0;
constructor(private as: ApiService, private routeInfo: ActivatedRoute, private tab: TabRef) {
this.id = routeInfo.snapshot.params.id;
tab.name = '项目详情';
}
ngOnInit(): void {
this.as.get('project/' + this.id).subscribe(res => {
if (res.ok) {
this.project = res.data;
this.tab.name = '项目【' + this.project.name + '';
}
// console.log(res);
});
}
}
<ngx-codemirror
[(ngModel)]="content"
[options]="{
lineNumbers: true,
theme: 'material',
mode: 'yaml'
}"
></ngx-codemirror>
<button nz-button nzType="primary" (click)="submit()">保存</button>
import {Component, Input, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {ActivatedRoute} from '@angular/router';
import {TabRef} from '../tabs/tabs.component';
import {NzMessageService, NzModalRef} from 'ng-zorro-antd';
@Component({
selector: 'app-project-edit',
templateUrl: './project-edit.component.html',
styleUrls: ['./project-edit.component.scss']
})
export class ProjectEditComponent implements OnInit {
target = 'project';
@Input() id = 0;
data: any = {};
content = "";
constructor(private as: ApiService, private mr: NzModalRef, private ms: NzMessageService) {
}
ngOnInit(): void {
if (this.id > 0) {
this.as.get(this.target + '/' + this.id).subscribe(res => {
this.data = res.data;
});
}
}
submit(): void {
let uri = this.target;
if (this.data.id) {
uri += '/' + this.data.id;
}
this.as.post(uri, this.data).subscribe(res => {
if (res.ok) {
this.ms.success('保存成功');
this.mr.close(res.data);
}
});
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-project-element-edit',
templateUrl: './project-element-edit.component.html',
styleUrls: ['./project-element-edit.component.scss']
})
export class ProjectElementEditComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<button nz-button (click)="create()">
<i nz-icon nzType="plus"></i>
创建
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="elements" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="ProjectId" [nzSortFn]="true">项目ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="Slave" [nzSortFn]="true">站号</th>
<th nzColumnKey="Alias" [nzSortFn]="true">别名</th>
<th nzColumnKey="Created" [nzSortFn]="true">创建时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data">
<td>{{ data.id }}</td>
<td>{{ data.project_id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.slave }}</td>
<td>{{ data.alias }}</td>
<td>{{ data.created | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a (click)="edit(data)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
import {Component, Input, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {NzTableQueryParams} from 'ng-zorro-antd';
import {Router} from '@angular/router';
@Component({
selector: 'app-project-element',
templateUrl: './project-element.component.html',
styleUrls: ['./project-element.component.scss']
})
export class ProjectElementComponent implements OnInit {
@Input() project: any = {};
inited = false;
tableQuery: any;
elements: [];
total = 0;
pageIndex = 1;
pageSize = 10;
sortField = null;
sortOrder = null;
filters = [];
keyword = '';
loading = false;
constructor(private as: ApiService, private router: Router) {
}
ngOnInit(): void {
this.inited = true;
if (this.tableQuery) {
this.onTableQuery(this.tableQuery)
}
}
reload(): void {
this.pageIndex = 1;
this.keyword = '';
this.load();
}
load(): void {
this.loading = true;
this.as.post('project/' + this.project.id + '/elements', {
offset: (this.pageIndex - 1) * this.pageSize,
length: this.pageSize,
sortKey: this.sortField,
sortOrder: this.sortOrder,
filters: this.filters,
keyword: this.keyword,
}).subscribe(res => {
this.elements = res.data;
this.total = res.total;
}, error => {
console.log('error', error);
}, () => {
this.loading = false;
});
}
create(): void {
this.router.navigate(['/admin/project/' + this.project.id + '/element/create']);
}
edit(c): void {
this.router.navigate(['/admin/project/' + this.project.id + '/element/' + c.id + '/edit']);
}
onTableQuery(params: NzTableQueryParams): void {
if (!this.inited) {
this.tableQuery = params;
return;
}
const {pageSize, pageIndex, sort, filter} = params;
this.pageSize = pageSize;
this.pageIndex = pageIndex;
const currentSort = sort.find(item => item.value !== null);
this.sortField = (currentSort && currentSort.key) || null;
this.sortOrder = (currentSort && currentSort.value) || null;
this.filters = filter;
this.load();
}
search(): void {
this.pageIndex = 1;
this.load();
}
}
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
名称
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.name" placeholder="名称"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
密钥
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.key" placeholder="密钥"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
密码
</div>
<div nz-col nzSpan="20">
<input nz-input [(ngModel)]="data.secret" placeholder="密码"/>
</div>
</div>
<div class="item" nz-row nzAlign="middle">
<div nz-col nzSpan="4">
禁用
</div>
<div nz-col nzSpan="20">
<nz-switch [(ngModel)]="data.disabled"></nz-switch>
</div>
</div>
<button nz-button nzType="primary" (click)="submit()">保存</button>
import {Component, Input, OnInit} from '@angular/core';
import {ApiService} from '../../api.service';
import {NzMessageService, NzModalRef} from 'ng-zorro-antd';
@Component({
selector: 'app-project-function-edit',
templateUrl: './project-function-edit.component.html',
styleUrls: ['./project-function-edit.component.scss']
})
export class ProjectFunctionEditComponent implements OnInit {
target = 'project/function';
@Input() id = 0;
data: any = {};
constructor(private as: ApiService, private mr: NzModalRef, private ms: NzMessageService) {
}
ngOnInit(): void {
if (this.id > 0) {
this.as.get(this.target + '/' + this.id).subscribe(res => {
this.data = res.data;
});
}
}
submit(): void {
let uri = this.target;
if (this.data.id) {
uri += '/' + this.data.id;
}
this.as.post(uri, this.data).subscribe(res => {
if (res.ok) {
this.ms.success('保存成功');
this.mr.close(res.data);
}
});
}
}
<nz-space>
<nz-space-item>
<button nz-button (click)="load()" [nzLoading]="loading">
<i nz-icon nzType="reload"></i>
刷新
</button>
</nz-space-item>
<nz-space-item>
<button nz-button (click)="edit()">
<i nz-icon nzType="plus"></i>
创建
</button>
</nz-space-item>
<nz-space-item>
<nz-input-group nzSearch nzCompact [nzAddOnAfter]="suffixButton">
<input type="text" nz-input [(ngModel)]="keyword" placeholder="名称、地址"/>
</nz-input-group>
<ng-template #suffixButton>
<button nz-button nzSearch (click)="search()">搜索</button>
</ng-template>
</nz-space-item>
</nz-space>
<nz-table #tbl [nzData]="datum" nzTableLayout="fixed" [nzFrontPagination]="false" [nzPageSize]="pageSize"
[nzPageIndex]="pageIndex" [nzTotal]="total" [nzLoading]="loading" (nzQueryParams)="onTableQuery($event)">
<thead>
<tr>
<th nzColumnKey="ID" [nzSortFn]="true">ID</th>
<th nzColumnKey="ProjectId" [nzSortFn]="true">项目ID</th>
<th nzColumnKey="Name" [nzSortFn]="true">名称</th>
<th nzColumnKey="Cron" [nzSortFn]="true">定时</th>
<th nzColumnKey="Script" [nzSortFn]="true">脚本</th>
<th nzColumnKey="Created" [nzSortFn]="true">创建时间</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of tbl.data">
<td>{{ data.id }}</td>
<td>{{ data.project_id }}</td>
<td>{{ data.name }}</td>
<td>{{ data.cron }}</td>
<td>{{ data.script }}</td>
<td>{{ data.created | amDateFormat:'YYYY-MM-DD HH:mm:ss' }}</td>
<td>
<a (click)="edit(data.id)" title="编辑">
<i nz-icon nzType="edit"></i>
</a>
</td>
</tr>
</tbody>
</nz-table>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册