Commit e954ad55 by 杨子

增加顶部导航栏

parent 23a71ccb
function fix(options) {
options.extraArgs = {
data: {
assets: '1111'
}
}
console.log(options);
return new Promise((resolve) => {
resolve();
});
}
module.exports = {
fix
};
...@@ -5116,8 +5116,7 @@ ...@@ -5116,8 +5116,7 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
...@@ -5138,14 +5137,12 @@ ...@@ -5138,14 +5137,12 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
...@@ -5160,20 +5157,17 @@ ...@@ -5160,20 +5157,17 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
...@@ -5290,8 +5284,7 @@ ...@@ -5290,8 +5284,7 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
...@@ -5303,7 +5296,6 @@ ...@@ -5303,7 +5296,6 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
...@@ -5318,7 +5310,6 @@ ...@@ -5318,7 +5310,6 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
...@@ -5326,14 +5317,12 @@ ...@@ -5326,14 +5317,12 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
...@@ -5352,7 +5341,6 @@ ...@@ -5352,7 +5341,6 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
...@@ -5433,8 +5421,7 @@ ...@@ -5433,8 +5421,7 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
...@@ -5446,7 +5433,6 @@ ...@@ -5446,7 +5433,6 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -5532,8 +5518,7 @@ ...@@ -5532,8 +5518,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
...@@ -5569,7 +5554,6 @@ ...@@ -5569,7 +5554,6 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
...@@ -5589,7 +5573,6 @@ ...@@ -5589,7 +5573,6 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
...@@ -5633,14 +5616,12 @@ ...@@ -5633,14 +5616,12 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
} }
} }
}, },
...@@ -8933,6 +8914,17 @@ ...@@ -8933,6 +8914,17 @@
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"ng-zorro-antd-mobile": {
"version": "0.11.9",
"resolved": "https://registry.npmjs.org/ng-zorro-antd-mobile/-/ng-zorro-antd-mobile-0.11.9.tgz",
"integrity": "sha512-QDD2WyWFFmV67gldkb17nPMy+kXLd2dZyYr66mz0NxwO/j+c6Na5GI09AEAYFMfG4UCOnR1RzATe73OmIfPDCw==",
"requires": {
"@angular/animations": "^7.1.0",
"@angular/cdk": "^7.2.0",
"@ant-design/icons-angular": "~2.0.1",
"tslib": "^1.9.0"
}
},
"ngx-countdown": { "ngx-countdown": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/ngx-countdown/-/ngx-countdown-3.2.0.tgz", "resolved": "https://registry.npmjs.org/ngx-countdown/-/ngx-countdown-3.2.0.tgz",
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
"core-js": "^2.5.4", "core-js": "^2.5.4",
"file-saver": "^2.0.0", "file-saver": "^2.0.0",
"ng-zorro-antd": "^7.2.0", "ng-zorro-antd": "^7.2.0",
"ng-zorro-antd-mobile": "^0.11.9",
"ngx-countdown": "^3.2.0", "ngx-countdown": "^3.2.0",
"ngx-tinymce": "^7.0.0", "ngx-tinymce": "^7.0.0",
"ngx-ueditor": "^2.1.3", "ngx-ueditor": "^2.1.3",
......
...@@ -114,8 +114,8 @@ export class DefaultInterceptor implements HttpInterceptor { ...@@ -114,8 +114,8 @@ export class DefaultInterceptor implements HttpInterceptor {
if (!url.startsWith('https://') && !url.startsWith('http://')) { if (!url.startsWith('https://') && !url.startsWith('http://')) {
url = environment.SERVER_URL + url; url = environment.SERVER_URL + url;
const api = /asset\/a\/[^(login)].*/g; const api = /asset\/a\/[^(login)].*/g;
if(api.test(url)){ if (api.test(url)) {
url += `;JSESSIONID=${this.tokenService.get().token}?_ajax=true&mobileLogin=true`; url += `JSESSIONID=${this.tokenService.get().token}?_ajax=true&mobileLogin=true`;
} }
} }
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AssetsComponent } from './assets.component';
describe('AssetsComponent', () => {
let component: AssetsComponent;
let fixture: ComponentFixture<AssetsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AssetsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AssetsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-assets',
templateUrl: './assets.component.html',
styleUrls: ['./assets.component.less']
})
export class AssetsComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
<div class="alain-default__progress-bar" *ngIf="isFetching"></div> <!-- <div class="alain-default__progress-bar" *ngIf="isFetching"></div>
<layout-header class="alain-default__header"></layout-header> <layout-header class="alain-default__header"></layout-header>
<layout-sidebar class="alain-default__aside"></layout-sidebar> <layout-sidebar class="alain-default__aside"></layout-sidebar>
<section class="alain-default__content"> <section class="alain-default__content">
<router-outlet></router-outlet> <router-outlet></router-outlet>
</section> </section>
<ng-template #settingHost></ng-template> <ng-template #settingHost></ng-template> -->
<app-tabbar></app-tabbar>
...@@ -19,13 +19,13 @@ import { updateHostClass } from '@delon/util'; ...@@ -19,13 +19,13 @@ import { updateHostClass } from '@delon/util';
import { SettingsService } from '@delon/theme'; import { SettingsService } from '@delon/theme';
import { environment } from '@env/environment'; import { environment } from '@env/environment';
import { SettingDrawerComponent } from './setting-drawer/setting-drawer.component'; // import { SettingDrawerComponent } from './setting-drawer/setting-drawer.component';
@Component({ @Component({
selector: 'layout-default', selector: 'app-default',
templateUrl: './default.component.html', templateUrl: './default.component.html',
}) })
export class LayoutDefaultComponent implements OnInit, AfterViewInit, OnDestroy { export class AppDefaultComponent implements OnInit, AfterViewInit, OnDestroy {
private unsubscribe$ = new Subject<void>(); private unsubscribe$ = new Subject<void>();
@ViewChild('settingHost', { read: ViewContainerRef }) @ViewChild('settingHost', { read: ViewContainerRef })
private settingHost: ViewContainerRef; private settingHost: ViewContainerRef;
......
import { Component, HostListener, ChangeDetectionStrategy } from '@angular/core';
import * as screenfull from 'screenfull';
@Component({
selector: 'header-fullscreen',
template: `
<i nz-icon [type]="status ? 'fullscreen-exit' : 'fullscreen'"></i>
{{ (status ? 'menu.fullscreen.exit' : 'menu.fullscreen') | translate }}
`,
host: {
'[class.d-block]': 'true',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderFullScreenComponent {
status = false;
private get sf(): screenfull.Screenfull {
return screenfull as screenfull.Screenfull;
}
@HostListener('window:resize')
_resize() {
this.status = this.sf.isFullscreen;
}
@HostListener('click')
_click() {
if (this.sf.enabled) {
this.sf.toggle();
}
}
}
import { Component, Inject, Input, ChangeDetectionStrategy } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { SettingsService, ALAIN_I18N_TOKEN } from '@delon/theme';
import { InputBoolean } from '@delon/util';
import { I18NService } from '@core';
@Component({
selector: 'header-i18n',
template: `
<nz-dropdown nzPlacement="bottomRight">
<div *ngIf="showLangText" nz-dropdown>
<i nz-icon type="global"></i>
{{ 'menu.lang' | translate }}
<i nz-icon type="down"></i>
</div>
<i *ngIf="!showLangText" nz-dropdown nz-icon type="global"></i>
<ul nz-menu>
<li
nz-menu-item
*ngFor="let item of langs"
[nzSelected]="item.code === curLangCode"
(click)="change(item.code)"
>
<span role="img" [attr.aria-label]="item.text" class="pr-xs">{{ item.abbr }}</span>
{{ item.text }}
</li>
</ul>
</nz-dropdown>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderI18nComponent {
/** Whether to display language text */
@Input() @InputBoolean() showLangText = true;
get langs() {
return this.i18n.getLangs();
}
get curLangCode() {
return this.settings.layout.lang;
}
constructor(
private settings: SettingsService,
@Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
@Inject(DOCUMENT) private doc: any,
) {}
change(lang: string) {
const spinEl = this.doc.createElement('div');
spinEl.setAttribute('class', `page-loading ant-spin ant-spin-lg ant-spin-spinning`);
spinEl.innerHTML = `<span class="ant-spin-dot ant-spin-dot-spin"><i></i><i></i><i></i><i></i></span>`;
this.doc.body.appendChild(spinEl);
this.i18n.use(lang);
this.settings.setLayout('lang', lang);
setTimeout(() => this.doc.location.reload());
}
}
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'header-icon',
template: `
<nz-dropdown nzTrigger="click" nzPlacement="bottomRight" (nzVisibleChange)="change()">
<div class="alain-default__nav-item" nz-dropdown>
<i class="anticon anticon-appstore"></i>
</div>
<div nz-menu class="wd-xl animated jello">
<nz-spin [nzSpinning]="loading" [nzTip]="'正在读取数据...'">
<div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="app-icons">
<div nz-col [nzSpan]="6">
<i class="anticon anticon-calendar bg-error text-white"></i>
<small>Calendar</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-file bg-geekblue text-white"></i>
<small>Files</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-cloud bg-success text-white"></i>
<small>Cloud</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-star-o bg-magenta text-white"></i>
<small>Star</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-team bg-purple text-white"></i>
<small>Team</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-scan bg-warning text-white"></i>
<small>QR</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-pay-circle-o bg-cyan text-white"></i>
<small>Pay</small>
</div>
<div nz-col [nzSpan]="6">
<i class="anticon anticon-printer bg-grey text-white"></i>
<small>Print</small>
</div>
</div>
</nz-spin>
</div>
</nz-dropdown>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderIconComponent {
loading = true;
constructor(private cdr: ChangeDetectorRef) {}
change() {
setTimeout(() => {
this.loading = false;
this.cdr.detectChanges();
}, 500);
}
}
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import * as distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
import { NzMessageService } from 'ng-zorro-antd';
import { NoticeItem, NoticeIconList } from '@delon/abc';
/**
* 菜单通知
*/
@Component({
selector: 'header-notify',
template: `
<notice-icon
[data]="data"
[count]="count"
[loading]="loading"
btnClass="alain-default__nav-item"
btnIconClass="alain-default__nav-item-icon"
(select)="select($event)"
(clear)="clear($event)"
(popoverVisibleChange)="loadData()"
></notice-icon>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderNotifyComponent {
data: NoticeItem[] = [
{
title: '通知',
list: [],
emptyText: '你已查看所有通知',
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
clearText: '清空通知',
},
{
title: '消息',
list: [],
emptyText: '您已读完所有消息',
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg',
clearText: '清空消息',
},
{
title: '待办',
list: [],
emptyText: '你已完成所有待办',
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg',
clearText: '清空待办',
},
];
count = 5;
loading = false;
constructor(private msg: NzMessageService, private cdr: ChangeDetectorRef) {}
private updateNoticeData(notices: NoticeIconList[]): NoticeItem[] {
const data = this.data.slice();
data.forEach(i => (i.list = []));
notices.forEach(item => {
const newItem = { ...item };
if (newItem.datetime)
newItem.datetime = distanceInWordsToNow(item.datetime!, {
locale: (window as any).__locale__,
});
if (newItem.extra && newItem.status) {
newItem.color = {
todo: undefined,
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newItem.status];
}
data.find(w => w.title === newItem.type)!.list.push(newItem);
});
return data;
}
loadData() {
if (this.loading) return;
this.loading = true;
setTimeout(() => {
this.data = this.updateNoticeData([
{
id: '000000001',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: '你收到了 14 份新周报',
datetime: '2017-08-09',
type: '通知',
},
{
id: '000000002',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
title: '你推荐的 曲妮妮 已通过第三轮面试',
datetime: '2017-08-08',
type: '通知',
},
{
id: '000000003',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
title: '这种模板可以区分多种通知类型',
datetime: '2017-08-07',
read: true,
type: '通知',
},
{
id: '000000004',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
datetime: '2017-08-07',
type: '通知',
},
{
id: '000000005',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: '内容不要超过两行字,超出时自动截断',
datetime: '2017-08-07',
type: '通知',
},
{
id: '000000006',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '曲丽丽 评论了你',
description: '描述信息描述信息描述信息',
datetime: '2017-08-07',
type: '消息',
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '朱偏右 回复了你',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: '消息',
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '标题',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: '消息',
},
{
id: '000000009',
title: '任务名称',
description: '任务需要在 2017-01-12 20:00 前启动',
extra: '未开始',
status: 'todo',
type: '待办',
},
{
id: '000000010',
title: '第三方紧急代码变更',
description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
extra: '马上到期',
status: 'urgent',
type: '待办',
},
{
id: '000000011',
title: '信息安全考试',
description: '指派竹尔于 2017-01-09 前完成更新并发布',
extra: '已耗时 8 天',
status: 'doing',
type: '待办',
},
{
id: '000000012',
title: 'ABCD 版本发布',
description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
extra: '进行中',
status: 'processing',
type: '待办',
},
]);
this.loading = false;
this.cdr.detectChanges();
}, 1000);
}
clear(type: string) {
this.msg.success(`清空了 ${type}`);
}
select(res: any) {
this.msg.success(`点击了 ${res.title}${res.item.title}`);
}
}
import { Component, HostBinding, Input, ElementRef, AfterViewInit, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'header-search',
template: `
<nz-input-group [nzAddOnBeforeIcon]="focus ? 'anticon anticon-arrow-down' : 'anticon anticon-search'">
<input
nz-input
[(ngModel)]="q"
(focus)="qFocus()"
(blur)="qBlur()"
[placeholder]="'menu.search.placeholder' | translate"
/>
</nz-input-group>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderSearchComponent implements AfterViewInit {
q: string;
qIpt: HTMLInputElement;
@HostBinding('class.alain-default__search-focus')
focus = false;
@HostBinding('class.alain-default__search-toggled')
searchToggled = false;
@Input()
set toggleChange(value: boolean) {
if (typeof value === 'undefined') return;
this.searchToggled = true;
this.focus = true;
setTimeout(() => this.qIpt.focus(), 300);
}
constructor(private el: ElementRef) {}
ngAfterViewInit() {
this.qIpt = (this.el.nativeElement as HTMLElement).querySelector('.ant-input') as HTMLInputElement;
}
qFocus() {
this.focus = true;
}
qBlur() {
this.focus = false;
this.searchToggled = false;
}
}
import { Component, HostListener, ChangeDetectionStrategy } from '@angular/core';
import { NzModalService, NzMessageService } from 'ng-zorro-antd';
@Component({
selector: 'header-storage',
template: `
<i nz-icon type="tool"></i>
{{ 'menu.clear.local.storage' | translate }}
`,
host: {
'[class.d-block]': 'true',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderStorageComponent {
constructor(private modalSrv: NzModalService, private messageSrv: NzMessageService) {}
@HostListener('click')
_click() {
this.modalSrv.confirm({
nzTitle: 'Make sure clear all local storage?',
nzOnOk: () => {
localStorage.clear();
this.messageSrv.success('Clear Finished!');
},
});
}
}
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'header-task',
template: `
<nz-dropdown nzTrigger="click" nzPlacement="bottomRight" (nzVisibleChange)="change()">
<div class="alain-default__nav-item" nz-dropdown>
<nz-badge [nzDot]="true">
<i nz-icon type="bell" class="alain-default__nav-item-icon"></i>
</nz-badge>
</div>
<div nz-menu class="wd-lg">
<div *ngIf="loading" class="mx-lg p-lg"><nz-spin></nz-spin></div>
<nz-card *ngIf="!loading" nzTitle="Notifications" nzBordered="false" class="ant-card__body-nopadding">
<ng-template #extra><i nz-icon type="plus"></i></ng-template>
<div
nz-row
[nzType]="'flex'"
[nzJustify]="'center'"
[nzAlign]="'middle'"
class="py-sm bg-grey-lighter-h point"
>
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/1.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>cipchk</strong>
<p class="mb0">Please tell me what happened in a few words, don't go into details.</p>
</div>
</div>
<div
nz-row
[nzType]="'flex'"
[nzJustify]="'center'"
[nzAlign]="'middle'"
class="py-sm bg-grey-lighter-h point"
>
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/2.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>はなさき</strong>
<p class="mb0">ハルカソラトキヘダツヒカリ</p>
</div>
</div>
<div
nz-row
[nzType]="'flex'"
[nzJustify]="'center'"
[nzAlign]="'middle'"
class="py-sm bg-grey-lighter-h point"
>
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/3.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>苏先生</strong>
<p class="mb0">请告诉我,我应该说点什么好?</p>
</div>
</div>
<div
nz-row
[nzType]="'flex'"
[nzJustify]="'center'"
[nzAlign]="'middle'"
class="py-sm bg-grey-lighter-h point"
>
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/4.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>Kent</strong>
<p class="mb0">Please tell me what happened in a few words, don't go into details.</p>
</div>
</div>
<div
nz-row
[nzType]="'flex'"
[nzJustify]="'center'"
[nzAlign]="'middle'"
class="py-sm bg-grey-lighter-h point"
>
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/5.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>Jefferson</strong>
<p class="mb0">Please tell me what happened in a few words, don't go into details.</p>
</div>
</div>
<div nz-row>
<div nz-col [nzSpan]="24" class="pt-md border-top-1 text-center text-grey point">
See All
</div>
</div>
</nz-card>
</div>
</nz-dropdown>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderTaskComponent {
loading = true;
constructor(private cdr: ChangeDetectorRef) {}
change() {
setTimeout(() => {
this.loading = false;
this.cdr.detectChanges();
}, 500);
}
}
import { Component, Inject, ChangeDetectionStrategy } from '@angular/core';
import { Router } from '@angular/router';
import { SettingsService } from '@delon/theme';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
@Component({
selector: 'header-user',
template: `
<nz-dropdown nzPlacement="bottomRight">
<div class="alain-default__nav-item d-flex align-items-center px-sm" nz-dropdown>
<nz-avatar [nzSrc]="settings.user.avatar" nzSize="small" class="mr-sm"></nz-avatar>
{{ settings.user.name }}
</div>
<div nz-menu class="width-sm">
<div nz-menu-item routerLink="/pro/account/center">
<i nz-icon type="user" class="mr-sm"></i>
{{ 'menu.account.center' | translate }}
</div>
<div nz-menu-item routerLink="/pro/account/settings">
<i nz-icon type="setting" class="mr-sm"></i>
{{ 'menu.account.settings' | translate }}
</div>
<div nz-menu-item routerLink="/exception/trigger">
<i nz-icon type="close-circle" class="mr-sm"></i>
{{ 'menu.account.trigger' | translate }}
</div>
<li nz-menu-divider></li>
<div nz-menu-item (click)="logout()">
<i nz-icon type="logout" class="mr-sm"></i>
{{ 'menu.account.logout' | translate }}
</div>
</div>
</nz-dropdown>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderUserComponent {
constructor(
public settings: SettingsService,
private router: Router,
@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
) {}
logout() {
this.tokenService.clear();
this.router.navigateByUrl(this.tokenService.login_url!);
}
}
<div class="alain-default__header-logo">
<a [routerLink]="['/']" class="alain-default__header-logo-link">
<img class="alain-default__header-logo-expanded" src="./assets/logo-full.svg" alt="{{settings.app.name}}" style="max-height:40px;" />
<img class="alain-default__header-logo-collapsed" src="./assets/luqiao.jpg" alt="{{settings.app.name}}" style="max-height:30px;border-radius:13px;" />
</a>
</div>
<div class="alain-default__nav-wrap">
<ul class="alain-default__nav">
<!-- Menu -->
<li>
<div class="alain-default__nav-item" (click)="toggleCollapsedSidebar()">
<i nz-icon type="menu-{{settings.layout.collapsed ? 'unfold' : 'fold'}}"></i>
</div>
</li>
<!-- Lock Page -->
<li class="hidden-mobile">
<div class="alain-default__nav-item" routerLink="/passport/lock">
<i nz-icon type="lock"></i>
</div>
</li>
<!-- Search Button -->
<!-- <li class="hidden-pc" (click)="searchToggleChange()">
<div class="alain-default__nav-item">
<i nz-icon type="search"></i>
</div>
</li> -->
</ul>
<!-- <header-search class="alain-default__search" [toggleChange]="searchToggleStatus"></header-search> -->
<ul class="alain-default__nav">
<!-- Notify -->
<!-- <li>
<header-notify></header-notify>
</li> -->
<!-- Task -->
<li class="hidden-mobile">
<header-task></header-task>
</li>
<!-- App Icons -->
<li class="hidden-mobile">
<header-icon></header-icon>
</li>
<!-- Settings -->
<li class="hidden-mobile">
<nz-dropdown nzTrigger="click" nzPlacement="bottomRight">
<div class="alain-default__nav-item" nz-dropdown>
<i nz-icon type="setting"></i>
</div>
<div nz-menu style="width:200px;">
<div nz-menu-item>
<header-fullscreen></header-fullscreen>
</div>
<div nz-menu-item>
<header-storage></header-storage>
</div>
<div nz-menu-item>
<header-i18n></header-i18n>
</div>
</div>
</nz-dropdown>
</li>
<li class="hidden-mobile">
<header-user></header-user>
</li>
</ul>
</div>
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { SettingsService } from '@delon/theme';
@Component({
selector: 'layout-header',
templateUrl: './header.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderComponent {
searchToggleStatus: boolean;
constructor(public settings: SettingsService) {}
toggleCollapsedSidebar() {
this.settings.setLayout('collapsed', !this.settings.layout.collapsed);
}
searchToggleChange() {
this.searchToggleStatus = !this.searchToggleStatus;
}
}
---
component: app-header
title: 顶部菜单
---
顶部菜单组件允许通过 `components` 目录下的组件进行按需组装。
## 组件列表
组件名 | 说明
----|------
`header-fullscreen` | 全屏切换
`header-icon` | 应用图标
`header-langs` | 语言切换
`header-notify` | 菜单通知
`header-search` | 搜索框
`header-storage` | 清除 LocalStorage 缓存
`header-task` | 任务通知
`header-theme` | 主题切换
`header-user` | 用户菜单
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InventoryComponent } from './inventory.component';
describe('InventoryComponent', () => {
let component: InventoryComponent;
let fixture: ComponentFixture<InventoryComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ InventoryComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InventoryComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-inventory',
templateUrl: './inventory.component.html',
styleUrls: ['./inventory.component.less']
})
export class InventoryComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
<Navbar>
信息中心
</Navbar>
<div class="title">事务管理中心</div>
<Grid [activeStyle]="false" [data]="data" (OnClick)="click($event)"></Grid>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MessageComponent } from './message.component';
describe('MessageComponent', () => {
let component: MessageComponent;
let fixture: ComponentFixture<MessageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MessageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-message',
templateUrl: './message.component.html',
styleUrls: ['./message.component.less'],
})
export class MessageComponent implements OnInit {
data = Array.from(new Array(9)).map((_val, i) => ({
icon: '/assets/img/logo.svg',
text: `name${i}`,
}));
constructor() {}
ngOnInit() {}
click(event) {
console.log(event);
}
}
<span>{{i.label}}<span class="pl-sm text-grey">{{i.tip}}</span></span>
<div [ngSwitch]="i.type">
<ng-container *ngSwitchCase="'color'">
<input nz-input type="color" style="min-width: 88px" [(ngModel)]="i.value" [ngModelOptions]="{standalone: true}">
</ng-container>
<ng-container *ngSwitchCase="'input'">
<input nz-input style="min-width: 88px" [(ngModel)]="i.value" [ngModelOptions]="{standalone: true}">
</ng-container>
<ng-container *ngSwitchCase="'px'">
<nz-input-number [(ngModel)]="pxVal" (ngModelChange)="pxChange($event)" [nzMin]="i.min" [nzMax]="i.max"
[nzStep]="i.step || 2" [nzFormatter]="format"></nz-input-number>
</ng-container>
<ng-container *ngSwitchCase="'switch'">
<nz-switch nzSize="small" [(ngModel)]="i.value" [ngModelOptions]="{standalone: true}"></nz-switch>
</ng-container>
<ng-container *ngSwitchDefault>
<ng-content></ng-content>
</ng-container>
</div>
import { Component, Input } from '@angular/core';
@Component({
// tslint:disable-next-line:component-selector
selector: 'setting-drawer-item',
templateUrl: './setting-drawer-item.component.html',
host: {
'[class.setting-drawer__body-item]': 'true',
},
})
export class SettingDrawerItemComponent {
i: any = {};
@Input()
set data(val: any) {
this.i = val;
if (val.type === 'px') {
this.pxVal = +val.value.replace('px', '');
}
}
pxVal: number;
pxChange(val: number) {
this.i.value = `${val}px`;
}
format = value => `${value} px`;
}
<nz-drawer [(nzVisible)]="collapse" [nzWidth]="500" (nzOnClose)="toggle()">
<div class="setting-drawer__content">
<div class="setting-drawer__body setting-drawer__theme">
<h3 class="setting-drawer__title">主题色</h3>
<span *ngFor="let c of colors" nz-tooltip [ngStyle]="{ 'background-color': c.color }" (click)="changeColor(c.color)"
nz-tooltip [nzTitle]="c.key" class="setting-drawer__theme-tag"><i *ngIf="color === c.color"
class="anticon anticon-check"></i></span>
</div>
<nz-divider></nz-divider>
<div class="setting-drawer__body">
<h3 class="setting-drawer__title">设置</h3>
<nz-tabset>
<nz-tab nzTitle="顶部">
<div class="setting-drawer__body">
<setting-drawer-item [data]="data['alain-default-header-hg']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-header-bg']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-header-padding']"></setting-drawer-item>
</div>
</nz-tab>
<nz-tab nzTitle="侧边栏">
<setting-drawer-item [data]="data['alain-default-aside-wd']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-aside-bg']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-aside-collapsed-wd']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-aside-nav-padding-top-bottom']"></setting-drawer-item>
</nz-tab>
<nz-tab nzTitle="内容">
<setting-drawer-item [data]="data['alain-default-content-bg']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-content-heading-bg']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-content-heading-border']"></setting-drawer-item>
<setting-drawer-item [data]="data['alain-default-content-padding']"></setting-drawer-item>
</nz-tab>
<nz-tab nzTitle="其它">
<setting-drawer-item [data]="data['form-state-visual-feedback-enabled']"></setting-drawer-item>
<setting-drawer-item [data]="data['preserve-white-spaces-enabled']"></setting-drawer-item>
<setting-drawer-item [data]="data['nz-table-img-radius']"></setting-drawer-item>
<setting-drawer-item [data]="data['nz-table-img-margin-right']"></setting-drawer-item>
<setting-drawer-item [data]="data['nz-table-img-max-width']"></setting-drawer-item>
<setting-drawer-item [data]="data['nz-table-img-max-height']"></setting-drawer-item>
</nz-tab>
</nz-tabset>
</div>
<nz-divider></nz-divider>
<div class="setting-drawer__body">
<div class="setting-drawer__body-item">
固定头和侧边栏
<nz-switch nzSize="small" [(ngModel)]="layout.fixed" (ngModelChange)="setLayout('fixed', layout.fixed)"></nz-switch>
</div>
<div class="setting-drawer__body-item">
色弱模式
<nz-switch nzSize="small" [(ngModel)]="layout.colorWeak" (ngModelChange)="setLayout('colorWeak', layout.colorWeak)"></nz-switch>
</div>
</div>
<nz-divider></nz-divider>
<button (click)="apply()" type="button" nz-button nzType="primary">预览</button>
<button (click)="reset()" type="button" nz-button>重置</button>
<button (click)="copyVar()" type="button" nz-button>拷贝</button>
<nz-alert class="mt-md" nzType="warning" nzMessage="配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改参数配置文件 src/styles/theme.less"></nz-alert>
</div>
</nz-drawer>
<div class="setting-drawer__handle" [ngClass]="{'setting-drawer__handle-opened': collapse}" (click)="toggle()">
<i nz-icon [type]="!collapse ? 'setting' : 'close'" class="setting-drawer__handle-icon"></i>
</div>
import { Component, ChangeDetectionStrategy, NgZone, Inject, ChangeDetectorRef } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NzMessageService } from 'ng-zorro-antd';
import { LazyService, copy, deepCopy } from '@delon/util';
import { SettingsService } from '@delon/theme';
const ALAINDEFAULTVAR = 'alain-default-vars';
const DEFAULT_COLORS = [
{
key: 'dust',
color: '#F5222D',
},
{
key: 'volcano',
color: '#FA541C',
},
{
key: 'sunset',
color: '#FAAD14',
},
{
key: 'cyan',
color: '#13C2C2',
},
{
key: 'green',
color: '#52C41A',
},
{
key: 'daybreak',
color: '#1890ff',
},
{
key: 'geekblue',
color: '#2F54EB',
},
{
key: 'purple',
color: '#722ED1',
},
];
const DEFAULT_VARS = {
'primary-color': { label: '主颜色', type: 'color', default: '#1890ff' },
'alain-default-header-hg': {
label: '高',
type: 'px',
default: '64px',
max: 300,
min: 24,
},
'alain-default-header-bg': {
label: '背景色',
type: 'color',
default: '@primary-color',
tip: '默认同主色系',
},
'alain-default-header-padding': {
label: '顶部左右内边距',
type: 'px',
default: '16px',
},
// 侧边栏
'alain-default-aside-wd': { label: '宽度', type: 'px', default: '200px' },
'alain-default-aside-bg': {
label: '背景',
type: 'color',
default: '#ffffff',
},
'alain-default-aside-collapsed-wd': {
label: '收缩宽度',
type: 'px',
default: '64px',
},
'alain-default-aside-nav-padding-top-bottom': {
label: '项上下内边距',
type: 'px',
default: '8px',
step: 8,
},
// 主菜单
'alain-default-aside-nav-fs': {
label: '菜单字号',
type: 'px',
default: '14px',
min: 14,
max: 30,
},
'alain-default-aside-collapsed-nav-fs': {
label: '收缩菜单字号',
type: 'px',
default: '24px',
min: 24,
max: 32,
},
'alain-default-aside-nav-item-height': {
label: '菜单项高度',
type: 'px',
default: '38px',
min: 24,
max: 64,
},
'alain-default-aside-nav-text-color': {
label: '菜单文本颜色',
type: 'color',
default: 'rgba(0, 0, 0, 0.65)',
rgba: true,
},
'alain-default-aside-nav-text-hover-color': {
label: '菜单文本悬停颜色',
type: 'color',
default: '@primary-color',
tip: '默认同主色系',
},
'alain-default-aside-nav-group-text-color': {
label: '菜单分组文本颜色',
type: 'color',
default: 'rgba(0, 0, 0, 0.43)',
rgba: true,
},
'alain-default-aside-nav-selected-text-color': {
label: '菜单激活时文本颜色',
type: 'color',
default: '@primary-color',
tip: '默认同主色系',
},
'alain-default-aside-nav-selected-bg': {
label: '菜单激活时背景颜色',
type: 'color',
default: '#fcfcfc',
},
// 内容
'alain-default-content-bg': {
label: '背景色',
type: 'color',
default: '#f5f7fa',
},
'alain-default-content-heading-bg': {
label: '标题背景色',
type: 'color',
default: '#fafbfc',
},
'alain-default-content-heading-border': {
label: '标题底部边框色',
type: 'color',
default: '#efe3e5',
},
'alain-default-content-padding': {
label: '内边距',
type: 'px',
default: '24px',
min: 0,
max: 128,
step: 8,
},
// zorro组件修正
'form-state-visual-feedback-enabled': {
label: '开启表单元素的视觉反馈',
type: 'switch',
default: true,
},
'preserve-white-spaces-enabled': {
label: '开启 preserveWhitespaces',
type: 'switch',
default: true,
},
'nz-table-img-radius': {
label: '表格中:图片圆角',
type: 'px',
default: '4px',
min: 0,
max: 128,
},
'nz-table-img-margin-right': {
label: '表格中:图片右外边距',
type: 'px',
default: '4px',
min: 0,
max: 128,
},
'nz-table-img-max-width': {
label: '表格中:图片最大宽度',
type: 'px',
default: '32px',
min: 8,
max: 128,
},
'nz-table-img-max-height': {
label: '表格中:图片最大高度',
type: 'px',
default: '32px',
min: 8,
max: 128,
},
};
@Component({
// tslint:disable-next-line:component-selector
selector: 'setting-drawer',
templateUrl: './setting-drawer.component.html',
host: {
'[class.setting-drawer]': 'true',
},
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SettingDrawerComponent {
private loadedLess = false;
collapse = false;
get layout() {
return this.settingSrv.layout;
}
data: any = {};
color: string;
colors = DEFAULT_COLORS;
constructor(
private cdr: ChangeDetectorRef,
private msg: NzMessageService,
private settingSrv: SettingsService,
private lazy: LazyService,
private zone: NgZone,
@Inject(DOCUMENT) private doc: any,
) {
this.color = this.cachedData['@primary-color'] || this.DEFAULT_PRIMARY;
this.resetData(this.cachedData, false);
}
private get cachedData() {
return this.settingSrv.layout[ALAINDEFAULTVAR] || {};
}
private get DEFAULT_PRIMARY() {
return DEFAULT_VARS['primary-color'].default;
}
private loadLess(): Promise<void> {
if (this.loadedLess) return Promise.resolve();
return this.lazy
.loadStyle('./assets/alain-default.less', 'stylesheet/less')
.then(() => {
const lessConfigNode = this.doc.createElement('script');
lessConfigNode.innerHTML = `
window.less = {
async: true,
env: 'production',
javascriptEnabled: true
};
`;
this.doc.body.appendChild(lessConfigNode);
})
.then(() => this.lazy.loadScript('https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js'))
.then(() => {
this.loadedLess = true;
});
}
private genVars() {
const { data, color, validKeys } = this;
const vars: any = {
[`@primary-color`]: color,
};
validKeys.filter(key => key !== 'primary-color').forEach(key => (vars[`@${key}`] = data[key].value));
this.setLayout(ALAINDEFAULTVAR, vars);
return vars;
}
private runLess() {
const { zone, msg, cdr } = this;
const msgId = msg.loading(`正在编译主题!`, { nzDuration: 0 }).messageId;
setTimeout(() => {
zone.runOutsideAngular(() => {
this.loadLess().then(() => {
(window as any).less.modifyVars(this.genVars()).then(() => {
msg.success('成功');
msg.remove(msgId);
zone.run(() => cdr.detectChanges());
});
});
});
}, 200);
}
toggle() {
this.collapse = !this.collapse;
}
changeColor(color: string) {
this.color = color;
Object.keys(DEFAULT_VARS)
.filter(key => DEFAULT_VARS[key].default === '@primary-color')
.forEach(key => delete this.cachedData[`@${key}`]);
this.resetData(this.cachedData, false);
}
setLayout(name: string, value: any) {
this.settingSrv.setLayout(name, value);
}
private resetData(nowData?: Object, run = true) {
nowData = nowData || {};
const data = deepCopy(DEFAULT_VARS);
Object.keys(data).forEach(key => {
const value = nowData![`@${key}`] || data[key].default || '';
data[key].value = value === `@primary-color` ? this.color : value;
});
this.data = data;
if (run) {
this.cdr.detectChanges();
this.runLess();
}
}
private get validKeys(): string[] {
return Object.keys(this.data).filter(key => this.data[key].value !== this.data[key].default);
}
apply() {
this.runLess();
}
reset() {
this.color = this.DEFAULT_PRIMARY;
this.settingSrv.setLayout(ALAINDEFAULTVAR, {});
this.resetData({});
}
copyVar() {
const vars = this.genVars();
const copyContent = Object.keys(vars)
.map(key => `${key}: ${vars[key]};`)
.join('\n');
copy(copyContent);
this.msg.success('Copy success');
}
}
<div class="alain-default__aside-inner">
<nz-dropdown nzTrigger="click" class="alain-default__aside-user">
<div nz-dropdown class="user-block-dropdown">
<nz-avatar class="alain-default__aside-user-avatar" [nzSrc]="settings.user.avatar"></nz-avatar>
<div class="alain-default__aside-user-info">
<strong>{{settings.user.name}}</strong>
<p class="text-truncate mb0">{{settings.user.email}}</p>
</div>
</div>
<ul nz-menu>
<li nz-menu-item routerLink="/pro/account/center">{{ 'menu.account.center' | translate }}</li>
<li nz-menu-item routerLink="/pro/account/settings">{{ 'menu.account.settings' | translate }}</li>
</ul>
</nz-dropdown>
<sidebar-nav class="d-block py-lg"></sidebar-nav>
</div>
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { SettingsService } from '@delon/theme';
@Component({
selector: 'layout-sidebar',
templateUrl: './sidebar.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SidebarComponent {
constructor(public settings: SettingsService) {}
}
<TabBar [barTintColor]="'white'" [tintColor]="tintColor" [unselectedTintColor]="unselectedTintColor"
[activeTab]="selectedIndex" [hidden]="hidden" [tabBarPosition]="topFlag ? 'top' : 'bottom'">
<TabPane style="background-color: white; text-align: center; height: 100%" [title]='custom1'>
<ng-template #custom1>
<TabBarTab [title]="'信息中心'" [key]="1" [badge]="1" [icon]="icon1" (onPress)="onPress($event)"
[selectedIcon]="icon11">
<ng-template #icon1>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/sifuoDUQdAFKAVcFGROC.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
<ng-template #icon11>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/iSrlOTqrKddqbOmlvUfq.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
</TabBarTab>
</ng-template>
<app-message></app-message>
<!-- <div style="background-color: white; height: 100%; text-align: center">
<div style="padding-top: 60px">Clicked Life tab, show Life information</div>
<ng-container>
<ng-template [ngTemplateOutlet]="content"></ng-template>
</ng-container>
</div> -->
</TabPane>
<TabPane style="background-color: white; text-align: center; height: 100%" [title]='custom2'>
<ng-template #custom2>
<TabBarTab [title]="'盘点'" [key]="2" [badge]="'new'" [icon]="icon2" [selectedIcon]="icon22">
<ng-template #icon2>
<div
style="width:22px;height: 22px;background: url('https://gw.alipayobjects.com/zos/rmsportal/BTSsmHkPsQSPTktcXyTV.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
<ng-template #icon22>
<div
style="width:22px;height: 22px;background: url('https://gw.alipayobjects.com/zos/rmsportal/ekLecvKBnRazVLXbWOnE.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
</TabBarTab>
</ng-template>
<app-inventory></app-inventory>
<!-- <div style="background-color: white; height: 100%; text-align: center">
<div style="padding-top: 60px">Clicked Koubei tab, show Koubei information</div>
<ng-container>
<ng-template [ngTemplateOutlet]="content"></ng-template>
</ng-container>
</div> -->
</TabPane>
<TabPane style="background-color: white; text-align: center; height: 100%" [title]='custom3'>
<ng-template #custom3>
<TabBarTab [title]="'资产管理'" [key]="3" [badge]="'new'" [icon]="icon3" [selectedIcon]="icon33">
<ng-template #icon3>
<div
style="width:22px;height: 22px;background: url('https://gw.alipayobjects.com/zos/rmsportal/BTSsmHkPsQSPTktcXyTV.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
<ng-template #icon33>
<div
style="width:22px;height: 22px;background: url('https://gw.alipayobjects.com/zos/rmsportal/ekLecvKBnRazVLXbWOnE.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
</TabBarTab>
</ng-template>
<app-assets></app-assets>
<!-- <div style="background-color: white; height: 100%; text-align: center">
<div style="padding-top: 60px">Clicked Koubei tab, show Koubei information</div>
<ng-container>
<ng-template [ngTemplateOutlet]="content"></ng-template>
</ng-container>
</div> -->
</TabPane>
<TabPane style="background-color: white; text-align: center; height: 100%" [title]='custom4'>
<ng-template #custom4>
<TabBarTab [title]="'统计'" [key]="4" [dot]="true" [icon]="icon4" [selectedIcon]="icon44">
<ng-template #icon4>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/psUFoAMjkCcjqtUCNPxB.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
<ng-template #icon44>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/IIRLrXXrFAhXVdhMWgUI.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
</TabBarTab>
</ng-template>
<app-total></app-total>
<!-- <div style="background-color: white; height: 100%; text-align: center">
<div style="padding-top: 60px">Clicked Friend tab, show Friend information</div>
<ng-container>
<ng-template [ngTemplateOutlet]="content"></ng-template>
</ng-container>
</div> -->
</TabPane>
<TabPane style="background-color: white; text-align: center; height: 100%" [title]='custom5'>
<ng-template #custom5>
<TabBarTab [title]="'我的'" [key]="5" [icon]="icon5" [selectedIcon]="icon55">
<ng-template #icon5>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/asJMfBrNqpMMlVpeInPQ.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
<ng-template #icon55>
<div
style="width:22px;height: 22px;background: url('https://zos.alipayobjects.com/rmsportal/gjpzzcrPMkhfEqgbYvmN.svg') center center / 21px 21px no-repeat;">
</div>
</ng-template>
</TabBarTab>
</ng-template>
<app-user></app-user>
<!-- <div style="background-color: white; height: 100%; text-align: center">
<div style="padding-top: 60px">Clicked My tab, show My information</div>
<ng-container>
<ng-template [ngTemplateOutlet]="content"></ng-template>
</ng-container>
</div> -->
</TabPane>
</TabBar>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TabbarComponent } from './tabbar.component';
describe('TabbarComponent', () => {
let component: TabbarComponent;
let fixture: ComponentFixture<TabbarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TabbarComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TabbarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-tabbar',
templateUrl: './tabbar.component.html',
styleUrls: ['./tabbar.component.less'],
})
export class TabbarComponent implements OnInit {
hidden: boolean = false;
fullScreen: boolean = false;
topFlag: boolean = false;
tintColor: string = '#108ee9';
unselectedTintColor: string = '#888';
selectedIndex: number = 1;
constructor() {}
ngOnInit() {}
showTabBar(event) {
event.preventDefault();
this.hidden = !this.hidden;
}
showNextTabBar(event) {
event.preventDefault();
const PANE_COUNT = 4;
if (this.selectedIndex == PANE_COUNT - 1) {
this.selectedIndex = 0;
} else {
this.selectedIndex++;
}
}
showFullScreen(event) {
event.preventDefault();
this.fullScreen = !this.fullScreen;
}
changePosition(event) {
event.preventDefault();
this.topFlag = !this.topFlag;
}
onPress(event) {
console.log('event: ', event);
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TotalComponent } from './total.component';
describe('TotalComponent', () => {
let component: TotalComponent;
let fixture: ComponentFixture<TotalComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TotalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TotalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-total',
templateUrl: './total.component.html',
styleUrls: ['./total.component.less']
})
export class TotalComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { UserComponent } from './user.component';
describe('UserComponent', () => {
let component: UserComponent;
let fixture: ComponentFixture<UserComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ UserComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(UserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.less']
})
export class UserComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { SharedModule } from '@shared'; import { SharedModule } from '@shared';
import { LayoutDefaultComponent } from './default/default.component'; import { AppDefaultComponent } from './default/default.component';
import { LayoutFullScreenComponent } from './fullscreen/fullscreen.component'; import { LayoutFullScreenComponent } from './fullscreen/fullscreen.component';
import { HeaderComponent } from './default/header/header.component';
import { SidebarComponent } from './default/sidebar/sidebar.component';
import { HeaderSearchComponent } from './default/header/components/search.component';
import { HeaderNotifyComponent } from './default/header/components/notify.component';
import { HeaderTaskComponent } from './default/header/components/task.component';
import { HeaderIconComponent } from './default/header/components/icon.component';
import { HeaderFullScreenComponent } from './default/header/components/fullscreen.component';
import { HeaderI18nComponent } from './default/header/components/i18n.component';
import { HeaderStorageComponent } from './default/header/components/storage.component';
import { HeaderUserComponent } from './default/header/components/user.component';
import { SettingDrawerComponent } from './default/setting-drawer/setting-drawer.component'; const COMPONENTS = [AppDefaultComponent, LayoutFullScreenComponent, TabbarComponent];
import { SettingDrawerItemComponent } from './default/setting-drawer/setting-drawer-item.component';
const SETTINGDRAWER = [SettingDrawerComponent, SettingDrawerItemComponent];
const COMPONENTS = [
LayoutDefaultComponent,
LayoutFullScreenComponent,
HeaderComponent,
SidebarComponent,
...SETTINGDRAWER,
];
const HEADERCOMPONENTS = [
HeaderSearchComponent,
HeaderNotifyComponent,
HeaderTaskComponent,
HeaderIconComponent,
HeaderFullScreenComponent,
HeaderI18nComponent,
HeaderStorageComponent,
HeaderUserComponent,
];
// passport // passport
import { LayoutPassportComponent } from './passport/passport.component'; import { LayoutPassportComponent } from './passport/passport.component';
import { TabbarComponent } from './default/tabbar/tabbar.component';
import { MessageComponent } from './default/message/message.component';
import { AssetsComponent } from './default/assets/assets.component';
import { TotalComponent } from './default/total/total.component';
import { UserComponent } from './default/user/user.component';
import { InventoryComponent } from './default/inventory/inventory.component';
const PASSPORT = [LayoutPassportComponent]; const PASSPORT = [LayoutPassportComponent];
@NgModule({ @NgModule({
imports: [SharedModule], imports: [SharedModule],
entryComponents: SETTINGDRAWER, declarations: [...COMPONENTS, ...PASSPORT, MessageComponent, AssetsComponent, TotalComponent, UserComponent, InventoryComponent],
declarations: [...COMPONENTS, ...HEADERCOMPONENTS, ...PASSPORT],
exports: [...COMPONENTS, ...PASSPORT], exports: [...COMPONENTS, ...PASSPORT],
}) })
export class LayoutModule {} export class LayoutModule {}
<div class="container"> <div class="container">
<header-i18n showLangText="false" class="langs"></header-i18n>
<div class="wrap"> <div class="wrap">
<div class="top"> <div class="top">
<div class="head"> <div class="head">
......
<div nz-row [nzGutter]="24" class="pt-lg">
<div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
<g2-card [title]="'app.analysis.total-sales' | translate" total="¥ 126,560" contentHeight="44px" [action]="action1"
[footer]="footer1">
<ng-template #action1>
<nz-tooltip [nzTitle]="'app.analysis.introduce' | translate">
<i nz-tooltip nz-icon type="info-circle"></i>
</nz-tooltip>
</ng-template>
<trend flag="up" style="display:block; margin-top:2px;">
{{'app.analysis.week' | translate}}
<span class="pl-sm">12%</span>
</trend>
<trend flag="down">
{{'app.analysis.day' | translate}}
<span class="pl-sm">11%</span>
</trend>
<ng-template #footer1>
<p class="text-truncate mb0">
{{'app.analysis.day-sales' | translate}}
<span class="ml-sm">¥12,423</span>
</p>
</ng-template>
</g2-card>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
<g2-card [title]="'app.analysis.visits' | translate" total="8,848" contentHeight="46px" [action]="action2" [footer]="footer2">
<ng-template #action2>
<nz-tooltip [nzTitle]="'app.analysis.introduce' | translate">
<i nz-tooltip nz-icon type="info-circle"></i>
</nz-tooltip>
</ng-template>
<g2-mini-area *ngIf="data.visitData" color="#975FE4" height="46" [data]="data.visitData"></g2-mini-area>
<ng-template #footer2>
<p class="text-truncate mb0">
{{'app.analysis.day-visits' | translate}}
<span class="ml-sm">1,234</span>
</p>
</ng-template>
</g2-card>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
<g2-card [title]="'app.analysis.payments' | translate" total="6,560" contentHeight="46px" [action]="action3"
[footer]="footer3">
<ng-template #action3>
<nz-tooltip [nzTitle]="'app.analysis.introduce' | translate">
<i nz-tooltip nz-icon type="info-circle"></i>
</nz-tooltip>
</ng-template>
<g2-mini-bar *ngIf="data.visitData" height="46" [data]="data.visitData"></g2-mini-bar>
<ng-template #footer3>
<p class="text-truncate mb0">
{{'app.analysis.conversion-rate' | translate}}
<span class="ml-sm">60%</span>
</p>
</ng-template>
</g2-card>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
<g2-card [title]="'app.analysis.operational-effect' | translate" total="78%" contentHeight="46px" [action]="action4"
[footer]="footer4">
<ng-template #action4>
<nz-tooltip [nzTitle]="'app.analysis.introduce' | translate">
<i nz-tooltip nz-icon type="info-circle"></i>
</nz-tooltip>
</ng-template>
<g2-mini-progress height="46" percent="78" strokeWidth="8" target="80" color="#13C2C2"></g2-mini-progress>
<ng-template #footer4>
<div class="d-flex justify-content-between text-truncate">
<trend flag="up">
{{'app.analysis.week' | translate}}
<span class="pl-sm">12%</span>
</trend>
<trend flag="down">
{{'app.analysis.day' | translate}}
<span class="pl-sm">11%</span>
</trend>
</div>
</ng-template>
</g2-card>
</div>
</div>
<nz-card [nzLoading]="loading" [nzBordered]="false" class="ant-card__body-nopadding sales-card">
<nz-tabset [nzTabBarExtraContent]="extraTemplate" *ngIf="data.salesData" (nzSelectedIndexChange)="salesChange($event)">
<nz-tab *ngFor="let tab of saleTabs" [nzTitle]="('app.analysis.' + tab.key) | translate">
<div nz-row>
<div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="16">
<div class="bar">
<g2-bar *ngIf="tab.show" height="295" style="width: 100%" [title]="('app.analysis.' + tab.key + '-trend') | translate" [data]="data.salesData"></g2-bar>
</div>
</div>
<div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="8">
<div class="rank">
<h4 class="ranking-title">{{ ('app.analysis.' + tab.key + '-ranking') | translate}}</h4>
<ul class="rank-list">
<li *ngFor="let i of rankingListData; let idx = index">
<span class="number" [ngClass]="{'active': idx < 3}">{{idx+1}}</span>
<span class="title">{{i.title}}</span>
<span class="value">{{i.total | number: '3.0'}}</span>
</li>
</ul>
</div>
</div>
</div>
</nz-tab>
<ng-template #extraTemplate>
<div class="sales-extra-wrap">
<div class="sales-extra">
<a (click)="setDate('today')">{{'app.analysis.all-day' | translate}}</a>
<a (click)="setDate('week')">{{'app.analysis.all-week' | translate}}</a>
<a (click)="setDate('month')">{{'app.analysis.all-month' | translate}}</a>
<a (click)="setDate('year')">{{'app.analysis.all-year' | translate}}</a>
</div>
<nz-range-picker [(ngModel)]="date_range" style="display:inline-block; width: 256px;"></nz-range-picker>
</div>
</ng-template>
</nz-tabset>
</nz-card>
<div nz-row [nzGutter]="24">
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
<nz-card [nzLoading]="loading" [nzBordered]="false" [nzTitle]="'app.analysis.online-top-search' | translate" [nzExtra]="extraOp" class="mb-0">
<ng-template #extraOp>
<nz-dropdown class="icon-group">
<i nz-dropdown nz-icon type="ellipsis"></i>
<ul nz-menu>
<li nz-menu-item>操作一</li>
<li nz-menu-item>操作二</li>
</ul>
</nz-dropdown>
</ng-template>
<div nz-row [nzGutter]="64">
<div nz-col nzXs="24" nzSm="12" class="mb-md">
<number-info total="12,321" subTotal="17.1" status="up" [subTitle]="subTitle">
<ng-template #subTitle>
{{'app.analysis.search-users' | translate}}
<nz-tooltip [nzTitle]="'app.analysis.introduce' | translate">
<i nz-tooltip nz-icon type="info-circle" class="ml-sm"></i>
</nz-tooltip>
</ng-template>
</number-info>
<g2-mini-area *ngIf="data.visitData2" [line]="true" height="45" [data]="data.visitData2"></g2-mini-area>
</div>
<div nz-col nzXs="24" nzSm="12" class="mb-md">
<number-info [subTitle]="'app.analysis.per-capita-search' | translate" total="2.7" subTotal="26.2" status="down"></number-info>
<g2-mini-area *ngIf="data.visitData2" [line]="true" height="45" [data]="data.visitData2"></g2-mini-area>
</div>
</div>
<st [data]="data.searchData" [columns]="searchColumn" size="small" ps="5" [page]="{toTopInChange:false}">
<ng-template st-row="range" let-i>
<trend [flag]="i.status === 1 ? 'down' : 'up'">
<span>{{i.range}}%</span>
</trend>
</ng-template>
</st>
</nz-card>
</div>
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
<nz-card [nzLoading]="loading" [nzBordered]="false" [nzTitle]="'app.analysis.the-proportion-of-sales' | translate" [nzBodyStyle]="{'padding.px': 24}" [nzExtra]="extra"
class="sales-card mb-0" style="min-height: 502.5px">
<ng-template #extra>
<div class="sales-card-extra">
<nz-dropdown class="icon-group" nzPlacement="bottomLeft">
<i nz-dropdown nz-icon type="ellipsis"></i>
<ul nz-menu>
<li nz-menu-item>操作一</li>
<li nz-menu-item>操作二</li>
</ul>
</nz-dropdown>
<div class="sales-type-radio">
<nz-radio-group [(ngModel)]="salesType" (ngModelChange)="changeSaleType()">
<label nz-radio-button [nzValue]="'all'">
{{ 'app.analysis.channel.all' | translate }}
</label>
<label nz-radio-button [nzValue]="'online'">
{{ 'app.analysis.channel.online' | translate }}
</label>
<label nz-radio-button [nzValue]="'offline'">
{{ 'app.analysis.channel.stores' | translate }}
</label>
</nz-radio-group>
</div>
</div>
</ng-template>
<h4 class="margin:8px 0 32px 0;">{{'app.analysis.sales' | translate}}</h4>
<g2-pie *ngIf="salesPieData" [data]="salesPieData" [hasLegend]="true" [subTitle]="'app.analysis.sales' | translate" [height]="248" [lineWidth]="4" [total]="salesTotal"
[valueFormat]="handlePieValueFormat">
</g2-pie>
</nz-card>
</div>
</div>
<nz-card [nzLoading]="loading" [nzBordered]="false" [nzBodyStyle]="{'padding': '0 0 32px'}" class="offline-card mt-lg">
<nz-tabset *ngIf="data.offlineData" [(nzSelectedIndex)]="offlineIdx" (nzSelectedIndexChange)="offlineChange($event)">
<nz-tab *ngFor="let tab of data.offlineData; let i = index;" [nzTitle]="nzTabHeading">
<ng-template #nzTabHeading>
<div nz-row [nzGutter]="8" style="width: 138px; margin: 8px 0;">
<div nz-col [nzSpan]="12">
<number-info [title]="tab.name" [subTitle]="'app.analysis.conversion-rate' | translate" gap="2" [total]="(tab.cvr * 100) + '%'" [theme]="i !== offlineIdx && 'light'"></number-info>
</div>
<div nz-col [nzSpan]="12" style="padding-top: 36px;">
<g2-pie [animate]="false" [color]="i !== offlineIdx && '#BDE4FF'"
[inner]="0.55" [tooltip]="false"
[padding]="[0, 0, 0, 0]" [percent]="tab.cvr * 100" [height]="64">
</g2-pie>
</div>
</div>
</ng-template>
<div class="px-lg">
<g2-timeline *ngIf="tab.show" [data]="tab.chart" [titleMap]="titleMap"></g2-timeline>
</div>
</nz-tab>
</nz-tabset>
</nz-card>
@import '~@delon/theme/styles/default';
:host ::ng-deep {
.icon-group {
i {
transition: color 0.32s;
color: @text-color-secondary;
cursor: pointer;
margin-left: 16px;
&:hover {
color: @text-color;
}
}
}
.rank-list {
margin: 25px 0 0;
padding: 0;
list-style: none;
li {
.clearfix();
margin-top: 16px;
display: flex;
align-items: center;
span {
color: @text-color;
font-size: 14px;
line-height: 22px;
}
.number {
background-color: @background-color-base;
border-radius: 20px;
display: inline-block;
font-size: 12px;
font-weight: 600;
margin-right: 16px;
height: 20px;
line-height: 20px;
width: 20px;
text-align: center;
margin-top: 1.5px;
&.active {
background-color: #314659;
color: #fff;
}
}
.title {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin-right: 8px;
}
}
}
.sales-extra {
display: inline-block;
margin-right: 24px;
a {
color: @text-color;
margin-left: 24px;
&:hover {
color: @primary-color;
}
&.currentDate {
color: @primary-color;
}
}
}
.sales-card {
.bar {
padding: 0 0 32px 32px;
}
.rank {
padding: 0 32px 32px 72px;
}
.ant-tabs-bar {
padding-left: 16px;
.ant-tabs-nav .ant-tabs-tab {
padding-top: 16px;
padding-bottom: 14px;
line-height: 24px;
}
}
.ant-tabs-extra-content {
padding-right: 24px;
line-height: 55px;
}
.ant-card-head {
position: relative;
}
.ant-card-head-title {
align-items: normal;
}
}
.sales-card-extra {
height: inherit;
}
.sales-type-radio {
position: absolute;
right: 54px;
bottom: 12px;
}
.offline-card {
.ant-tabs-ink-bar {
bottom: auto;
}
.ant-tabs-bar {
border-bottom: none;
}
.ant-tabs-nav-container-scrolling {
padding-left: 40px;
padding-right: 40px;
}
.ant-tabs-tab-prev-icon:before {
position: relative;
left: 6px;
}
.ant-tabs-tab-next-icon:before {
position: relative;
right: 6px;
}
.ant-tabs-tab-active h4 {
color: @primary-color;
}
}
.trend-text {
margin-left: 8px;
color: @heading-color;
}
@media screen and (max-width: @screen-lg) {
.sales-extra {
display: none;
}
.rank-list {
li {
span:first-child {
margin-right: 8px;
}
}
}
}
@media screen and (max-width: @screen-md) {
.rank-title {
margin-top: 16px;
}
.sales-card .bar {
padding: 16px;
}
}
@media screen and (max-width: @screen-sm) {
.sales-extra-wrap {
display: none;
}
.sales-card {
.ant-tabs-content {
padding-top: 30px;
}
}
}
// fix pagination bottom
.ant-table-pagination {
margin-bottom: 0;
}
.g2-pie__legend-block .g2-pie__chart {
margin: 0;
}
}
import { Component, ChangeDetectionStrategy, OnInit, ChangeDetectorRef } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { STColumn } from '@delon/abc';
import { getTimeDistance } from '@delon/util';
import { _HttpClient } from '@delon/theme';
import { I18NService } from '@core';
import { yuan } from '@shared';
@Component({
selector: 'app-dashboard-analysis',
templateUrl: './analysis.component.html',
styleUrls: ['./analysis.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardAnalysisComponent implements OnInit {
data: any = {};
loading = true;
date_range: Date[] = [];
rankingListData: any[] = Array(7)
.fill({})
.map((item, i) => {
return {
title: this.i18n.fanyi('app.analysis.test', { no: i }),
total: 323234,
};
});
titleMap = {
y1: this.i18n.fanyi('app.analysis.traffic'),
y2: this.i18n.fanyi('app.analysis.payments'),
};
searchColumn: STColumn[] = [
{ title: '排名', i18n: 'app.analysis.table.rank', index: 'index' },
{
title: '搜索关键词',
i18n: 'app.analysis.table.search-keyword',
index: 'keyword',
click: (item: any) => this.msg.success(item.keyword),
},
{
type: 'number',
title: '用户数',
i18n: 'app.analysis.table.users',
index: 'count',
sorter: (a, b) => a.count - b.count,
},
{
type: 'number',
title: '周涨幅',
i18n: 'app.analysis.table.weekly-range',
index: 'range',
render: 'range',
sorter: (a, b) => a.range - b.range,
},
];
constructor(
private http: _HttpClient,
public msg: NzMessageService,
private i18n: I18NService,
private cdr: ChangeDetectorRef,
) {}
ngOnInit() {
this.http.get('/chart').subscribe((res: any) => {
res.offlineData.forEach((item: any, idx: number) => {
item.show = idx === 0;
item.chart = Object.assign([], res.offlineChartData);
});
this.data = res;
this.loading = false;
this.changeSaleType();
});
}
setDate(type: any) {
this.date_range = getTimeDistance(type);
setTimeout(() => this.cdr.detectChanges());
}
salesType = 'all';
salesPieData: any;
salesTotal = 0;
changeSaleType() {
this.salesPieData =
this.salesType === 'all'
? this.data.salesTypeData
: this.salesType === 'online'
? this.data.salesTypeDataOnline
: this.data.salesTypeDataOffline;
if (this.salesPieData) {
this.salesTotal = this.salesPieData.reduce((pre, now) => now.y + pre, 0);
}
this.cdr.detectChanges();
}
handlePieValueFormat(value: any) {
return yuan(value);
}
saleTabs: any[] = [{ key: 'sales', show: true }, { key: 'visits' }];
salesChange(idx: number) {
if (this.saleTabs[idx].show !== true) {
this.saleTabs[idx].show = true;
this.cdr.detectChanges();
}
}
offlineIdx = 0;
offlineChange(idx: number) {
if (this.data.offlineData[idx].show !== true) {
this.data.offlineData[idx].show = true;
this.cdr.detectChanges();
}
}
}
<div nz-row [nzGutter]="24" class="pt-lg">
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="18">
<nz-card [nzTitle]="'app.monitor.trading-activity' | translate" [nzBordered]="false" class="mb-lg">
<div nz-row>
<div nz-col nzXs="24" nzSm="12" nzMd="6">
<number-info [subTitle]="'app.monitor.total-transactions' | translate" [total]="'124,543,233'" suffix="元"></number-info>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6">
<number-info [subTitle]="'app.monitor.sales-target' | translate" [total]="'92%'"></number-info>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6">
<number-info [subTitle]="'app.monitor.remaining-time' | translate" [total]="lastTotalTime">
<ng-template #lastTotalTime>
<count-down [target]="30"></count-down>
</ng-template>
</number-info>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6">
<number-info [subTitle]="'app.monitor.total-transactions-per-second' | translate" [total]="234" suffix="元"></number-info>
</div>
</div>
<div class="map-chart">
<nz-tooltip [nzTitle]="'app.monitor.waiting-for-implementation' | translate">
<img nz-tooltip nzPlacement="top" src="https://gw.alipayobjects.com/zos/rmsportal/HBWnDEUXCnGnGrRfrpKa.png" alt="map" />
</nz-tooltip>
</div>
</nz-card>
</div>
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="6">
<nz-card [nzTitle]="'app.monitor.activity-forecast' | translate" [nzBordered]="false" class="mb-lg">
<div class="active-chart" *ngIf="activeData">
<number-info subTitle="目标评估" total="有望达到预期"></number-info>
<g2-mini-area [animate]="false" line [borderWidth]="2" [height]="84" padding="0" [data]="activeData"></g2-mini-area>
<div class="active-grid">
<p>{{activeStat.max}} 亿元</p>
<p>{{activeStat.min}} 亿元</p>
</div>
<div class="active-legend">
<span>00:00</span>
<span>{{activeStat.t1}}</span>
<span>{{activeStat.t2}}</span>
</div>
</div>
</nz-card>
<nz-card [nzTitle]="'app.monitor.efficiency' | translate" [nzBordered]="false" [nzBodyStyle]="{'text-align': 'center'}" class="mb-lg">
<g2-gauge *ngIf="percent" [title]="'app.monitor.ratio' | translate" [height]="180" [percent]="percent" [format]="couponFormat"></g2-gauge>
</nz-card>
</div>
</div>
<div nz-row [nzGutter]="24">
<div nz-col nzXs="24" nzSm="24" nzLg="12" class="mb-lg">
<nz-card [nzTitle]="'app.monitor.proportion-per-category' | translate" [nzBordered]="false" class="pie-card">
<div nz-row [nzGutter]="4" style="padding:16px 0">
<div nz-col [nzSpan]="8">
<g2-pie [animate]="false" [percent]="28" [subTitle]="'app.monitor.fast-food' | translate" total="28%" [height]="128" [lineWidth]="2"></g2-pie>
</div>
<div nz-col [nzSpan]="8">
<g2-pie [animate]="false" color="#5DDECF" [percent]="22" [subTitle]="'app.monitor.western-food' | translate" total="22%" [height]="128" [lineWidth]="2"></g2-pie>
</div>
<div nz-col [nzSpan]="8">
<g2-pie [animate]="false" color="#2FC25B" [percent]="32" [subTitle]="'app.monitor.hot-pot' | translate" total="32%" [height]="128" [lineWidth]="2"></g2-pie>
</div>
</div>
</nz-card>
</div>
<div nz-col nzXs="24" nzSm="24" nzLg="6" class="mb-lg">
<nz-card [nzTitle]="'app.monitor.popular-searches' | translate" [nzBordered]="false">
<g2-tag-cloud [data]="tags" [height]="165"></g2-tag-cloud>
</nz-card>
</div>
<div nz-col nzXs="24" nzSm="24" nzLg="6" class="mb-lg">
<nz-card [nzTitle]="'app.monitor.resource-surplus' | translate" [nzBordered]="false">
<div class="text-center">
<g2-water-wave [title]="'app.monitor.fund-surplus' | translate" [percent]="34" [height]="165"></g2-water-wave>
</div>
</nz-card>
</div>
</div>
@import '~@delon/theme/styles/default';
:host ::ng-deep {
.map-chart {
padding-top: 24px;
height: 457px;
text-align: center;
img {
display: inline-block;
max-width: 100%;
max-height: 437px;
}
}
.pie-card {
.pie-stat {
font-size: 24px !important;
}
}
.active-chart {
position: relative;
g2-mini-area {
margin-top: 32px;
}
.active-grid {
p {
position: absolute;
top: 80px;
border-bottom: 1px dashed #e9e9e9;
padding-bottom: 4px;
width: 100%;
}
p:last-child {
top: 115px;
}
}
.active-legend {
position: relative;
font-size: 0;
margin-top: 8px;
height: 20px;
line-height: 20px;
span {
display: inline-block;
font-size: 12px;
text-align: center;
width: 33.33%;
}
span:first-child {
text-align: left;
}
span:last-child {
text-align: right;
}
}
}
@media screen and (max-width: @screen-lg) {
.map-chart {
height: auto;
}
}
}
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { zip } from 'rxjs';
import { _HttpClient } from '@delon/theme';
@Component({
selector: 'app-dashboard-monitor',
templateUrl: './monitor.component.html',
styleUrls: ['./monitor.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardMonitorComponent implements OnInit, OnDestroy {
data: any = {};
tags = [];
loading = true;
q: any = {
start: null,
end: null,
};
percent: number | null = null;
constructor(private http: _HttpClient, public msg: NzMessageService, private cdr: ChangeDetectorRef) {}
ngOnInit() {
zip(this.http.get('/chart'), this.http.get('/chart/tags')).subscribe(([res, tags]: [any, any]) => {
this.data = res;
tags.list[Math.floor(Math.random() * tags.list.length) + 1].value = 1000;
this.tags = tags.list;
this.loading = false;
this.cdr.detectChanges();
});
// active chart
this.refData();
this.activeTime$ = setInterval(() => this.refData(), 1000 * 2);
}
// region: active chart
activeTime$: any;
activeData: any[];
activeStat = {
max: 0,
min: 0,
t1: '',
t2: '',
};
refData() {
const activeData: any[] = [];
for (let i = 0; i < 24; i += 1) {
activeData.push({
x: `${i.toString().padStart(2, '0')}:00`,
y: i * 50 + Math.floor(Math.random() * 200),
});
}
this.activeData = activeData;
// stat
this.activeStat.max = [...activeData].sort()[activeData.length - 1].y + 200;
this.activeStat.min = [...activeData].sort()[Math.floor(activeData.length / 2)].y;
this.activeStat.t1 = activeData[Math.floor(activeData.length / 2)].x;
this.activeStat.t2 = activeData[activeData.length - 1].x;
// percent
this.percent = Math.floor(Math.random() * 100);
this.cdr.detectChanges();
}
// endregion
couponFormat(val: any) {
switch (parseInt(val, 10)) {
case 20:
return '差';
case 40:
return '中';
case 60:
return '良';
case 80:
return '优';
default:
return '';
}
}
ngOnDestroy(): void {
if (this.activeTime$) clearInterval(this.activeTime$);
}
}
<div class="alain-default__content-title">
<h1>
Dashboard
<small>Welcome !</small>
</h1>
</div>
<quick-menu>
<nz-list [nzBordered]="false" [nzSplit]="false">
<nz-list-item>
<a routerLink="/">Home</a>
</nz-list-item>
<nz-list-item>
<a routerLink="/widgets">Widgets</a>
</nz-list-item>
<nz-list-item>
<a routerLink="/style/typography">typography</a>
</nz-list-item>
<nz-list-item>
<a routerLink="/style/gridmasonry">gridmasonry</a>
</nz-list-item>
<nz-list-item>
<a routerLink="/pro/result/success">success result</a>
</nz-list-item>
</nz-list>
</quick-menu>
<div nz-row nzGutter="16">
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
<div nz-row nzType="flex" nzAlign="middle" class="bg-primary rounded-md">
<div nz-col nzSpan="12" class="p-md text-white">
<div class="h2 mt0">123,456</div>
<p class="text-nowrap mb0">Website Traffics</p>
</div>
<div nz-col nzSpan="12">
<g2-mini-bar *ngIf="webSite" height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite" tooltipType="mini"></g2-mini-bar>
</div>
</div>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
<div nz-row nzType="flex" nzAlign="middle" class="bg-success rounded-md">
<div nz-col nzSpan="12" class="p-md text-white">
<div class="h2 mt0">234,567K</div>
<p class="text-nowrap mb0">Website Impressions</p>
</div>
<div nz-col nzSpan="12">
<g2-mini-bar *ngIf="webSite" height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite" tooltipType="mini"></g2-mini-bar>
</div>
</div>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
<div nz-row nzType="flex" nzAlign="middle" class="bg-orange rounded-md">
<div nz-col nzSpan="12" class="p-md text-white">
<div class="h2 mt0">$458,778</div>
<p class="text-nowrap mb0">Total Sales</p>
</div>
<div nz-col nzSpan="12">
<g2-mini-bar *ngIf="webSite" height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite" tooltipType="mini"></g2-mini-bar>
</div>
</div>
</div>
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
<div nz-row nzType="flex" nzAlign="middle" class="bg-magenta rounded-md">
<div nz-col nzSpan="12" class="p-md text-white">
<div class="h2 mt0">456</div>
<p class="text-nowrap mb0">Support Tickets</p>
</div>
<div nz-col nzSpan="12">
<g2-mini-bar *ngIf="webSite" height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite" tooltipType="mini"></g2-mini-bar>
</div>
</div>
</div>
</div>
<div nz-row nzGutter="16">
<div nz-col nzXs="24" nzMd="12">
<nz-card [nzBordered]="false" [nzTitle]="salesTitle">
<ng-template #salesTitle>
Sales Statistics
<small class="text-sm font-weight-normal">Business Expectations & Retail Sales Statistics</small>
</ng-template>
<g2-bar *ngIf="salesData" height="275" [data]="salesData"></g2-bar>
</nz-card>
</div>
<div nz-col nzXs="24" nzMd="12">
<nz-card [nzTitle]="growthTitle" [nzBordered]="false">
<ng-template #growthTitle>
Growth Rate
<small class="text-sm font-weight-normal">Business Expectations & Retail Sales Statistics</small>
</ng-template>
<g2-timeline *ngIf="offlineChartData" [data]="offlineChartData" [height]="239" [padding]="[0, 0, 0, 0]" [titleMap]="{ y1: '客流量', y2: '支付笔数' }"></g2-timeline>
</nz-card>
</div>
</div>
<div nz-row nzGutter="16">
<div nz-col nzXs="24" nzMd="12">
<nz-card [nzBordered]="false" [nzCover]="coverTpl">
<ng-template #coverTpl>
<img class="img" src="//os.alipayobjects.com/rmsportal/GhjqstwSgxBXrZS.png">
</ng-template>
<h3>ANT DESIGN</h3>
<p class="text-grey">A UI Design Language</p>
<ol class="list-styled text-lg pt-md">
<li>Designed by experienced team, and showcase dozens of inspiring projects.</li>
<li>Provide solutions for usual problems that may be encountered while developing enterprise-like complex UIs.</li>
<li>Dozens of flexible and practical reusable components that increase your productivity.</li>
</ol>
<p class="pt-md mb0">
<a class="text-grey" href="//ng.ant.design" target="_blank">View Site...</a>
</p>
</nz-card>
</div>
<div nz-col nzXs="24" nzMd="12">
<nz-card [nzTitle]="recentTitle" [nzBordered]="false" class="ant-card__body-nopadding">
<ng-template #recentTitle>
Recent Posts
<small class="text-sm font-weight-normal">Venenatis portauam Inceptos ameteiam</small>
</ng-template>
<div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="20">
<strong>{{item.name}}</strong>
<p class="mb0">{{item.content}}</p>
</div>
</div>
</nz-card>
</div>
<div nz-col nzXs="24" nzMd="12">
<nz-card nzTitle="Todo lists" [nzBordered]="false" class="ant-card__body-nopadding">
<div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
<div nz-col [nzSpan]="4" class="text-center">
<nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
</div>
<div nz-col [nzSpan]="18">
<strong>{{item.name}}</strong>
<p [class.text-deleted]="item.completed" class="mb0">{{item.content}}</p>
</div>
<div nz-col [nzSpan]="2" class="text-right pr-md">
<nz-dropdown [nzPlacement]="'topRight'">
<i nz-dropdown nz-icon type="ellipsis" class="rotate-90"></i>
<ul nz-menu>
<li nz-menu-item *ngIf="item.completed" (click)="item.completed=false">Active</li>
<li nz-menu-item *ngIf="!item.completed" (click)="item.completed=true">Completed</li>
<li nz-menu-item (click)="todoData.splice(todoData.indexOf(item), 1)">Delted</li>
</ul>
</nz-dropdown>
</div>
</div>
</nz-card>
</div>
</div>
import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
selector: 'app-dashboard-v1',
templateUrl: './v1.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardV1Component implements OnInit {
todoData: any[] = [
{
completed: true,
avatar: '1',
name: '苏先生',
content: `请告诉我,我应该说点什么好?`,
},
{
completed: false,
avatar: '2',
name: 'はなさき',
content: `ハルカソラトキヘダツヒカリ`,
},
{
completed: false,
avatar: '3',
name: 'cipchk',
content: `this world was never meant for one as beautiful as you.`,
},
{
completed: false,
avatar: '4',
name: 'Kent',
content: `my heart is beating with hers`,
},
{
completed: false,
avatar: '5',
name: 'Are you',
content: `They always said that I love beautiful girl than my friends`,
},
{
completed: false,
avatar: '6',
name: 'Forever',
content: `Walking through green fields ,sunshine in my eyes.`,
},
];
webSite: any[];
salesData: any[];
offlineChartData: any[];
constructor(private http: _HttpClient, private cdr: ChangeDetectorRef) {}
ngOnInit() {
this.http.get('/chart').subscribe((res: any) => {
this.webSite = res.visitData.slice(0, 10);
this.salesData = res.salesData;
this.offlineChartData = res.offlineChartData;
this.cdr.detectChanges();
});
}
}
<page-header [breadcrumb]="breadcrumb" [content]="content" [extra]="extra">
<ng-template #breadcrumb>
<nz-breadcrumb>
<nz-breadcrumb-item>
<a [routerLink]="['/']">首页</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/']">Dashboard</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>工作台</nz-breadcrumb-item>
</nz-breadcrumb>
</ng-template>
<ng-template #content>
<div class="content">
<div class="avatar">
<nz-avatar nzSrc="https://gw.alipayobjects.com/zos/rmsportal/lctvVCLfRpYCkYxAsiVQ.png"></nz-avatar>
</div>
<div class="desc">
<div class="desc-title">早安,山治,我要吃肉!</div>
<div>假砖家 | 地球-伟大航道-黄金梅丽号-厨房-小强部门</div>
</div>
</div>
</ng-template>
<ng-template #extra>
<div class="page-extra">
<div>
<p>项目数</p>
<p>56</p>
</div>
<div>
<p>团队内排名</p>
<p>8
<span> / 24</span>
</p>
</div>
<div>
<p>项目访问</p>
<p>2,223</p>
</div>
</div>
</ng-template>
</page-header>
<div nz-row [nzGutter]="24">
<div nz-col nzXs="24" nzSm="24" nzMd="16">
<nz-card nzTitle="进行中的项目" [nzExtra]="ingExtra" [nzBordered]="false" [nzLoading]="loading" class="ant-card__body-nopadding mb-lg project-list">
<ng-template #ingExtra>
<a (click)="msg.success('to')">全部项目</a>
</ng-template>
<div *ngFor="let item of notice" nz-card-grid class="project-grid">
<nz-card [nzBordered]="false" class="ant-card__body-nopadding mb0">
<nz-card-meta [nzTitle]="noticeTitle" [nzDescription]="item.description">
<ng-template #noticeTitle>
<div class="card-title">
<nz-avatar [nzSrc]="item.logo" [nzSize]="'small'"></nz-avatar>
<a (click)="msg.info('to' + item.href)">{{item.title}}</a>
</div>
</ng-template>
</nz-card-meta>
<div class="project-item">
<a (click)="msg.info('show user: ' + item.member)">{{item.member}}</a>
<span *ngIf="item.updatedAt" class="datetime" title="{{item.updatedAt}}">
{{item.updatedAt | _date: 'fn' }}
</span>
</div>
</nz-card>
</div>
</nz-card>
<nz-card nzTitle="动态" [nzBordered]="false" [nzLoading]="loading" class="ant-card__body-nopadding mb-lg active-card">
<nz-list nzSize="large" class="activities">
<nz-list-item *ngFor="let item of activities">
<nz-list-item-meta [nzAvatar]="item.user.avatar" [nzTitle]="activeTitle" [nzDescription]="activeDescription">
<ng-template #activeTitle>
<a (click)="msg.success(item.user.name)" class="username">{{item.user.name}}</a>
&nbsp;
<span class="event" [innerHTML]="item.template"></span>
</ng-template>
<ng-template #activeDescription>
<span class="datetime" title="{{item.updatedAt}}">{{item.updatedAt | _date: 'fn'}}</span>
</ng-template>
</nz-list-item-meta>
</nz-list-item>
</nz-list>
</nz-card>
</div>
<div nz-col nzXs="24" nzSm="24" nzMd="8">
<nz-card nzTitle="快速开始 / 便捷导航" [nzBordered]="false" class="ant-card__body-nopadding mb-lg">
<div class="links">
<a *ngFor="let item of links" (click)="msg.success(item.title)">{{item.title}}</a>
<button nz-button (click)="links.push({title: 'new titel', href: 'href'})" [nzType]="'dashed'" [nzSize]="'small'">
<i nz-icon type="plus"></i>
<span>添加</span>
</button>
</div>
</nz-card>
<nz-card nzTitle="XX 指数" [nzBordered]="false" [nzLoading]="loading" class="mb-lg">
<g2-radar *ngIf="radarData" [data]="radarData" [height]="343" [hasLegend]="true"></g2-radar>
</nz-card>
<nz-card nzTitle="团队" [nzBordered]="false" [nzBodyStyle]="{'padding-top.px': 12, 'padding-bottom.px': 12 }" class="mb-lg">
<div class="members">
<div nz-row [nzGutter]="48">
<div nz-col [nzSpan]="12" *ngFor="let i of members">
<a (click)="msg.success(i.title)">
<nz-avatar [nzSrc]="i.logo" [nzSize]="'small'"></nz-avatar>
<span class="member">{{i.title}}</span>
</a>
</div>
</div>
</div>
</nz-card>
</div>
</div>
@import '~@delon/theme/styles/default';
:host ::ng-deep {
.content {
display: flex;
.avatar {
flex: 0 1 72px;
margin-bottom: 8px;
.ant-avatar {
border-radius: 72px;
display: block;
width: 72px;
height: 72px;
}
}
.desc {
position: relative;
top: 4px;
margin-left: 24px;
flex: 1 1 auto;
color: @text-color-secondary;
line-height: 22px;
.desc-title {
font-size: 20px;
line-height: 28px;
font-weight: 500;
color: @heading-color;
margin-bottom: 12px;
}
}
}
.page-extra {
.clearfix();
float: right;
white-space: nowrap;
& > div {
padding: 0 32px;
position: relative;
display: inline-block;
& > p:first-child {
color: @text-color-secondary;
font-size: @font-size-base;
line-height: 22px;
margin-bottom: 4px;
}
& > p {
color: @heading-color;
font-size: 30px;
line-height: 38px;
margin: 0;
& > span {
color: @text-color-secondary;
font-size: 20px;
}
}
&:after {
background-color: @border-color-split;
position: absolute;
top: 8px;
right: 0;
width: 1px;
height: 40px;
content: '';
}
}
& > div:last-child {
padding-right: 0;
&:after {
display: none;
}
}
}
.project-list {
.ant-card-meta-description {
color: @text-color-secondary;
height: 44px;
line-height: 22px;
overflow: hidden;
}
.card-title {
font-size: 0;
a {
color: @heading-color;
margin-left: 12px;
line-height: 24px;
height: 24px;
display: inline-block;
vertical-align: top;
font-size: @font-size-base;
&:hover {
color: @primary-color;
}
}
}
.project-grid {
width: 33.33%;
}
.project-item {
display: flex;
margin-top: 8px;
overflow: hidden;
font-size: 12px;
height: 20px;
line-height: 20px;
.textOverflow();
a {
color: @text-color-secondary;
display: inline-block;
flex: 1 1 0;
.textOverflow();
&:hover {
color: @primary-color;
}
}
.datetime {
color: @disabled-color;
flex: 0 0 auto;
float: right;
}
}
}
.activities {
padding: 0 24px 8px;
.username {
color: @text-color;
}
.event {
font-weight: normal;
}
}
.members {
a {
display: block;
margin: 12px 0;
line-height: 24px;
height: 24px;
.textOverflow();
.member {
font-size: @font-size-base;
color: @text-color;
line-height: 24px;
max-width: 100px;
vertical-align: top;
margin-left: 12px;
transition: all 0.3s;
display: inline-block;
.textOverflow();
}
&:hover {
span {
color: @primary-color;
}
}
}
}
.datetime {
color: @disabled-color;
}
.links {
padding: 20px 0 8px 24px;
font-size: 0;
> a {
color: @text-color;
display: inline-block;
font-size: @font-size-base;
margin-bottom: 13px;
width: 25%;
&:hover {
color: @primary-color;
}
}
}
@media screen and (max-width: @screen-xl) and (min-width: @screen-lg) {
.active-card {
margin-bottom: 24px;
}
.members {
margin-bottom: 0;
}
.page-extra {
margin-left: -44px;
& > div {
padding: 0 16px;
}
}
}
@media screen and (max-width: @screen-lg) {
.active-card {
margin-bottom: 24px;
}
.members {
margin-bottom: 0;
}
.page-extra {
float: none;
margin-right: 0;
& > div {
padding: 0 16px;
text-align: left;
&:after {
display: none;
}
}
}
}
@media screen and (max-width: @screen-md) {
.page-extra {
margin-left: -16px;
}
.project-list {
.project-grid {
width: 50%;
}
}
}
@media screen and (max-width: @screen-sm) {
.content {
display: block;
.desc {
margin-left: 0;
}
}
.page-extra {
& > div {
float: none;
}
}
}
@media screen and (max-width: @screen-xs) {
.project-list {
.project-grid {
width: 100%;
}
}
}
}
import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { zip } from 'rxjs';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
@Component({
selector: 'app-dashboard-workplace',
templateUrl: './workplace.component.html',
styleUrls: ['./workplace.component.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardWorkplaceComponent implements OnInit {
notice: any[] = [];
activities: any[] = [];
radarData: any[];
loading = true;
// region: mock data
links = [
{
title: '操作一',
href: '',
},
{
title: '操作二',
href: '',
},
{
title: '操作三',
href: '',
},
{
title: '操作四',
href: '',
},
{
title: '操作五',
href: '',
},
{
title: '操作六',
href: '',
},
];
members = [
{
id: 'members-1',
title: '科学搬砖组',
logo: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
link: '',
},
{
id: 'members-2',
title: '程序员日常',
logo: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
link: '',
},
{
id: 'members-3',
title: '设计天团',
logo: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
link: '',
},
{
id: 'members-4',
title: '中二少女团',
logo: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
link: '',
},
{
id: 'members-5',
title: '骗你学计算机',
logo: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
link: '',
},
];
// endregion
constructor(private http: _HttpClient, public msg: NzMessageService, private cdr: ChangeDetectorRef) {}
ngOnInit() {
zip(this.http.get('/chart'), this.http.get('/api/notice'), this.http.get('/api/activities')).subscribe(
([chart, notice, activities]: [any, any, any]) => {
this.radarData = chart.radarData;
this.notice = notice;
this.activities = activities.map((item: any) => {
item.template = item.template.split(/@\{([^{}]*)\}/gi).map((key: string) => {
if (item[key]) return `<a>${item[key].name}</a>`;
return key;
});
return item;
});
this.loading = false;
this.cdr.detectChanges();
},
);
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RelationComponent } from './relation/relation.component';
const routes: Routes = [{ path: 'relation', component: RelationComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DataVRoutingModule {}
import { NgModule } from '@angular/core';
import { SharedModule } from '@shared';
import { DataVRoutingModule } from './data-v-routing.module';
import { RelationComponent } from './relation/relation.component';
const COMPONENTS = [RelationComponent];
const COMPONENTS_NOROUNT = [];
@NgModule({
imports: [SharedModule, DataVRoutingModule],
declarations: [...COMPONENTS, ...COMPONENTS_NOROUNT],
entryComponents: COMPONENTS_NOROUNT,
})
export class DataVModule {}
<page-header [title]="'asdf'"></page-header>
<quick-menu>
<nz-list [nzBordered]="false" [nzSplit]="false">
<nz-list-item><a href="#">Link1</a></nz-list-item>
<nz-list-item><a href="#">Link2</a></nz-list-item>
<nz-list-item><a href="#">Link3</a></nz-list-item>
<nz-list-item><a href="#">Link4</a></nz-list-item>
<nz-list-item><a href="#">Link5</a></nz-list-item>
</nz-list>
</quick-menu>
import { Component, OnDestroy, ViewEncapsulation, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
selector: 'app-data-v-relation',
templateUrl: './relation.component.html',
styleUrls: ['./relation.component.less'],
})
export class RelationComponent implements OnInit, OnDestroy {
ecIntance: any;
options: any = {
title: {
text: 'User Releaction',
},
tooltip: {},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [
{
type: 'graph',
layout: 'force',
symbolSize: 60,
focusNodeAdjacency: true,
roam: true,
categories: [
{
name: 'User',
},
],
label: {
normal: {
show: true,
textStyle: {
fontSize: 12,
},
},
},
force: {
repulsion: 2000,
gravity: 0.3,
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
draggable: true,
tooltip: {
triggerOn: 'click',
formatter: item => {
if (item.dataType === 'node') return `${item.data.name}${item.data.arg}`;
return item.name;
},
},
data: Array(20)
.fill({})
.map((v, i) => {
return {
name: 'User' + i,
arg: i + 10,
category: 0,
};
}),
links: [
{
source: 'User0',
target: 'User1',
},
{
source: 'User0',
target: 'User2',
},
{
source: 'User0',
target: 'User3',
},
{
source: 'User1',
target: 'User4',
},
{
source: 'User2',
target: 'User5',
},
{
source: 'User3',
target: 'User6',
},
{
source: 'User4',
target: 'User7',
},
{
source: 'User5',
target: 'User8',
},
{
source: 'User6',
target: 'User9',
},
{
source: 'User1',
target: 'User10',
},
{
source: 'User1',
target: 'User11',
},
{
source: 'User11',
target: 'User12',
},
{
source: 'User11',
target: 'User13',
},
{
source: 'User11',
target: 'User14',
},
{
source: 'User11',
target: 'User15',
},
{
source: 'User11',
target: 'User16',
},
{
source: 'User11',
target: 'User17',
},
{
source: 'User11',
target: 'User18',
},
{
source: 'User11',
target: 'User19',
},
],
lineStyle: {
normal: {
opacity: 0.7,
width: 1,
curveness: 0.1,
},
},
},
],
};
constructor(private http: _HttpClient) {}
chartInit(ec) {
this.ecIntance = ec;
}
ngOnInit() {
window.addEventListener('resize', () => this.resize);
}
private resize() {
if (this.ecIntance) this.ecIntance.resize();
}
ngOnDestroy(): void {
window.removeEventListener('resize', () => this.resize);
}
}
<div class="alain-default__content-title">
<h1>
ACL 访问控制
<small>注意观察左边的菜单;ACLService提供一个完整的基于角色的访问控制的服务,若需要支持路由守卫,请配合ACLService与Route Guard配合简便实现。</small>
</h1>
</div>
<div nz-row [nzGutter]="8">
<div nz-col [nzSpan]="24">
<nz-card nzTitle="按钮粒度">
ACL原始数据:{{ aclSrv.data | json }}
<button nz-button [acl]="'role-a'">role-a</button>
<button nz-button [acl]="'role-b'" class="ml-sm">role-b</button>
</nz-card>
</div>
</div>
<div nz-row [nzGutter]="8">
<div nz-col [nzSpan]="8">
<nz-card nzTitle="全量">
<button nz-button (click)="toggleFull()">
<span>{{ full ? '离开' : '设置'}}权限</span>
</button>
<p class="pt-md">全量类指系统管理员角色,无任何受限。</p>
</nz-card>
</div>
<div nz-col [nzSpan]="8">
<nz-card nzTitle="角色[role-a]">
<button nz-button (click)="toggleRoleA()">
<span>{{ roleA.length > 0 ? '离开' : '设置'}}权限</span>
</button>
</nz-card>
</div>
<div nz-col [nzSpan]="8">
<nz-card nzTitle="角色[role-b]">
<button nz-button (click)="toggleRoleB()">
<span>{{ roleB.length > 0 ? '离开' : '设置'}}权限</span>
</button>
</nz-card>
</div>
</div>
import { Component } from '@angular/core';
import { ACLService } from '@delon/acl';
import { MenuService } from '@delon/theme';
@Component({
selector: 'app-acl',
templateUrl: './acl.component.html',
})
export class ACLComponent {
full = true;
roleA = '';
roleB = '';
constructor(public aclSrv: ACLService, private menuSrv: MenuService) {}
private reMenu() {
this.menuSrv.resume();
}
toggleFull() {
this.full = !this.full;
this.aclSrv.setFull(this.full);
this.reMenu();
}
toggleRoleA() {
this.full = false;
this.roleA = this.roleA === 'role-a' ? '' : 'role-a';
this.aclSrv.setFull(this.full);
this.aclSrv.setRole([this.roleA]);
this.reMenu();
}
toggleRoleB() {
this.full = false;
this.roleB = this.roleB === 'role-b' ? '' : 'role-b';
this.aclSrv.setFull(this.full);
this.aclSrv.setRole([this.roleB]);
this.reMenu();
}
}
<div class="alain-default__content-title">
<h1>
Cache 缓存,
<a href="https://ng-alain.com/components/cache" target="_blank">Document</a>
</h1>
</div>
<nz-card nzTitle="Service">
<button nz-button (click)="set()">设置</button>
<button nz-button (click)="get()" class="ml-sm">获取</button>
</nz-card>
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { CacheService } from '@delon/cache';
@Component({
selector: 'app-cache',
templateUrl: './cache.component.html',
styles: [],
})
export class CacheComponent implements OnInit {
KEY = 'user';
constructor(public cache: CacheService, public msg: NzMessageService) {}
ngOnInit() {}
set() {
this.cache.set(this.KEY, +new Date());
}
get() {
this.msg.success(this.cache.getNone(this.KEY));
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ACLGuard } from '@delon/acl';
import { SimpleTableComponent } from './simple-table/simple-table.component';
import { UtilComponent } from './util/util.component';
import { PrintComponent } from './print/print.component';
import { ACLComponent } from './acl/acl.component';
import { GuardComponent } from './guard/guard.component';
import { GuardLeaveComponent } from './guard/leave.component';
import { GuardAuthComponent } from './guard/auth.component';
import { GuardAdminComponent } from './guard/admin.component';
import { CanLeaveProvide } from './guard/can-leave.provide';
import { CacheComponent } from './cache/cache.component';
import { DownFileComponent } from './downfile/downfile.component';
import { XlsxComponent } from './xlsx/xlsx.component';
import { ZipComponent } from './zip/zip.component';
import { DelonFormComponent } from './form/form.component';
import { QRComponent } from './qr/qr.component';
const routes: Routes = [
{ path: 'simple-table', component: SimpleTableComponent },
{ path: 'util', component: UtilComponent },
{ path: 'print', component: PrintComponent },
{ path: 'acl', component: ACLComponent },
{
path: 'guard',
component: GuardComponent,
children: [
{
path: 'leave',
component: GuardLeaveComponent,
canDeactivate: [CanLeaveProvide],
},
{
path: 'auth',
component: GuardAuthComponent,
canActivate: [ACLGuard],
data: { guard: 'user1' },
},
{
path: 'admin',
component: GuardAdminComponent,
canActivate: [ACLGuard],
data: { guard: 'admin' },
},
],
},
{ path: 'cache', component: CacheComponent },
{ path: 'qr', component: QRComponent },
{ path: 'downfile', component: DownFileComponent },
{ path: 'xlsx', component: XlsxComponent },
{ path: 'zip', component: ZipComponent },
{ path: 'form', component: DelonFormComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DelonRoutingModule {}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared';
import { DelonRoutingModule } from './delon-routing.module';
import { SimpleTableComponent } from './simple-table/simple-table.component';
import { UtilComponent } from './util/util.component';
import { PrintComponent } from './print/print.component';
import { ACLComponent } from './acl/acl.component';
import { CanLeaveProvide } from './guard/can-leave.provide';
import { GuardComponent } from './guard/guard.component';
import { GuardLeaveComponent } from './guard/leave.component';
import { GuardAdminComponent } from './guard/admin.component';
import { GuardAuthComponent } from './guard/auth.component';
import { CacheComponent } from './cache/cache.component';
import { DownFileComponent } from './downfile/downfile.component';
import { XlsxComponent } from './xlsx/xlsx.component';
import { ZipComponent } from './zip/zip.component';
import { DelonFormComponent } from './form/form.component';
import { QRComponent } from './qr/qr.component';
const COMPONENTS = [
SimpleTableComponent,
UtilComponent,
PrintComponent,
ACLComponent,
GuardComponent,
GuardLeaveComponent,
GuardAdminComponent,
GuardAuthComponent,
CacheComponent,
DownFileComponent,
XlsxComponent,
ZipComponent,
DelonFormComponent,
QRComponent,
];
const COMPONENTS_NOROUNT = [];
@NgModule({
imports: [CommonModule, SharedModule, DelonRoutingModule],
providers: [CanLeaveProvide],
declarations: [...COMPONENTS, ...COMPONENTS_NOROUNT],
entryComponents: COMPONENTS_NOROUNT,
})
export class DelonModule {}
<div class="alain-default__content-title">
<h1>Download a file</h1>
</div>
<nz-card nzTitle="DEMO">
<button nz-button *ngFor="let i of fileTypes" class="mr-sm" down-file [http-data]="data" http-url="assets/tmp/demo{{i}}" file-name="demo中文">{{i}}</button>
</nz-card>
import { Component } from '@angular/core';
@Component({
selector: 'app-down-file',
templateUrl: './downfile.component.html',
})
export class DownFileComponent {
fileTypes = ['.xlsx', '.docx', '.pptx', '.pdf'];
data = {
otherdata: 1,
time: new Date(),
};
}
<page-header [title]="'Page Name'"></page-header>
<nz-card>
<sf mode="search" [schema]="searchSchema" [formData]="params" (formSubmit)="st.reset($event)" (formReset)="st.reset(params)"></sf>
<st #st [data]="url" [columns]="columns" [req]="{params: params}"></st>
</nz-card>
import { Component, OnInit, ViewChild } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { STColumn, STComponent } from '@delon/abc';
import { SFSchema } from '@delon/form';
@Component({
selector: 'app-delon-form',
templateUrl: './form.component.html',
})
export class DelonFormComponent implements OnInit {
params: any = {};
url = `/user`;
@ViewChild('st')
st: STComponent;
searchSchema: SFSchema = {
properties: {
no: {
type: 'string',
title: '编号',
},
},
};
columns: STColumn[] = [
{ title: '编号', index: 'no' },
{ title: '调用次数', type: 'number', index: 'callNo' },
{ title: '头像', type: 'img', width: '50px', index: 'avatar' },
{ title: '时间', type: 'date', index: 'updatedAt' },
];
constructor(private http: _HttpClient) {}
ngOnInit() {}
}
import { Component } from '@angular/core';
@Component({
selector: 'app-guard-admin',
template: `
<p>这是一个admin页面</p>
`,
})
export class GuardAdminComponent {}
import { Component } from '@angular/core';
@Component({
selector: 'app-guard-auth',
template: `
<p>这是一个user1页面</p>
`,
})
export class GuardAuthComponent {}
import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { GuardComponent } from './guard.component';
import { Observable } from 'rxjs';
import { NzModalService } from 'ng-zorro-antd';
@Injectable()
export class CanLeaveProvide implements CanDeactivate<GuardComponent> {
constructor(private confirmSrv: NzModalService) {}
canDeactivate(
component: GuardComponent,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot,
): boolean | Observable<boolean> | Promise<boolean> {
return new Observable(observer => {
this.confirmSrv.confirm({
nzTitle: '确认要离开吗?',
nzContent: '你已经填写了部分表单离开会放弃已经填写的内容。',
nzOkText: '离开',
nzCancelText: '取消',
nzOnOk: () => {
observer.next(true);
observer.complete();
},
nzOnCancel: () => {
observer.next(false);
observer.complete();
},
});
});
}
}
<div class="alain-default__content-title">
<h1>
路由守卫
</h1>
</div>
<nz-button-group>
<button nz-button [routerLink]="['/delon/guard/leave']">
<span>离开确认页</span>
</button>
</nz-button-group>
<nz-button-group class="ml-sm">
<button nz-button (click)="setRole(true)">
<span>设置管理员</span>
</button>
<button nz-button (click)="setRole('user1')">
<span>设置员工1</span>
</button>
<button nz-button (click)="setRole('user2')">
<span>设置员工2</span>
</button>
</nz-button-group>
<nz-button-group class="ml-sm">
<button nz-button [routerLink]="['/delon/guard/auth']">
<span>需要user1</span>
</button>
<button nz-button [routerLink]="['/delon/guard/admin']">
<span>需要管理员</span>
</button>
</nz-button-group>
<p class="mb-lg">
当前ACL信息:{{ aclSrv.data | json }}
</p>
<router-outlet></router-outlet>
import { MenuService } from '@delon/theme';
import { Router } from '@angular/router';
import { Component } from '@angular/core';
import { ACLService } from '@delon/acl';
@Component({
selector: 'app-guard',
templateUrl: './guard.component.html',
})
export class GuardComponent {
constructor(public aclSrv: ACLService, private menuSrv: MenuService, private router: Router) {}
setRole(value: string | boolean) {
this.aclSrv.setFull(typeof value === 'boolean' ? value : false);
this.aclSrv.set({ role: [value as string] });
this.menuSrv.resume();
this.router.navigate(['/delon/guard']);
}
}
import { Component } from '@angular/core';
@Component({
selector: 'app-guard-leave',
template: `
<p>离开时需要确认</p>
<button nz-button [nzType]="'primary'" [routerLink]="['/logics/guard']">
<span>我要离开</span>
</button>
`,
})
export class GuardLeaveComponent {}
<div class="alain-default__content-title">
<h1>Lodop打印
<small>更多体验请至
<a href="https://ng-alain.com/components/lodop" target="_blank">ng-alain.com</a>
</small>
</h1>
</div>
<nz-card>
<nz-alert *ngIf="error" [nzType]="'warning'" [nzMessage]="message">
<ng-template #message>
请先下载
<a href="http://c-lodop.com/download.html" target="_blank">Lodop插件</a>
</ng-template>
</nz-alert>
<form *ngIf="!error" nz-form>
<nz-form-item nz-row>
<nz-form-label nz-col [nzSm]="6">打印服务器</nz-form-label>
<nz-form-control nz-col [nzSm]="18">
<nz-input-group>
<div nz-col [nzSpan]="16">
<input nz-input nzPlaceHolder="https://localhost:8443/CLodopfuncs.js" [(ngModel)]="cog.url" name="url">
</div>
<div nz-col [nzSpan]="8">
<button nz-button (click)="reload(null)">重新加载打印机</button>
</div>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row>
<nz-form-label nz-col [nzSm]="6">打印机</nz-form-label>
<nz-form-control nz-col [nzSm]="18">
<nz-select style="width:90%;" nzPlaceHolder="请选择打印机" nzShowSearch nzAllowClear [(ngModel)]="cog.printer" name="printer" (ngModelChange)="changePinter($event)">
<nz-option *ngFor="let name of pinters" [nzLabel]="name" [nzValue]="name">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row>
<nz-form-label nz-col [nzSm]="6">纸张类型</nz-form-label>
<nz-form-control nz-col [nzSm]="18">
<nz-select style="width:90%;" nzPlaceHolder="请选择纸张类型" nzShowSearch nzAllowClear [(ngModel)]="cog.paper" name="paper">
<nz-option *ngFor="let name of papers" [nzLabel]="name" [nzValue]="name">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row>
<nz-form-label nz-col [nzSm]="6">打印内容</nz-form-label>
<nz-form-control nz-col [nzSm]="18">
<textarea nz-input [(ngModel)]="cog.html" name="html" nzAutosize></textarea>
<div nz-form-extra>仅限HTML,更多类型支持请参考官网</div>
</nz-form-control>
</nz-form-item>
<nz-form-item nz-row>
<nz-form-control nz-col [nzSm]="18" [nzOffset]="6">
<button nz-button (click)="print(true)" [nzLoading]="printing">打印预览</button>
<button nz-button (click)="print()" [nzLoading]="printing">直接打印</button>
</nz-form-control>
</nz-form-item>
</form>
</nz-card>
import { Component } from '@angular/core';
import { NzMessageService, NzNotificationService } from 'ng-zorro-antd';
import { Lodop, LodopService } from '@delon/abc';
@Component({
selector: 'app-print',
templateUrl: './print.component.html',
})
export class PrintComponent {
cog: any = {
url: 'https://localhost:8443/CLodopfuncs.js',
printer: '',
paper: '',
html: `
<h1>Title</h1>
<p>这~!@#¥%……&*()——sdilfjnvn</p>
<p>这~!@#¥%……&*()——sdilfjnvn</p>
<p>这~!@#¥%……&*()——sdilfjnvn</p>
<p>这~!@#¥%……&*()——sdilfjnvn</p>
<p>这~!@#¥%……&*()——sdilfjnvn</p>
`,
};
error = false;
lodop: Lodop | null = null;
pinters: any[] = [];
papers: string[] = [];
constructor(public lodopSrv: LodopService, private msg: NzMessageService, private notify: NzNotificationService) {
this.lodopSrv.lodop.subscribe(({ lodop, ok }) => {
if (!ok) {
this.error = true;
return;
}
this.error = false;
this.msg.success(`打印机加载成功`);
this.lodop = lodop as Lodop;
this.pinters = this.lodopSrv.printer;
});
}
reload(options: any = { url: 'https://localhost:8443/CLodopfuncs.js' }) {
this.pinters = [];
this.papers = [];
this.cog.printer = '';
this.cog.paper = '';
this.lodopSrv.cog = Object.assign({}, this.cog, options);
this.error = false;
if (options === null) this.lodopSrv.reset();
}
changePinter(name: string) {
this.papers = this.lodop!.GET_PAGESIZES_LIST(name, '\n').split('\n');
}
printing = false;
print(isPrivew = false) {
const LODOP = this.lodop as Lodop;
LODOP.PRINT_INITA(10, 20, 810, 610, '测试C-Lodop远程打印四步骤');
LODOP.SET_PRINTER_INDEXA(this.cog.printer);
LODOP.SET_PRINT_PAGESIZE(0, 0, 0, this.cog.paper);
LODOP.ADD_PRINT_TEXT(1, 1, 300, 200, '下面输出的是本页源代码及其展现效果:');
LODOP.ADD_PRINT_TEXT(20, 10, '90%', '95%', this.cog.html);
LODOP.SET_PRINT_STYLEA(0, 'ItemType', 4);
LODOP.NewPageA();
LODOP.ADD_PRINT_HTM(20, 10, '90%', '95%', this.cog.html);
if (isPrivew) LODOP.PREVIEW();
else LODOP.PRINT();
}
}
<div class="alain-default__content-title">
<h1>二维码
<a href="//ng-alain.com/components/qr" target="_blank">Document</a>
</h1>
</div>
<nz-card>
<nz-row [nzGutter]="24">
<nz-col [nzSpan]="8" class="text-center">
<qr [value]="value" [background]="background" [backgroundAlpha]="backgroundAlpha" [foreground]="foreground" [foregroundAlpha]="foregroundAlpha"
[level]="level" [mime]="mime" [padding]="padding" [size]="size" style="border:1px solid #999"></qr>
</nz-col>
<nz-col [nzSpan]="16">
<form nz-form>
<nz-form-item>
<nz-form-label [nzSpan]="8">背景</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-input-group>
<div nz-col nzSpan="12">
<input nz-input type="color" [(ngModel)]="background" [ngModelOptions]="{standalone: true}">
</div>
<div nz-col nzSpan="12">
<nz-input-number [(ngModel)]="backgroundAlpha" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [ngModelOptions]="{standalone: true}"></nz-input-number>
</div>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="8">前景</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-input-group>
<div nz-col nzSpan="12">
<input nz-input type="color" [(ngModel)]="foreground" [ngModelOptions]="{standalone: true}">
</div>
<div nz-col nzSpan="12">
<nz-input-number [(ngModel)]="foregroundAlpha" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [ngModelOptions]="{standalone: true}"></nz-input-number>
</div>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="8">误差</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-select [(ngModel)]="level" [ngModelOptions]="{standalone: true}">
<nz-option nzValue="L" nzLabel="L"></nz-option>
<nz-option nzValue="M" nzLabel="M"></nz-option>
<nz-option nzValue="Q" nzLabel="Q"></nz-option>
<nz-option nzValue="H" nzLabel="H"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="8">Mime</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-select [(ngModel)]="mime" [ngModelOptions]="{standalone: true}">
<nz-option nzValue="image/png" nzLabel="image/png"></nz-option>
<nz-option nzValue="image/jpeg" nzLabel="image/jpeg"></nz-option>
<nz-option nzValue="image/gif" nzLabel="image/gif"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="8">内边距</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-input-number [(ngModel)]="padding" [ngModelOptions]="{standalone: true}" [nzMin]="0" [nzMax]="100"></nz-input-number>px
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="8">大小</nz-form-label>
<nz-form-control [nzSpan]="16">
<nz-input-number [(ngModel)]="size" [ngModelOptions]="{standalone: true}" [nzMin]="100" [nzMax]="1000" [nzStep]="padding"></nz-input-number>px
</nz-form-control>
</nz-form-item>
</form>
</nz-col>
</nz-row>
</nz-card>
import { Component } from '@angular/core';
@Component({
selector: 'app-qr',
templateUrl: './qr.component.html',
})
export class QRComponent {
value = 'https://ng-alain.com/';
background = 'white';
backgroundAlpha = 1.0;
foreground = 'black';
foregroundAlpha = 1.0;
level = 'L';
mime = 'image/png';
padding = 10;
size = 220;
}
<div class="alain-default__content-title">
<h1>
Fullscreen Table
<small>使用
<a href="//ng-alain.com/components/table" target="_blank">simple-table</a>
<a href="//ng-alain.com/components/full-content" target="_blank">full-content</a> 组合,由于 nz-table 固定表头暂不支持自适应,因此表格的展示的效果在响应式里面效果并不是特别好。</small>
</h1>
</div>
<full-content (fullscreenChange)="fullChange($event)">
<nz-card>
<div nz-row class="mb-md">
<div nz-col nzSpan="12">
<form nz-form [nzLayout]="'inline'">
<nz-form-item>
<nz-form-label nzFor="userid">User ID</nz-form-label>
<nz-form-control>
<input nz-input [(ngModel)]="args.userid" name="userid" id="userid">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control>
<button nz-button [nzType]="'primary'" (click)="st.load()" [nzLoading]="http.loading">Search</button>
<button nz-button (click)="st.load({_allow_anonymous: true})" [disabled]="http.loading">Clear</button>
</nz-form-control>
</nz-form-item>
</form>
</div>
<div nz-col nzSpan="12">
<div class="text-right">
<nz-dropdown>
<button nz-button nz-dropdown>
<span>Export</span>
<i nz-icon type="down"></i>
</button>
<ul nz-menu>
<li nz-menu-item>Excel</li>
<li nz-menu-item>JSON</li>
<li nz-menu-item>PNG</li>
</ul>
</nz-dropdown>
<button nz-button [nzType]="'default'" full-toggle class="ml-sm">Full</button>
</div>
</div>
</div>
<st #st [data]="url" [req]="{params: args}" [res]="{ reName: {list: 'results' } }" [total]="total" [ps]="ps" [columns]="columns"
[scroll]="scroll">
<ng-template st-row="events" let-item let-index="index">
<g2-mini-bar height="15" theme="mini" color="#999" borderWidth="3" [padding]="[0, 0, 0, 0]" [data]="events"></g2-mini-bar>
</ng-template>
</st>
</nz-card>
</full-content>
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { STColumn } from '@delon/abc';
import { _HttpClient } from '@delon/theme';
@Component({
selector: 'app-simple-table',
templateUrl: './simple-table.component.html',
})
export class SimpleTableComponent implements OnInit {
ps = 20;
total = 200; // mock total
args: any = { _allow_anonymous: true };
url = `https://api.randomuser.me/?results=20`;
events: any[] = [];
scroll = { y: '230px' };
columns: STColumn[] = [
{ title: 'id', index: 'id.value', type: 'checkbox' },
{ title: 'Avatar', index: 'picture.thumbnail', type: 'img', width: '80px' },
{
title: 'Name',
index: 'name.first',
width: '150px',
format: (item: any) => `${item.name.first} ${item.name.last}`,
type: 'link',
click: (item: any) => this.message.info(`${item.name.first}`),
},
{ title: 'Email', index: 'email' },
{
title: 'Gender',
index: 'gender',
type: 'yn',
ynTruth: 'female',
ynYes: '男',
ynNo: '女',
width: '120px',
},
{ title: 'Events', render: 'events', width: '90px' },
{ title: 'Registered', index: 'registered', type: 'date', width: '150px' },
{
title: 'Actions',
width: '120px',
buttons: [
{
text: 'Edit',
click: (item: any) => this.message.info(`edit [${item.id.value}]`),
if: (item: any) => item.gender === 'female',
},
{
text: 'Delete',
type: 'del',
click: (item: any) => this.message.info(`deleted [${item.id.value}]`),
},
],
},
];
constructor(public http: _HttpClient, private message: NzMessageService) {}
ngOnInit(): void {
this.http.get('/chart/visit').subscribe((res: any[]) => (this.events = res.slice(0, 8)));
}
fullChange(val: boolean) {
this.scroll = val ? { y: '350px' } : { y: '230px' };
}
}
<div class="alain-default__content-title">
<h1>
工具集
<small>@delon/util 日常用法。</small>
</h1>
</div>
<nz-row [nzGutter]="16">
<nz-col [nzSpan]="12">
<nz-card nzTitle="字符串类">
<nz-card nzType="inner" nzTitle="format">
<form nz-form>
<nz-form-item>
<nz-form-label [nzSm]="8">String</nz-form-label>
<nz-form-control [nzSm]="16">
<input nz-input [(ngModel)]="format_str" [ngModelOptions]="{standalone: true}">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8">Object</nz-form-label>
<nz-form-control [nzSm]="16">
<input nz-input [(ngModel)]="format_obj" [ngModelOptions]="{standalone: true}">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzSpan]="16" [nzOffset]="8">
<button (click)="onFormat()" nz-button>Run</button>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="8">Result</nz-form-label>
<nz-form-control [nzSm]="16">
{{format_res}}
</nz-form-control>
</nz-form-item>
</form>
</nz-card>
<nz-card nzType="inner" nzTitle="yuan">
<nz-row [nzGutter]="16">
<nz-col [nzSpan]="12">
<input type="number" nz-input [(ngModel)]="yuan_str" (ngModelChange)="onYuan($event)">
</nz-col>
<nz-col [nzSpan]="12">
<div [innerHTML]="yuan_res"></div>
</nz-col>
</nz-row>
</nz-card>
</nz-card>
</nz-col>
<nz-col [nzSpan]="12">
<nz-card nzTitle="其它类">
<button nz-button (click)="onCopy()">Copy</button>
</nz-card>
</nz-col>
</nz-row>
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { copy, format } from '@delon/util';
import { yuan } from '@shared';
@Component({
selector: 'app-util',
templateUrl: './util.component.html',
})
export class UtilComponent {
constructor(public messageSrv: NzMessageService) {}
// region: string
format_str = 'this is ${name}';
format_res = '';
format_obj = JSON.stringify({ name: 'asdf' });
onFormat() {
let obj = null;
try {
obj = JSON.parse(this.format_obj);
} catch {
this.messageSrv.error(`无法使用 JSON.parse 转换`);
return;
}
this.format_res = format(this.format_str, obj, true);
}
// yuan
yuan_str: any;
yuan_res: string;
onYuan(value: string) {
this.yuan_res = yuan(value);
}
// endregion
// region: other
content = `time ${+new Date()}
中文!@#¥%……&*`;
onCopy() {
copy(`time ${+new Date()}`).then(() => this.messageSrv.success(`success`));
}
// endregion
}
<div class="alain-default__content-title">
<h1>Import & Export excel file,
<a href="//ng-alain.com/components/xlsx" target="_blank">Document</a>
</h1>
</div>
<nz-card nzTitle="Import">
<button nz-button (click)="url()">Via Url</button>
<input type="file" (change)="change($event)" multiple="false" class="ml-sm" />
<p class="mt-sm">result: {{data | json}}</p>
</nz-card>
<nz-card nzTitle="Export">
<button nz-button (click)="download()">Export</button>
<st [data]="users" [ps]="3" [columns]="columns" class="mt-sm"></st>
</nz-card>
import { Component, OnInit } from '@angular/core';
import { XlsxService, STColumn } from '@delon/abc';
@Component({
selector: 'app-xlsx',
templateUrl: './xlsx.component.html',
})
export class XlsxComponent {
constructor(private xlsx: XlsxService) {}
data: any;
url() {
this.xlsx.import(`./assets/tmp/demo.xlsx`).then(res => (this.data = res));
}
change(e: Event) {
const file = (e.target as HTMLInputElement).files![0];
this.xlsx.import(file).then(res => (this.data = res));
}
users: any[] = Array(100)
.fill({})
.map((item: any, idx: number) => {
return {
id: idx + 1,
name: `name ${idx + 1}`,
age: Math.ceil(Math.random() * 10) + 20,
};
});
columns: STColumn[] = [
{ title: '编号', index: 'id', type: 'checkbox' },
{ title: '姓名', index: 'name' },
{ title: '年龄', index: 'age' },
];
download() {
const data = [this.columns.map(i => i.title)];
this.users.forEach(i => data.push(this.columns.map(c => i[c.index as string])));
this.xlsx.export({
sheets: [
{
data: data,
name: 'sheet name',
},
],
});
}
}
<div class="alain-default__content-title">
<h1>Read & Write zip file,
<a href="//ng-alain.com/components/zip" target="_blank">Document</a>
</h1>
</div>
<nz-card nzTitle="解压">
<button nz-button (click)="url()">Via Url</button>
<input type="file" (change)="change($event)" multiple="false" class="ml-sm" />
<ol>
<li *ngFor="let i of list">{{i | json}}</li>
</ol>
</nz-card>
<nz-card nzTitle="压缩" *ngIf="instance">
<button nz-button (click)="data.push({})" [nzType]="'primary'">new</button>
<button nz-button (click)="download()" class="ml-sm">download</button>
<nz-table [nzData]="data" [nzFrontPagination]="false" [nzShowPagination]="false" class="mt-sm">
<thead>
<tr>
<th>
<span>path</span>
</th>
<th>
<span>url</span>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let i of data; let index = index">
<td>
<input nz-input [(ngModel)]="i.path" name="path{{index}}">
</td>
<td>
<input nz-input [(ngModel)]="i.url" name="url{{index}}">
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
import { Component, OnInit } from '@angular/core';
import { ZipService } from '@delon/abc';
import * as JSZip from 'jszip';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
selector: 'app-zip',
templateUrl: './zip.component.html',
})
export class ZipComponent {
constructor(private zip: ZipService, private msg: NzMessageService) {
this.zip.create().then(ret => (this.instance = ret));
}
// region: read
list: any;
private format(data: any) {
const files = data.files;
this.list = Object.keys(files).map(key => {
return {
name: key,
dir: files[key].dir,
date: files[key].date,
};
});
}
url() {
this.zip.read(`./assets/tmp/demo.zip`).then(res => this.format(res));
}
change(e: Event) {
const file = (e.target as HTMLInputElement).files![0];
this.zip.read(file).then(res => this.format(res));
}
// endregion
// region: write
instance: JSZip | null = null;
data: { path: string; url: string }[] = [
{ path: 'demo.docx', url: 'https://ng-alain.com/assets/demo.docx' },
{
path: '小程序标志.zip',
url: 'https://wximg.gtimg.com/shake_tv/mina/standard_logo.zip',
},
];
download() {
const promises: Promise<any>[] = [];
this.data.forEach(item => {
promises.push(this.zip.pushUrl(this.instance, item.path, item.url));
});
Promise.all(promises).then(
() => {
this.zip.save(this.instance).then(() => {
this.msg.success('download success');
this.data = [];
});
},
(error: any) => {
console.warn(error);
this.msg.error(JSON.stringify(error));
},
);
}
// endregion
}
...@@ -5,9 +5,7 @@ import { _HttpClient } from '@delon/theme'; ...@@ -5,9 +5,7 @@ import { _HttpClient } from '@delon/theme';
selector: 'exception-trigger', selector: 'exception-trigger',
template: ` template: `
<div class="pt-lg"> <div class="pt-lg">
<nz-card> <nz-card> </nz-card>
<button *ngFor="let t of types" (click)="go(t)" nz-button nzType="danger">触发{{ t }}</button>
</nz-card>
</div> </div>
`, `,
}) })
......
<div class="text-center pb-lg">
<h1 class="py-md mt-sm">帮助中心</h1>
<div>帮助用户快速找到问题答案</div>
</div>
<div class="text-center">
<nz-input-group nzCompact nzSize="large">
<input [(ngModel)]="q" placeholder="请用关键词进行搜索,例如“服务器密码重置”" style="width: 50%;" nz-input>
<nz-select [(ngModel)]="type" nzSize="large" style="width:20%;">
<nz-option [nzLabel]="'不限'" [nzValue]="''"></nz-option>
<nz-option [nzLabel]="'弹性计算'" [nzValue]="'弹性计算'"></nz-option>
<nz-option [nzLabel]="'存储与CDN'" [nzValue]="'存储与CDN'"></nz-option>
<nz-option [nzLabel]="'会员服务'" [nzValue]="'会员服务'"></nz-option>
<nz-option [nzLabel]="'数据库'" [nzValue]="'数据库'"></nz-option>
</nz-select>
<button nz-button [nzType]="'primary'" (click)="search()" nzSize="large">
<span>搜索</span>
</button>
</nz-input-group>
<div class="py-sm text-grey-dark">
搜索热词:
<a class="ml-sm" (click)="quick('远程连接服务器')">远程连接服务器</a>
<a class="ml-sm" (click)="quick('挂载数据盘')">挂载数据盘</a>
<a class="ml-sm" (click)="quick('域名解析')">域名解析</a>
<a class="ml-sm" (click)="quick('域名实名认证')">域名实名认证</a>
<a class="ml-sm" (click)="quick('账号实名认证')">账号实名认证</a>
<a class="ml-sm" (click)="quick('忘记密码')">忘记密码</a>
</div>
</div>
<nz-row [nzGutter]="16" class="py-lg">
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('弹性计算')" class="d-block text-center text-primary">
<i nz-icon type="rocket" class="display-1 mb-md"></i>
<h2 class="mb0">弹性计算</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('存储与CDN')" class="d-block text-center text-red">
<i nz-icon type="hdd" class="display-1 mb-md"></i>
<h2 class="mb0">存储与CDN</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('会员服务')" class="d-block text-center text-orange">
<i nz-icon type="user" class="display-1 mb-md"></i>
<h2 class="mb0">会员服务</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('数据库')" class="d-block text-center text-purple">
<i nz-icon type="database" class="display-1 mb-md"></i>
<h2 class="mb0">数据库</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('域名与网站')" class="d-block text-center text-cyan">
<i nz-icon type="api" class="display-1 mb-md"></i>
<h2 class="mb0">域名与网站</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('网络')" class="d-block text-center text-teal">
<i nz-icon type="global" class="display-1 mb-md"></i>
<h2 class="mb0">网络</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('应用服务')" class="d-block text-center text-pink">
<i nz-icon type="appstore" class="display-1 mb-md"></i>
<h2 class="mb0">应用服务</h2>
</a>
</nz-card>
</nz-col>
<nz-col [nzXs]="12" [nzMd]="8">
<nz-card>
<a (click)="msg.info('开发者工具')" class="d-block text-center text-success">
<i nz-icon type="tool" class="display-1 mb-md"></i>
<h2 class="mb0">开发者工具</h2>
</a>
</nz-card>
</nz-col>
</nz-row>
<div class="modal-header">
<div class="modal-title">{{i.id > 0 ? '编辑' : '添加'}}-门店(基于HTML模板表单写法)</div>
</div>
<form #f="ngForm" (ngSubmit)="save()" nz-form>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">所属分销商</nz-form-label>
<nz-form-control nzSpan="8">
{{i.user_id}}
<a (click)="msgSrv.info('find')">查找用户</a>
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">门店名称</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.name" name="name" maxlength="30" required />
<p nz-form-explain>如:国美、麦当劳,不应包含地区、地址、分店名等信息,错误示例:北京国美</p>
</nz-form-control>
<nz-form-label nzSpan="4">分店名称</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.branch_name" name="branch_name" maxlength="20" required />
<p nz-form-explain>不应包含地区信息,不应与门店名有重复,错误示例:北京王府井店</p>
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">所在地</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.geo" name="geo" maxlength="50" required />
</nz-form-control>
<nz-form-label nzSpan="4">街道地址</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.address" name="address" maxlength="50" required />
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">纬度</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.lat" name="lat" required />
</nz-form-control>
<nz-form-label nzSpan="4">经度</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.lng" name="lng" required />
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">电话</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.tel" name="tel" maxlength="30" required />
</nz-form-control>
<nz-form-label nzSpan="4">门店类型</nz-form-label>
<nz-form-control nzSpan="8">
<nz-select [(ngModel)]="i.categories" name="categories" required [nzAllowClear]="false">
<nz-option *ngFor="let i of cat" [nzLabel]="i" [nzValue]="i">
</nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">推荐品</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.recommend" name="recommend" maxlength="200" placeholder="200字以内" />
</nz-form-control>
<nz-form-label nzSpan="4">特色服务</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.special" name="special" maxlength="50" placeholder="50字以内" />
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">商户简介</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.introduction" name="introduction" maxlength="300" placeholder="300字以内" />
</nz-form-control>
<nz-form-label nzSpan="4">营业时间</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input [(ngModel)]="i.open_time" name="open_time" maxlength="30" placeholder="30字以内" />
</nz-form-control>
</nz-form-item>
<nz-form-item class="mb-sm">
<nz-form-label nzSpan="4">人均价格</nz-form-label>
<nz-form-control nzSpan="8">
<nz-input-number [(ngModel)]="i.avg_price" name="avg_price" [nzMin]="0" [nzStep]="10"></nz-input-number>
</nz-form-control>
</nz-form-item>
<div class="modal-footer">
<button nz-button type="button" (click)="close()">关闭</button>
<button nz-button [disabled]="!f.form.valid || !f.form.dirty" [nzLoading]="http.loading" [nzType]="'primary'">保存</button>
</div>
</form>
<div class="alain-default__content-title">
<h1>门店</h1>
<button nz-button (click)="add()" [nzType]="'primary'">添加</button>
</div>
<form nz-form nzLayout="inline" se-container>
<se>
<nz-select [(ngModel)]="s.s" name="s" [nzAllowClear]="false">
<nz-option nzValue="" 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-option nzValue="10" nzLabel="待提交"></nz-option>
<nz-option nzValue="11" nzLabel="待审核"></nz-option>
</nz-select>
</se>
<se>
<input nz-input [(ngModel)]="s.user_id" name="user_id" placeholder="用户编号">
</se>
<se>
<input nz-input [(ngModel)]="s.q" name="q" placeholder="门店、分店名称">
</se>
<se>
<button nz-button (click)="st.reset(s)" nzType="primary">搜索</button>
</se>
</form>
<st #st class="bg-white" [columns]="columns" [data]="url" [req]="{params: s}"></st>
<page-header [title]="'资产列表'" [extra]="extra">
<form nz-form [nzLayout]="'inline'" (ngSubmit)="getData()" class="search__form">
<div nz-row [nzGutter]="{ xs: 8, sm: 8, md: 8, lg: 24, xl: 48, xxl: 48 }">
<div nz-col nzMd="8" nzSm="24">
<nz-form-item>
<nz-form-label nzFor="no">规则编号</nz-form-label>
<nz-form-control>
<input nz-input [(ngModel)]="q.no" name="no" placeholder="请输入" id="no">
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzMd="8" nzSm="24">
<nz-form-item>
<nz-form-label nzFor="status">使用状态</nz-form-label>
<nz-form-control>
<nz-select [(ngModel)]="q.status" name="status" id="status" [nzPlaceHolder]="'请选择'" [nzShowSearch]="true">
<nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
<nz-form-item>
<nz-form-label nzFor="callNo">调用次数</nz-form-label>
<nz-form-control>
<input nz-input id="callNo">
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
<nz-form-item>
<nz-form-label nzFor="updatedAt">更新日期</nz-form-label>
<nz-form-control>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
<nz-form-item>
<nz-form-label nzFor="status2">使用状态</nz-form-label>
<nz-form-control>
<nz-select [nzPlaceHolder]="'请选择'" nzId="status2" [nzShowSearch]="true">
<nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
<nz-form-item>
<nz-form-label nzFor="status3">使用状态</nz-form-label>
<nz-form-control>
<nz-select [nzPlaceHolder]="'请选择'" nzId="status3" [nzShowSearch]="true">
<nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="24">
<button nz-button type="submit" [nzType]="'primary'" [nzLoading]="loading">查询</button>
<button nz-button type="reset" (click)="reset()" class="mx-sm">重置</button>
<a (click)="expandForm=!expandForm">
{{expandForm ? '收起' : '展开'}}
<i class="anticon" [class.anticon-down]="!expandForm" [class.anticon-up]="expandForm"></i>
</a>
</div>
</div>
</form>
</page-header>
<nz-list [nzLoading]="loading" [nzDataSource]="list" [nzRenderItem]="item"
[nzGrid]="{gutter: 24, lg: 8, md: 12, sm: 24, xs: 24 }">
<ng-template #item let-item>
<nz-list-item>
<nz-card nzHoverable *ngIf="item !== null" [nzActions]="[op1]">
<ng-template #op1>
<a [routerLink]="['./detail', item.id]">查看</a>
</ng-template>
<nz-card-meta [nzAvatar]="nzAvatar" [nzTitle]="nzTitle" [nzDescription]="nzDescription">
<ng-template #nzTitle>
<a (click)="msg.success('标题:' + item.id);">{{item.name}}</a>
</ng-template>
<ng-template #nzDescription>
<ellipsis>xxxxxxxxxxxxxxxxxxxxxxxxxxxxx</ellipsis>
</ng-template>
</nz-card-meta>
</nz-card>
</nz-list-item>
</ng-template>
</nz-list>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment