Skip to content

Commit 2fecca7

Browse files
committed
feat:add tabs widget
1 parent 191447f commit 2fecca7

File tree

7 files changed

+184
-50
lines changed

7 files changed

+184
-50
lines changed

packages/client/src/app/core/startup/startup.service.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ACLService } from '@delon/acl';
88
import { TranslateService } from '@ngx-translate/core';
99
import { I18NService } from '../i18n/i18n.service';
1010
import { CoreService } from 'generated';
11+
import * as treeify from 'array-to-tree';
1112
/**
1213
* 用于应用启动时
1314
* 一般用来获取应用所需要的基础数据等
@@ -32,14 +33,14 @@ export class StartupService {
3233
zip(
3334
this.httpClient.get(`assets/i18n/${this.i18n.defaultLang}.json`),
3435
this.coreService.settingGetSettingsByName('main'),
35-
// this.coreService.menuGetUserMenus(),
36+
this.coreService.menuGetUserMenus(),
3637
).pipe(
3738
// 接收其他拦截器后产生的异常消息
38-
catchError(([langData, settingsData]) => {
39+
catchError(([langData, settingsData, menuData]) => {
3940
resolve(null);
40-
return [langData, settingsData];
41+
return [langData, settingsData, menuData];
4142
})
42-
).subscribe(([langData, settings]) => {
43+
).subscribe(([langData, settings, menuData]) => {
4344
// setting language data
4445
this.translate.setTranslation(this.i18n.defaultLang, langData);
4546
this.translate.setDefaultLang(this.i18n.defaultLang);
@@ -53,29 +54,29 @@ export class StartupService {
5354
// 设置页面标题的后缀
5455
this.titleService.suffix = settings.name;
5556

56-
// if (menuData && Array.isArray(menuData)) {
57-
// const menus = menuData.map((item) => {
58-
// return {
59-
// id: item.id,
60-
// text: item.name,
61-
// group: item.group,
62-
// icon: item.icon,
63-
// link: item.link,
64-
// parent: item.parent
65-
// };
66-
// });
57+
if (menuData && Array.isArray(menuData)) {
58+
const menus = menuData.map((item) => {
59+
return {
60+
id: item.id,
61+
text: item.name,
62+
group: item.group,
63+
icon: item.icon,
64+
link: item.link,
65+
parent: item.parent
66+
};
67+
});
6768

68-
// const tree = treeify(menus, {
69-
// parentProperty: 'parent',
70-
// customID: 'id'
71-
// });
69+
const tree = treeify(menus, {
70+
parentProperty: 'parent',
71+
customID: 'id'
72+
});
7273

73-
// this.menuService.add([{
74-
// text: '主导航',
75-
// group: true,
76-
// children: tree
77-
// }]);
78-
// }
74+
this.menuService.add([{
75+
text: '主导航',
76+
group: true,
77+
children: tree
78+
}]);
79+
}
7980
},
8081
() => { },
8182
() => {

packages/client/src/app/layout/default/header/header.component.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Component, ViewChild, OnInit } from '@angular/core';
22
import { SettingsService, MenuService } from '@delon/theme';
33
import { CoreService } from 'generated';
44
import * as treeify from 'array-to-tree';
5+
import { StartupService } from '@core/startup/startup.service';
56

67
@Component({
78
selector: 'app-header',
@@ -15,33 +16,36 @@ export class HeaderComponent implements OnInit {
1516
public settings: SettingsService,
1617
public menuService: MenuService,
1718
public coreService: CoreService,
19+
public startupService: StartupService,
1820

1921
) { }
2022
async ngOnInit() {
21-
this.menuService.clear();
22-
const menuData = await this.coreService.menuGetUserMenus().toPromise();
23-
if (menuData && Array.isArray(menuData)) {
24-
const menus = menuData.map((item) => {
25-
return {
26-
id: item.id,
27-
text: item.name,
28-
group: item.group,
29-
icon: item.icon,
30-
link: item.link,
31-
parent: item.parent
32-
};
33-
});
34-
const tree = treeify(menus, {
35-
parentProperty: 'parent',
36-
customID: 'id'
37-
});
23+
// this.menuService.clear();
24+
// this.startupService.load();
25+
// this.menuService.clear();
26+
// const menuData = await this.coreService.menuGetUserMenus().toPromise();
27+
// if (menuData && Array.isArray(menuData)) {
28+
// const menus = menuData.map((item) => {
29+
// return {
30+
// id: item.id,
31+
// text: item.name,
32+
// group: item.group,
33+
// icon: item.icon,
34+
// link: item.link,
35+
// parent: item.parent
36+
// };
37+
// });
38+
// const tree = treeify(menus, {
39+
// parentProperty: 'parent',
40+
// customID: 'id'
41+
// });
3842

39-
this.menuService.add([{
40-
text: '主导航',
41-
group: true,
42-
children: tree
43-
}]);
44-
}
43+
// this.menuService.add([{
44+
// text: '主导航',
45+
// group: true,
46+
// children: tree
47+
// }]);
48+
// }
4549
}
4650
toggleCollapsedSidebar() {
4751
this.settings.setLayout('collapsed', !this.settings.layout.collapsed);

packages/client/src/app/pages/login/login.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SettingsService } from '@delon/theme';
55
import { NzMessageService } from 'ng-zorro-antd';
66
import { SocialService, DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
77
import { UserService } from '../../services/user.service';
8+
import { StartupService } from '@core/startup/startup.service';
89

910
@Component({
1011
selector: 'app-pages-login',
@@ -26,7 +27,7 @@ export class CustomLoginComponent implements OnDestroy {
2627
private router: Router,
2728
public msg: NzMessageService,
2829
public userService: UserService,
29-
private settingsService: SettingsService
30+
private start: StartupService
3031
) {
3132
this.form = fb.group({
3233
userName: [null, [Validators.required, Validators.minLength(5)]],
@@ -47,6 +48,8 @@ export class CustomLoginComponent implements OnDestroy {
4748
password: this.password.value
4849
});
4950

51+
this.start.load();
52+
5053
if (res) {
5154
this.router.navigate(['/']);
5255
} else {

packages/client/src/app/shared/json-schema/json-schema.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ChoicesWidgetComponent } from '@shared/json-schema/widgets/choices/choi
1212
import { ImageWidgetComponent } from '@shared/json-schema/widgets/image/image.widget';
1313
import { AvatarWidgetComponent } from '@shared/json-schema/widgets/avatar/avatar.widget';
1414
import { UmeditorWidget } from '@shared/json-schema/widgets/umeditor/umeditor.widget';
15+
import { TabsWidgetComponent } from '@shared/json-schema/widgets/tabs/tabs.widget';
1516

1617
export const SCHEMA_THIRDS_COMPONENTS = [
1718
TinymceWidget,
@@ -24,6 +25,7 @@ export const SCHEMA_THIRDS_COMPONENTS = [
2425
ChoicesWidgetComponent,
2526
ImageWidgetComponent,
2627
AvatarWidgetComponent,
28+
TabsWidgetComponent,
2729
];
2830

2931
@NgModule({
@@ -49,5 +51,6 @@ export class JsonSchemaModule {
4951
widgetRegistry.register(ImageWidgetComponent.KEY, ImageWidgetComponent);
5052
widgetRegistry.register(AvatarWidgetComponent.KEY, AvatarWidgetComponent);
5153
widgetRegistry.register(UmeditorWidget.KEY, UmeditorWidget);
54+
widgetRegistry.register(TabsWidgetComponent.KEY, TabsWidgetComponent);
5255
}
5356
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { Component, OnInit, ChangeDetectorRef, Inject } from '@angular/core';
2+
import { ControlWidget, SFSchemaEnum, SFSchema, SFUISchemaItem, SFComponent, SFSchemaEnumType, SFGridSchema, ObjectLayoutWidget, FormProperty } from '@delon/form';
3+
import { getData } from './../../util';
4+
// tslint:disable-next-line:import-blacklist
5+
import { of, Observable } from 'rxjs';
6+
import { delay } from 'rxjs/operators';
7+
import { HttpClient } from '@angular/common/http';
8+
9+
@Component({
10+
selector: 'sf-tabs',
11+
template:
12+
`
13+
<nz-tabset (nzSelectChange)="queryChange([$event])">
14+
<nz-tab *ngFor="let tab of tabs" [nzTitle]="titleTemplate">
15+
<ng-template #titleTemplate>
16+
{{tab.title}}
17+
</ng-template>
18+
</nz-tab>
19+
</nz-tabset>
20+
<div>
21+
<div nz-row [nzGutter]="16">
22+
<ng-container *ngIf="grid; else noGrid">
23+
<nz-row [nzGutter]="grid.gutter">
24+
<ng-container *ngFor="let i of props[currentIndex]">
25+
<ng-container *ngIf="i.property.visible">
26+
<nz-col
27+
[nzSpan]="i.grid.span" [nzOffset]="i.grid.offset"
28+
[nzXs]="i.grid.xs" [nzSm]="i.grid.sm" [nzMd]="i.grid.md"
29+
[nzLg]="i.grid.lg" [nzXl]="i.grid.xl" [nzXXl]="i.grid.xxl">
30+
<sf-item [formProperty]="i.property" [fixed-label]="i.spanLabelFixed"></sf-item>
31+
</nz-col>
32+
</ng-container>
33+
</ng-container>
34+
</nz-row>
35+
</ng-container>
36+
<ng-template #noGrid>
37+
<ng-container *ngFor="let i of props[currentIndex]">
38+
<ng-container *ngIf="i.property.visible">
39+
<sf-item [formProperty]="i.property" [fixed-label]="i.spanLabelFixed"></sf-item>
40+
</ng-container>
41+
</ng-container>
42+
</ng-template>
43+
</div>
44+
</div>
45+
`,
46+
preserveWhitespaces: false,
47+
48+
})
49+
export class TabsWidgetComponent extends ObjectLayoutWidget implements OnInit {
50+
51+
grid: SFGridSchema;
52+
tabs: any = [];
53+
static readonly KEY = 'tabs';
54+
currentIndex = 0;
55+
props: any = {};
56+
57+
constructor(
58+
@Inject(ChangeDetectorRef) public readonly cd: ChangeDetectorRef,
59+
@Inject(SFComponent) public readonly sfComp: SFComponent,
60+
public client: HttpClient,
61+
) {
62+
super(cd, sfComp);
63+
}
64+
65+
ngOnInit(): void {
66+
this.grid = this.ui.grid;
67+
this.tabs = this.ui.tabs || [];
68+
this.tabs.forEach((tab, index) => {
69+
this.props[index] = this.props[index] || [];
70+
if (Array.isArray(tab.fields)) {
71+
tab.fields.forEach(element => {
72+
const item = this.getFormProperty(element);
73+
this.props[index].push(item);
74+
});
75+
}
76+
});
77+
78+
}
79+
80+
getFormProperty(key) {
81+
const property = this.formProperty.properties[key] as FormProperty;
82+
property.ui = property.ui || {};
83+
84+
// to fixed ui widget default set by parent.
85+
if (property.ui.widget === this.ui.widget) {
86+
property.ui.widget = property.type;
87+
}
88+
89+
const item = {
90+
property: property,
91+
grid: property.ui.grid || this.grid || {},
92+
spanLabelFixed: property.ui.spanLabelFixed,
93+
};
94+
return item;
95+
}
96+
97+
98+
queryChange(list: any) {
99+
this.currentIndex = list[0].index;
100+
}
101+
}

packages/server/src/modules/core/appearance/setting.appearance.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const profile: SFSchema = {
2020
}
2121
},
2222
},
23+
avatar2: {
24+
title: '头像',
25+
type: t.string
26+
},
2327
nick: {
2428
title: '昵称',
2529
type: t.string,
@@ -63,10 +67,27 @@ const profile: SFSchema = {
6367
},
6468
required: ['nick', 'email', 'mobile'],
6569
ui: {
70+
widget: w.tabs,
6671
spanLabelFixed: 100,
6772
grid: {
6873
span: 8
69-
}
74+
},
75+
tabs: [{
76+
title: '基本信息',
77+
fields: [
78+
'avatar',
79+
'nick',
80+
]
81+
}, {
82+
title: '联系信息',
83+
fields: [
84+
'email',
85+
'mobile',
86+
'siteUrl',
87+
'company',
88+
'address',
89+
]
90+
}]
7091
}
7192
};
7293

packages/server/src/types/appearance.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export enum WidgetTypes {
4343
choices = 'choices',
4444
image = 'image',
4545
avatar = 'avatar',
46+
tabs = 'tabs',
4647
}
4748

4849
export interface ColumnSets {

0 commit comments

Comments
 (0)