This commit is contained in:
Lingzi
2022-03-29 11:26:55 +08:00
parent 86d2ac0e66
commit fb21d5fdeb
38 changed files with 1807 additions and 75 deletions

View File

@ -0,0 +1,6 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<nz-card>
<sf mode="search" [schema]="searchSchema" (formSubmit)="st.reset($event)" (formReset)="st.reset($event)"></sf>
<st #st [data]="url" [columns]="columns"></st>
</nz-card>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableCustomindexComponent } from './customindex.component';
describe('DatatableCustomindexComponent', () => {
let component: DatatableCustomindexComponent;
let fixture: ComponentFixture<DatatableCustomindexComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableCustomindexComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableCustomindexComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';
import { SFSchema } from '@delon/form';
import { ModalHelper, _HttpClient } from '@delon/theme';
@Component({
selector: 'app-datatable-customindex',
templateUrl: './customindex.component.html',
})
export class DatatableCustomindexComponent implements OnInit {
url = `/user`;
searchSchema: SFSchema = {
properties: {
no: {
type: 'string',
title: '编号'
}
}
};
@ViewChild('st') private readonly st!: STComponent;
columns: STColumn[] = [
{ title: '编号', index: 'no' },
{ title: '调用次数', type: 'number', index: 'callNo' },
{ title: '头像', type: 'img', width: '50px', index: 'avatar' },
{ title: '时间', type: 'date', index: 'updatedAt' },
{
title: '',
buttons: [
// { text: '查看', click: (item: any) => `/form/${item.id}` },
// { text: '编辑', type: 'static', component: FormEditComponent, click: 'reload' },
]
}
];
constructor(private http: _HttpClient, private modal: ModalHelper) { }
ngOnInit(): void { }
add(): void {
// this.modal
// .createStatic(FormEditComponent, { i: { id: 0 } })
// .subscribe(() => this.st.reload());
}
}

View File

@ -0,0 +1,6 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<nz-card>
<sf mode="search" [schema]="searchSchema" (formSubmit)="st.reset($event)" (formReset)="st.reset($event)"></sf>
<st #st [data]="url" [columns]="columns"></st>
</nz-card>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableCustomtableComponent } from './customtable.component';
describe('DatatableCustomtableComponent', () => {
let component: DatatableCustomtableComponent;
let fixture: ComponentFixture<DatatableCustomtableComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableCustomtableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableCustomtableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';
import { SFSchema } from '@delon/form';
import { ModalHelper, _HttpClient } from '@delon/theme';
@Component({
selector: 'app-datatable-customtable',
templateUrl: './customtable.component.html',
})
export class DatatableCustomtableComponent implements OnInit {
url = `/user`;
searchSchema: SFSchema = {
properties: {
no: {
type: 'string',
title: '编号'
}
}
};
@ViewChild('st') private readonly st!: STComponent;
columns: STColumn[] = [
{ title: '编号', index: 'no' },
{ title: '调用次数', type: 'number', index: 'callNo' },
{ title: '头像', type: 'img', width: '50px', index: 'avatar' },
{ title: '时间', type: 'date', index: 'updatedAt' },
{
title: '',
buttons: [
// { text: '查看', click: (item: any) => `/form/${item.id}` },
// { text: '编辑', type: 'static', component: FormEditComponent, click: 'reload' },
]
}
];
constructor(private http: _HttpClient, private modal: ModalHelper) { }
ngOnInit(): void { }
add(): void {
// this.modal
// .createStatic(FormEditComponent, { i: { id: 0 } })
// .subscribe(() => this.st.reload());
}
}

View File

@ -0,0 +1,6 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<nz-card>
<sf mode="search" [schema]="searchSchema" (formSubmit)="st.reset($event)" (formReset)="st.reset($event)"></sf>
<st #st [data]="url" [columns]="columns"></st>
</nz-card>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableDriverComponent } from './driver.component';
describe('DatatableDriverComponent', () => {
let component: DatatableDriverComponent;
let fixture: ComponentFixture<DatatableDriverComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableDriverComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableDriverComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';
import { SFSchema } from '@delon/form';
import { ModalHelper, _HttpClient } from '@delon/theme';
@Component({
selector: 'app-datatable-driver',
templateUrl: './driver.component.html',
})
export class DatatableDriverComponent implements OnInit {
url = `/user`;
searchSchema: SFSchema = {
properties: {
no: {
type: 'string',
title: '编号'
}
}
};
@ViewChild('st') private readonly st!: STComponent;
columns: STColumn[] = [
{ title: '编号', index: 'no' },
{ title: '调用次数', type: 'number', index: 'callNo' },
{ title: '头像', type: 'img', width: '50px', index: 'avatar' },
{ title: '时间', type: 'date', index: 'updatedAt' },
{
title: '',
buttons: [
// { text: '查看', click: (item: any) => `/form/${item.id}` },
// { text: '编辑', type: 'static', component: FormEditComponent, click: 'reload' },
]
}
];
constructor(private http: _HttpClient, private modal: ModalHelper) { }
ngOnInit(): void { }
add(): void {
// this.modal
// .createStatic(FormEditComponent, { i: { id: 0 } })
// .subscribe(() => this.st.reload());
}
}

View File

@ -0,0 +1,5 @@
<!-- 页头 -->
<page-header-wrapper [title]="'运营报表'"></page-header-wrapper>
<nz-card>
<st #st [data]="url" [columns]="columns"></st>
</nz-card>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableOwnerComponent } from './owner.component';
describe('DatatableOwnerComponent', () => {
let component: DatatableOwnerComponent;
let fixture: ComponentFixture<DatatableOwnerComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableOwnerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableOwnerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';
import { SFSchema } from '@delon/form';
import { ModalHelper, _HttpClient } from '@delon/theme';
@Component({
selector: 'app-datatable-owner',
templateUrl: './owner.component.html',
})
export class DatatableOwnerComponent implements OnInit {
url = `/user`;
searchSchema: SFSchema = {
properties: {
no: {
type: 'string',
title: '编号'
}
}
};
@ViewChild('st') private readonly st!: STComponent;
columns: STColumn[] = [
{ title: '编号', index: 'no' },
{ title: '调用次数', type: 'number', index: 'callNo' },
{ title: '头像', type: 'img', width: '50px', index: 'avatar' },
{ title: '时间', type: 'date', index: 'updatedAt' },
{
title: '',
buttons: [
// { text: '查看', click: (item: any) => `/form/${item.id}` },
// { text: '编辑', type: 'static', component: FormEditComponent, click: 'reload' },
]
}
];
constructor(private http: _HttpClient, private modal: ModalHelper) { }
ngOnInit(): void { }
add(): void {
// this.modal
// .createStatic(FormEditComponent, { i: { id: 0 } })
// .subscribe(() => this.st.reload());
}
}

View File

@ -0,0 +1,69 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'业绩量总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'司机应付总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'附加费总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'订单类型比例'">
<g2-custom delay="100" (render)="render($event)"></g2-custom>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'大区业绩完成情况'">
<g2-timeline
[data]="chartData"
[titleMap]="{ y1: '客流量', y2: '支付笔数' }"
[height]="200"
mask="MM月DD日"
[slider]="false"
></g2-timeline>
</nz-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'运单直付比例'">
<g2-pie #pie title="销售额" subTitle="销售额" [total]="total" [valueFormat]="format" [data]="salesPieData" height="294"
(clickItem)="handleClick($event)" [lineWidth]="10">
</g2-pie>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'业绩完成情况'">
<g2-bar height="200" [title]="'销售额趋势'" [data]="salesData" (clickItem)="handleClick($event)"></g2-bar>
</nz-card>
</div>
</div>

View File

@ -0,0 +1,249 @@
import { Component, ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { G2MiniAreaClickItem, G2MiniAreaData } from '@delon/chart/mini-area';
import { G2PieClickItem, G2PieComponent, G2PieData } from '@delon/chart/pie';
import { format } from 'date-fns';
import { DataService } from '../../services/data.service';
import { Chart, registerShape, Util } from '@antv/g2';
import { G2TimelineClickItem, G2TimelineData } from '@delon/chart/timeline';
@Component({
selector: 'app-datatable-dataindex',
templateUrl: './dataindex.component.html',
styleUrls: ['./dataindex.component.less']
})
export class DatatableDataindexComponent implements OnInit {
@ViewChild('pie', { static: false }) pie!: G2PieComponent;
chartData: G2TimelineData[] = [];
visitData = this.genData();
salesData = this.genData();
salesPieData: G2PieData[] = [];
total = '';
constructor(private service: DataService, private ngZone: NgZone) {
}
ngOnInit(): void {
this.refreshPie();
this.initLineData()
}
initLineData(){
for (let i = 0; i < 20; i += 1) {
this.chartData.push({
time: new Date().getTime() + 1000 * 60 * 60 * 24 * i,
y1: Math.floor(Math.random() * 100) + 1000,
y2: Math.floor(Math.random() * 100) + 10,
});
}
}
private genData(): G2MiniAreaData[] {
const beginDay = new Date().getTime();
const res: G2MiniAreaData[] = [];
for (let i = 0; i < 20; i += 1) {
res.push({
x: format(new Date(beginDay + 1000 * 60 * 60 * 24 * i), 'yyyy-MM-dd'),
y: Math.floor(Math.random() * 100) + 10,
});
}
return res;
}
refresh(): void {
this.visitData = this.genData();
}
refreshPie(): void {
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
this.salesPieData = [
{
x: '家用电器',
y: rv(),
},
{
x: '食用酒水',
y: rv(),
},
{
x: '个护健康',
y: rv(),
},
{
x: '服饰箱包',
y: rv(),
},
{
x: '母婴产品',
y: rv(),
},
];
if (Math.random() > 0.5) {
this.salesPieData.push({
x: '其他',
y: rv(),
});
}
this.total = `&yen ${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
if (this.pie) {
// 等待组件渲染
setTimeout(() => {
console.log('a')
this.pie.changeData()
});
}
}
handleClick(data: G2MiniAreaClickItem): void {
this.service.msgSrv.info(`${data.item.x} - ${data.item.y}`);
}
format(val: number): string {
return `&yen ${val.toFixed(2)}`;
}
render(el: ElementRef<HTMLDivElement>): void {
this.ngZone.runOutsideAngular(() => this.init(el.nativeElement));
}
private init(el: HTMLElement): void {
const data = [
{ item: '货源单', count: 40, percent: 0.4 },
{ item: '合同单', count: 21, percent: 0.21 },
{ item: '事例三', count: 17, percent: 0.17 },
{ item: '事例四', count: 13, percent: 0.13 },
{ item: '事例五', count: 9, percent: 0.09 },
];
const chart = new Chart({
container: el,
autoFit: true,
height: 400,
});
// 新建一个 view 用来单独渲染Annotation
const innerView = chart.createView();
chart.coordinate('theta', {
radius: 0.6,
innerRadius: 0.7,
});
chart.data(data);
chart.scale('percent', {
formatter: val => {
val = val * 100 + '%';
return val;
},
});
chart.tooltip(false);
// 声明需要进行自定义图例字段: 'item'
chart.legend('item', {
position: 'right', // 配置图例显示位置
custom: true, // 关键字段,告诉 G2要使用自定义的图例
items: data.map((obj, index) => {
return {
name: obj.item, // 对应 itemName
value: obj.percent, // 对应 itemValue
marker: {
symbol: 'square', // marker 的形状
style: {
r: 5, // marker 图形半径
fill: chart.getTheme().colors10[index], // marker 颜色,使用默认颜色,同图形对应
},
}, // marker 配置
};
}),
itemValue: {
style: {
fill: '#999',
}, // 配置 itemValue 样式
formatter: (val: any) => `${val * 100}%` // 格式化 itemValue 内容
},
});
chart
.interval()
.adjust('stack')
.position('percent')
.color('item')
.style({
fillOpacity: 1,
stroke: 'white',
lineWidth: 8,
})
.state({
active: {
style: element => {
const shape = element.shape;
return {
lineWidth: 1,
stroke: 'white',
strokeOpacity: shape.attr('fillOpacity'),
};
},
},
});
// 移除图例点击过滤交互
chart.removeInteraction('legend-filter');
chart.interaction('element-active');
chart.render();
// 监听 element 上状态的变化来动态更新 Annotation 信息
chart.on('element:statechange', (ev: any) => {
const { state, stateStatus, element } = ev.gEvent.originalEvent;
// 本示例只需要监听 active 的状态变化
if (state === 'active') {
const data = element.getData();
if (stateStatus) {
// 更新 Annotation
updateAnnotation(data);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
});
// 绘制 annotation
let lastItem: any;
function updateAnnotation(data: any) {
if (data.item !== lastItem) {
innerView.annotation().clear(true);
innerView
.annotation()
.text({
position: ['50%', '50%'],
content: data.item,
style: {
fontSize: 20,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetY: -20,
})
.text({
position: ['50%', '50%'],
content: data.count,
style: {
fontSize: 28,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetX: -10,
offsetY: 20,
})
innerView.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
innerView.annotation().clear(true);
innerView.render(true);
lastItem = null;
}
}
}

View File

@ -0,0 +1,69 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'业绩量总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'司机应付总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'附加费总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'订单类型比例'">
<g2-custom delay="100" (render)="render($event)"></g2-custom>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'大区业绩完成情况'">
<g2-timeline
[data]="chartData"
[titleMap]="{ y1: '客流量', y2: '支付笔数' }"
[height]="200"
mask="MM月DD日"
[slider]="false"
></g2-timeline>
</nz-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'运单直付比例'">
<g2-pie #pie title="销售额" subTitle="销售额" [total]="total" [valueFormat]="format" [data]="salesPieData" height="294"
(clickItem)="handleClick($event)" [lineWidth]="10">
</g2-pie>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'业绩完成情况'">
<g2-bar height="200" [title]="'销售额趋势'" [data]="salesData" (clickItem)="handleClick($event)"></g2-bar>
</nz-card>
</div>
</div>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableDataindexComponent } from './dataindex.component';
describe('DatatableDataindexComponent', () => {
let component: DatatableDataindexComponent;
let fixture: ComponentFixture<DatatableDataindexComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableDataindexComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableDataindexComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,249 @@
import { Component, ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { G2MiniAreaClickItem, G2MiniAreaData } from '@delon/chart/mini-area';
import { G2PieClickItem, G2PieComponent, G2PieData } from '@delon/chart/pie';
import { format } from 'date-fns';
import { DataindexService } from '../services/dataindex.service';
import { Chart, registerShape, Util } from '@antv/g2';
import { G2TimelineClickItem, G2TimelineData } from '@delon/chart/timeline';
@Component({
selector: 'app-datatable-dataindex',
templateUrl: './dataindex.component.html',
styleUrls: ['./dataindex.component.less']
})
export class DatatableDataindexComponent implements OnInit {
@ViewChild('pie', { static: false }) pie!: G2PieComponent;
chartData: G2TimelineData[] = [];
visitData = this.genData();
salesData = this.genData();
salesPieData: G2PieData[] = [];
total = '';
constructor(private service: DataindexService, private ngZone: NgZone) {
}
ngOnInit(): void {
this.refreshPie();
this.initLineData()
}
initLineData(){
for (let i = 0; i < 20; i += 1) {
this.chartData.push({
time: new Date().getTime() + 1000 * 60 * 60 * 24 * i,
y1: Math.floor(Math.random() * 100) + 1000,
y2: Math.floor(Math.random() * 100) + 10,
});
}
}
private genData(): G2MiniAreaData[] {
const beginDay = new Date().getTime();
const res: G2MiniAreaData[] = [];
for (let i = 0; i < 20; i += 1) {
res.push({
x: format(new Date(beginDay + 1000 * 60 * 60 * 24 * i), 'yyyy-MM-dd'),
y: Math.floor(Math.random() * 100) + 10,
});
}
return res;
}
refresh(): void {
this.visitData = this.genData();
}
refreshPie(): void {
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
this.salesPieData = [
{
x: '家用电器',
y: rv(),
},
{
x: '食用酒水',
y: rv(),
},
{
x: '个护健康',
y: rv(),
},
{
x: '服饰箱包',
y: rv(),
},
{
x: '母婴产品',
y: rv(),
},
];
if (Math.random() > 0.5) {
this.salesPieData.push({
x: '其他',
y: rv(),
});
}
this.total = `&yen ${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
if (this.pie) {
// 等待组件渲染
setTimeout(() => {
console.log('a')
this.pie.changeData()
});
}
}
handleClick(data: G2MiniAreaClickItem): void {
this.service.msgSrv.info(`${data.item.x} - ${data.item.y}`);
}
format(val: number): string {
return `&yen ${val.toFixed(2)}`;
}
render(el: ElementRef<HTMLDivElement>): void {
this.ngZone.runOutsideAngular(() => this.init(el.nativeElement));
}
private init(el: HTMLElement): void {
const data = [
{ item: '货源单', count: 40, percent: 0.4 },
{ item: '合同单', count: 21, percent: 0.21 },
{ item: '事例三', count: 17, percent: 0.17 },
{ item: '事例四', count: 13, percent: 0.13 },
{ item: '事例五', count: 9, percent: 0.09 },
];
const chart = new Chart({
container: el,
autoFit: true,
height: 400,
});
// 新建一个 view 用来单独渲染Annotation
const innerView = chart.createView();
chart.coordinate('theta', {
radius: 0.6,
innerRadius: 0.7,
});
chart.data(data);
chart.scale('percent', {
formatter: val => {
val = val * 100 + '%';
return val;
},
});
chart.tooltip(false);
// 声明需要进行自定义图例字段: 'item'
chart.legend('item', {
position: 'right', // 配置图例显示位置
custom: true, // 关键字段,告诉 G2要使用自定义的图例
items: data.map((obj, index) => {
return {
name: obj.item, // 对应 itemName
value: obj.percent, // 对应 itemValue
marker: {
symbol: 'square', // marker 的形状
style: {
r: 5, // marker 图形半径
fill: chart.getTheme().colors10[index], // marker 颜色,使用默认颜色,同图形对应
},
}, // marker 配置
};
}),
itemValue: {
style: {
fill: '#999',
}, // 配置 itemValue 样式
formatter: (val: any) => `${val * 100}%` // 格式化 itemValue 内容
},
});
chart
.interval()
.adjust('stack')
.position('percent')
.color('item')
.style({
fillOpacity: 1,
stroke: 'white',
lineWidth: 8,
})
.state({
active: {
style: element => {
const shape = element.shape;
return {
lineWidth: 1,
stroke: 'white',
strokeOpacity: shape.attr('fillOpacity'),
};
},
},
});
// 移除图例点击过滤交互
chart.removeInteraction('legend-filter');
chart.interaction('element-active');
chart.render();
// 监听 element 上状态的变化来动态更新 Annotation 信息
chart.on('element:statechange', (ev: any) => {
const { state, stateStatus, element } = ev.gEvent.originalEvent;
// 本示例只需要监听 active 的状态变化
if (state === 'active') {
const data = element.getData();
if (stateStatus) {
// 更新 Annotation
updateAnnotation(data);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
});
// 绘制 annotation
let lastItem: any;
function updateAnnotation(data: any) {
if (data.item !== lastItem) {
innerView.annotation().clear(true);
innerView
.annotation()
.text({
position: ['50%', '50%'],
content: data.item,
style: {
fontSize: 20,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetY: -20,
})
.text({
position: ['50%', '50%'],
content: data.count,
style: {
fontSize: 28,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetX: -10,
offsetY: 20,
})
innerView.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
innerView.annotation().clear(true);
innerView.render(true);
lastItem = null;
}
}
}

View File

@ -0,0 +1,69 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'业绩量总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'司机应付总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'附加费总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)">
</g2-mini-area>
</ng-template>
</g2-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'订单类型比例'">
<g2-custom delay="100" (render)="render($event)"></g2-custom>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'大区业绩完成情况'">
<g2-timeline
[data]="chartData"
[titleMap]="{ y1: '客流量', y2: '支付笔数' }"
[height]="200"
mask="MM月DD日"
[slider]="false"
></g2-timeline>
</nz-card>
</div>
</div>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'运单直付比例'">
<g2-pie #pie title="销售额" subTitle="销售额" [total]="total" [valueFormat]="format" [data]="salesPieData" height="294"
(clickItem)="handleClick($event)" [lineWidth]="10">
</g2-pie>
</nz-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="12">
<nz-card [nzTitle]="'业绩完成情况'">
<g2-bar height="200" [title]="'销售额趋势'" [data]="salesData" (clickItem)="handleClick($event)"></g2-bar>
</nz-card>
</div>
</div>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableDataindexComponent } from './dataindex.component';
describe('DatatableDataindexComponent', () => {
let component: DatatableDataindexComponent;
let fixture: ComponentFixture<DatatableDataindexComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableDataindexComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableDataindexComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,249 @@
import { Component, ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { G2MiniAreaClickItem, G2MiniAreaData } from '@delon/chart/mini-area';
import { G2PieClickItem, G2PieComponent, G2PieData } from '@delon/chart/pie';
import { format } from 'date-fns';
import { Chart, registerShape, Util } from '@antv/g2';
import { G2TimelineClickItem, G2TimelineData } from '@delon/chart/timeline';
import { DataService } from '../../../services/data.service';
@Component({
selector: 'app-datatable-curve',
templateUrl: './curve.component.html',
styleUrls: ['./curve.component.less']
})
export class DatatableDataindexComponent implements OnInit {
@ViewChild('pie', { static: false }) pie!: G2PieComponent;
chartData: G2TimelineData[] = [];
visitData = this.genData();
salesData = this.genData();
salesPieData: G2PieData[] = [];
total = '';
constructor(private service: DataService, private ngZone: NgZone) {
}
ngOnInit(): void {
this.refreshPie();
this.initLineData()
}
initLineData(){
for (let i = 0; i < 20; i += 1) {
this.chartData.push({
time: new Date().getTime() + 1000 * 60 * 60 * 24 * i,
y1: Math.floor(Math.random() * 100) + 1000,
y2: Math.floor(Math.random() * 100) + 10,
});
}
}
private genData(): G2MiniAreaData[] {
const beginDay = new Date().getTime();
const res: G2MiniAreaData[] = [];
for (let i = 0; i < 20; i += 1) {
res.push({
x: format(new Date(beginDay + 1000 * 60 * 60 * 24 * i), 'yyyy-MM-dd'),
y: Math.floor(Math.random() * 100) + 10,
});
}
return res;
}
refresh(): void {
this.visitData = this.genData();
}
refreshPie(): void {
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
this.salesPieData = [
{
x: '家用电器',
y: rv(),
},
{
x: '食用酒水',
y: rv(),
},
{
x: '个护健康',
y: rv(),
},
{
x: '服饰箱包',
y: rv(),
},
{
x: '母婴产品',
y: rv(),
},
];
if (Math.random() > 0.5) {
this.salesPieData.push({
x: '其他',
y: rv(),
});
}
this.total = `&yen ${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
if (this.pie) {
// 等待组件渲染
setTimeout(() => {
console.log('a')
this.pie.changeData()
});
}
}
handleClick(data: G2MiniAreaClickItem): void {
this.service.msgSrv.info(`${data.item.x} - ${data.item.y}`);
}
format(val: number): string {
return `&yen ${val.toFixed(2)}`;
}
render(el: ElementRef<HTMLDivElement>): void {
this.ngZone.runOutsideAngular(() => this.init(el.nativeElement));
}
private init(el: HTMLElement): void {
const data = [
{ item: '货源单', count: 40, percent: 0.4 },
{ item: '合同单', count: 21, percent: 0.21 },
{ item: '事例三', count: 17, percent: 0.17 },
{ item: '事例四', count: 13, percent: 0.13 },
{ item: '事例五', count: 9, percent: 0.09 },
];
const chart = new Chart({
container: el,
autoFit: true,
height: 400,
});
// 新建一个 view 用来单独渲染Annotation
const innerView = chart.createView();
chart.coordinate('theta', {
radius: 0.6,
innerRadius: 0.7,
});
chart.data(data);
chart.scale('percent', {
formatter: val => {
val = val * 100 + '%';
return val;
},
});
chart.tooltip(false);
// 声明需要进行自定义图例字段: 'item'
chart.legend('item', {
position: 'right', // 配置图例显示位置
custom: true, // 关键字段,告诉 G2要使用自定义的图例
items: data.map((obj, index) => {
return {
name: obj.item, // 对应 itemName
value: obj.percent, // 对应 itemValue
marker: {
symbol: 'square', // marker 的形状
style: {
r: 5, // marker 图形半径
fill: chart.getTheme().colors10[index], // marker 颜色,使用默认颜色,同图形对应
},
}, // marker 配置
};
}),
itemValue: {
style: {
fill: '#999',
}, // 配置 itemValue 样式
formatter: (val: any) => `${val * 100}%` // 格式化 itemValue 内容
},
});
chart
.interval()
.adjust('stack')
.position('percent')
.color('item')
.style({
fillOpacity: 1,
stroke: 'white',
lineWidth: 8,
})
.state({
active: {
style: element => {
const shape = element.shape;
return {
lineWidth: 1,
stroke: 'white',
strokeOpacity: shape.attr('fillOpacity'),
};
},
},
});
// 移除图例点击过滤交互
chart.removeInteraction('legend-filter');
chart.interaction('element-active');
chart.render();
// 监听 element 上状态的变化来动态更新 Annotation 信息
chart.on('element:statechange', (ev: any) => {
const { state, stateStatus, element } = ev.gEvent.originalEvent;
// 本示例只需要监听 active 的状态变化
if (state === 'active') {
const data = element.getData();
if (stateStatus) {
// 更新 Annotation
updateAnnotation(data);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
});
// 绘制 annotation
let lastItem: any;
function updateAnnotation(data: any) {
if (data.item !== lastItem) {
innerView.annotation().clear(true);
innerView
.annotation()
.text({
position: ['50%', '50%'],
content: data.item,
style: {
fontSize: 20,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetY: -20,
})
.text({
position: ['50%', '50%'],
content: data.count,
style: {
fontSize: 28,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetX: -10,
offsetY: 20,
})
innerView.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
innerView.annotation().clear(true);
innerView.render(true);
lastItem = null;
}
}
}

View File

@ -0,0 +1,46 @@
<!-- 页头 -->
<page-header-wrapper [title]="'运营报表'"></page-header-wrapper>
<nz-card nzTitle="运营报表" [nzExtra]="extraTemplate">
<ng-template #extraTemplate>
<div class="chooseBox">
<button nz-button nzType="primary" (click)="exportFun()">导出</button>
<div class="timeBox">
<nz-radio-group [(ngModel)]="mode" nzButtonStyle="solid" (ngModelChange)="changeData()">
<label nz-radio-button nzValue="year"></label>
<label nz-radio-button nzValue="month"></label>
<label nz-radio-button nzValue="date"></label>
<label nz-radio-button nzValue="define">自定义</label>
</nz-radio-group>
<div class="dateBox">
<nz-date-picker [(ngModel)]="date" [nzMode]="mode" [nzFormat]="dateFormat" *ngIf="mode !== 'define'" [nzDisabledDate]="disabledDate" (ngModelChange)="onChange($event)"></nz-date-picker>
<nz-range-picker [(ngModel)]="defineDate" [nzFormat]="dateFormat" *ngIf="mode === 'define'" [nzDisabledDate]="disabledDate" (ngModelChange)="onChange($event)"></nz-range-picker>
</div>
</div>
</div>
</ng-template>
<st #st multiSort [columns]="columns" [ps]="20" [data]="service.$api_listOperationalReportPage"
[req]="{ method: 'POST', allInBody: true, reName: { pi: 'pageIndex', ps: 'pageSize' }, params: reqParams }"
[scroll]="{ x: '1200px' }" [res]="{ reName: { list: 'data.records', total: 'data.total' } }"
[page]="{ show: true, showSize: true, pageSizes: [20, 50, 100] }" [loading]="false"></st>
</nz-card>
<nz-card nzTitle="运营报表" [nzExtra]="extraTemplate">
<ng-template #extraTemplate>
<div class="chooseBox">
<button nz-button nzType="primary" (click)="exportFun()">导出</button>
<div class="timeBox">
<nz-radio-group [(ngModel)]="mode" nzButtonStyle="solid" (ngModelChange)="changeData()">
<label nz-radio-button nzValue="year"></label>
<label nz-radio-button nzValue="month"></label>
</nz-radio-group>
<div class="dateBox">
<nz-date-picker [nzDisabledDate]="disabledDate" [nzMode]="mode" (ngModelChange)="onChange($event)"></nz-date-picker>
</div>
</div>
</div>
</ng-template>
</nz-card>
<nz-card nzTitle="运单状态分布">
<app-opeationtable-pie></app-opeationtable-pie>
</nz-card>

View File

@ -0,0 +1,11 @@
.chooseBox{
display: flex;
}
.timeBox{
display: flex;
margin: 0 0 0 10px;
}
.dateBox{
display: inline-block;
margin: 0 0 0 10px;
}

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableOperationtableComponent } from './operationtable.component';
describe('DatatableOperationtableComponent', () => {
let component: DatatableOperationtableComponent;
let fixture: ComponentFixture<DatatableOperationtableComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableOperationtableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableOperationtableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,89 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';
import { DatePipe, _HttpClient } from '@delon/theme';
import { DataService } from '../../services/data.service';
import { differenceInCalendarDays } from 'date-fns';
@Component({
selector: 'app-datatable-operationtable',
templateUrl: './operationtable.component.html',
styleUrls: ['./operationtable.component.less'],
providers: [DatePipe]
})
export class DatatableOperationtableComponent implements OnInit {;
type = 1;
mode = 'year';
date: any = null;
defineDate = [];
time: any = []
dateFormat = 'yyyy-MM-dd';
today = new Date();
@ViewChild('st') private readonly st!: STComponent;
columns: STColumn[] = [
{ title: '运营主体', index: 'networkTransporterName', className: 'text-center' },
{ title: '订单数', index: 'zsl', className: 'text-center' },
{ title: '应收金额', index: 'yingsje', className: 'text-center' },
{ title: '承运数', index: 'cys', className: 'text-center' },
{ title: '应付运费', index: 'yingfyf', className: 'text-center' },
{ title: '运量(吨)', index: 'yl', className: 'text-center' },
{ title: '待接单数', index: 'djd', className: 'text-center' },
{ title: '在途数', index: 'ysz', className: 'text-center' },
{ title: '运输完成', index: 'yswc', className: 'text-center' },
{ title: '已收金额', index: 'yisje', className: 'text-center' },
{ title: '已付运费', index: 'yifyf', className: 'text-center' }
];
/**
* 查询参数
*/
get reqParams() {
if(this.mode === 'year') {
this.type = 1
} else if(this.mode === 'month') {
this.type = 2
} else if(this.mode === 'date') {
this.type = 3
} else {
this.type = 4
}
let params: any = {
time: this.time,
type: this.type
};
delete params._$expand;
return { ...params };
}
constructor(public service: DataService, private datePipe: DatePipe) { }
ngOnInit(): void { }
changeData(){
if(this.mode === 'year') {
this.dateFormat = 'yyyy'
} else if(this.mode === 'month') {
this.dateFormat = 'yyyy-MM'
} else {
this.dateFormat = 'yyyy-MM-dd'
}
}
onChange(result: any) {
if(this.mode === 'year') {
this.time = [this.datePipe.transform(this.date, 'yyyy') + '-01-01 00:00:00']
} else if(this.mode === 'month') {
this.time = [this.datePipe.transform(this.date, 'yyyy-MM') + '-01 00:00:00']
} else if(this.mode === 'date') {
this.time = [this.datePipe.transform(this.date, 'yyyy-MM-dd') + ' 00:00:00']
} else{
this.time = [this.datePipe.transform(this.defineDate[0], 'yyyy-MM-dd') + '00:00:00', this.datePipe.transform(this.defineDate[1], 'yyyy-MM-dd') + ' 00:00:00']
}
this.st.reload({ ...this.reqParams });
}
disabledDate = (current: Date): boolean =>
// Can not select days before today and today
differenceInCalendarDays(current, this.today) > 0;
exportFun(){
}
}

View File

@ -0,0 +1 @@
<g2-custom delay="100" (render)="render($event)"></g2-custom>

View File

@ -0,0 +1,24 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { DatatableDataindexComponent } from './dataindex.component';
describe('DatatableDataindexComponent', () => {
let component: DatatableDataindexComponent;
let fixture: ComponentFixture<DatatableDataindexComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DatatableDataindexComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DatatableDataindexComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,252 @@
import { Component, ElementRef, NgZone, OnInit, ViewChild } from '@angular/core';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { G2MiniAreaClickItem, G2MiniAreaData } from '@delon/chart/mini-area';
import { G2PieClickItem, G2PieComponent, G2PieData } from '@delon/chart/pie';
import { format } from 'date-fns';
import { Chart, registerShape, Util } from '@antv/g2';
import { G2TimelineClickItem, G2TimelineData } from '@delon/chart/timeline';
import { DataService } from '../../../services/data.service';
@Component({
selector: 'app-opeationtable-pie',
templateUrl: './pie.component.html',
styleUrls: ['./pie.component.less']
})
export class OperationtablePieComponent implements OnInit {
@ViewChild('pie', { static: false }) pie!: G2PieComponent;
chartData: G2TimelineData[] = [];
visitData = this.genData();
salesData = this.genData();
salesPieData: G2PieData[] = [];
total = '';
constructor(private service: DataService, private ngZone: NgZone) {
}
ngOnInit(): void {
this.refreshPie();
this.initLineData()
}
initLineData() {
for (let i = 0; i < 20; i += 1) {
this.chartData.push({
time: new Date().getTime() + 1000 * 60 * 60 * 24 * i,
y1: Math.floor(Math.random() * 100) + 1000,
y2: Math.floor(Math.random() * 100) + 10,
});
}
}
private genData(): G2MiniAreaData[] {
const beginDay = new Date().getTime();
const res: G2MiniAreaData[] = [];
for (let i = 0; i < 20; i += 1) {
res.push({
x: format(new Date(beginDay + 1000 * 60 * 60 * 24 * i), 'yyyy-MM-dd'),
y: Math.floor(Math.random() * 100) + 10,
});
}
return res;
}
refresh(): void {
this.visitData = this.genData();
}
refreshPie(): void {
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
this.salesPieData = [
{
x: '家用电器',
y: rv(),
},
{
x: '食用酒水',
y: rv(),
},
{
x: '个护健康',
y: rv(),
},
{
x: '服饰箱包',
y: rv(),
},
{
x: '母婴产品',
y: rv(),
},
];
if (Math.random() > 0.5) {
this.salesPieData.push({
x: '其他',
y: rv(),
});
}
this.total = `&yen ${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
if (this.pie) {
// 等待组件渲染
setTimeout(() => {
console.log('a')
this.pie.changeData()
});
}
}
handleClick(data: G2MiniAreaClickItem): void {
this.service.msgSrv.info(`${data.item.x} - ${data.item.y}`);
}
format(val: number): string {
return `&yen ${val.toFixed(2)}`;
}
render(el: ElementRef<HTMLDivElement>): void {
this.ngZone.runOutsideAngular(() => this.init(el.nativeElement));
}
private init(el: HTMLElement): void {
const data = [
{ item: '货源单', count: 40, percent: 0.4 },
{ item: '合同单', count: 21, percent: 0.21 },
{ item: '事例三', count: 17, percent: 0.17 },
{ item: '事例四', count: 13, percent: 0.13 },
{ item: '事例五', count: 9, percent: 0.09 },
];
const chart = new Chart({
container: el,
autoFit: true,
height: 400,
});
// 新建一个 view 用来单独渲染Annotation
const innerView = chart.createView();
chart.coordinate('theta', {
radius: 0.6,
innerRadius: 0.7,
});
chart.data(data);
chart.scale('percent', {
formatter: val => {
val = val * 100 + '%';
return val;
},
});
chart.tooltip(false);
// 声明需要进行自定义图例字段: 'item'
chart.legend('item', {
position: 'right', // 配置图例显示位置
custom: true, // 关键字段,告诉 G2要使用自定义的图例
items: data.map((obj, index) => {
return {
name: obj.item, // 对应 itemName
value: obj.percent, // 对应 itemValue
marker: {
symbol: 'square', // marker 的形状
style: {
r: 5, // marker 图形半径
fill: chart.getTheme().colors10[index], // marker 颜色,使用默认颜色,同图形对应
},
}, // marker 配置
};
}),
itemValue: {
style: {
fill: '#999',
}, // 配置 itemValue 样式
formatter: (val: any) => `${val * 100}%` // 格式化 itemValue 内容
},
});
const interval = chart
.interval()
.adjust('stack')
.position('percent')
.color('item')
.style({
fillOpacity: 1,
stroke: 'white',
lineWidth: 8,
})
.state({
active: {
style: element => {
const shape = element.shape;
return {
lineWidth: 1,
stroke: 'white',
strokeOpacity: shape.attr('fillOpacity'),
};
},
},
});
// 移除图例点击过滤交互
chart.removeInteraction('legend-filter');
chart.interaction('element-active');
chart.render();
// 默认选择
interval.elements[0].setState('selected', true);
// 监听 element 上状态的变化来动态更新 Annotation 信息
chart.on('element:statechange', (ev: any) => {
const { state, stateStatus, element } = ev.gEvent.originalEvent;
// 本示例只需要监听 active 的状态变化
if (state === 'active') {
const data = element.getData();
if (stateStatus) {
// 更新 Annotation
updateAnnotation(data);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
});
// 绘制 annotation
let lastItem: any;
function updateAnnotation(data: any) {
if (data.item !== lastItem) {
innerView.annotation().clear(true);
innerView
.annotation()
.text({
position: ['50%', '50%'],
content: data.item,
style: {
fontSize: 20,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetY: -20,
})
.text({
position: ['50%', '50%'],
content: data.count,
style: {
fontSize: 28,
fill: '#8c8c8c',
textAlign: 'center',
},
offsetX: -10,
offsetY: 20,
})
innerView.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
innerView.annotation().clear(true);
innerView.render(true);
lastItem = null;
}
}
}

View File

@ -1,32 +0,0 @@
<!-- 页头 -->
<page-header-wrapper [title]="'数据报表'"></page-header-wrapper>
<div nz-row [nzGutter]="16">
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)"></g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)"></g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)"></g2-mini-area>
</ng-template>
</g2-card>
</div>
<div nz-col class="gutter-row" [nzSpan]="6">
<g2-card [title]="'客户预存款总额'" [bordered]="true" [total]="'¥ 126,560.00'" [footer]="footer" contentHeight="46">
<ng-template #footer>
<g2-mini-area line color="#cceafe" height="45" [data]="visitData" (clickItem)="handleClick($event)"></g2-mini-area>
</ng-template>
</g2-card>
</div>
</div>

View File

@ -1,37 +0,0 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { G2MiniAreaClickItem, G2MiniAreaData } from '@delon/chart/mini-area';
import { format } from 'date-fns';
@Component({
selector: 'app-datatable-dataindex',
templateUrl: './dataindex.component.html',
styleUrls: ['./dataindex.component.less']
})
export class DatatableDataindexComponent implements OnInit {
visitData = this.genData();
constructor(private http: _HttpClient, private modal: ModalHelper) { }
ngOnInit(): void { }
private genData(): G2MiniAreaData[] {
const beginDay = new Date().getTime();
const res: G2MiniAreaData[] = [];
for (let i = 0; i < 20; i += 1) {
res.push({
x: format(new Date(beginDay + 1000 * 60 * 60 * 24 * i), 'yyyy-MM-dd'),
y: Math.floor(Math.random() * 100) + 10,
});
}
return res;
}
refresh(): void {
this.visitData = this.genData();
}
handleClick(data: G2MiniAreaClickItem): void {
//this.msg.info(`${data.item.x} - ${data.item.y}`);
}
}

View File

@ -1,10 +1,19 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DatatableDataindexComponent } from './dataindex/dataindex.component';
import { DatatableCustomtableComponent } from './components/customtable/customtable.component';
import { DatatableCustomindexComponent } from './components/customtable/customindex/customindex.component';
import { DatatableOwnerComponent } from './components/customtable/owner/owner.component';
import { DatatableDriverComponent } from './components/customtable/driver/driver.component';
import { DatatableOperationtableComponent } from './components/operationtable/operationtable.component';
import { DatatableDataindexComponent } from './components/dataindex/dataindex.component';
const routes: Routes = [
{ path: 'dataindex', component: DatatableDataindexComponent }];
{ path: 'dataindex', component: DatatableDataindexComponent },
{ path: 'customtable', component: DatatableCustomtableComponent },
{ path: 'customindex', component: DatatableCustomindexComponent },
{ path: 'owner', component: DatatableOwnerComponent },
{ path: 'driver', component: DatatableDriverComponent },
{ path: 'operationtable', component: DatatableOperationtableComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],

View File

@ -1,10 +1,23 @@
import { NgModule, Type } from '@angular/core';
import { SharedModule, SHARED_G2_MODULES } from '@shared';
import { DatatableRoutingModule } from './datatable-routing.module';
import { DatatableDataindexComponent } from './dataindex/dataindex.component';
import { DatatableCustomtableComponent } from './components/customtable/customtable.component';
import { DatatableCustomindexComponent } from './components/customtable/customindex/customindex.component';
import { DatatableOwnerComponent } from './components/customtable/owner/owner.component';
import { DatatableDriverComponent } from './components/customtable/driver/driver.component';
import { DatatableOperationtableComponent } from './components/operationtable/operationtable.component';
import { DatatableDataindexComponent } from './components/dataindex/dataindex.component';
import { OperationtablePieComponent } from './components/operationtable/pie/pie.component';
const COMPONENTS: Type<void>[] = [
DatatableDataindexComponent];
DatatableDataindexComponent,
DatatableCustomtableComponent,
DatatableCustomindexComponent,
DatatableOwnerComponent,
DatatableDriverComponent,
DatatableOperationtableComponent,
OperationtablePieComponent
];
@NgModule({
imports: [

View File

@ -0,0 +1,30 @@
/*
* @Description :
* @Version : 1.0
* @Author : Shiming
* @Date : 2021-12-27 10:30:56
* @LastEditors : Shiming
* @LastEditTime : 2022-01-18 17:14:59
* @FilePath : \\tms-obc-web\\src\\app\\routes\\account\\services\\account.service.ts
* Copyright (C) 2022 huzhenhong. All rights reserved.
*/
import { Injectable, Injector } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { map } from 'rxjs/operators';
import { BaseService } from 'src/app/shared/services/core/base.service';
import { EAFileUtil } from 'src/app/shared/utils/file.util';
@Injectable({
providedIn: 'root',
})
export class DataService extends BaseService {
// 查询运营报表
$api_listOperationalReportPage = `/api/sdc/report/listOperationalReportPage`;
constructor(public injector: Injector) {
super(injector);
}
}

View File

@ -3,6 +3,7 @@ import { G2MiniAreaModule } from '@delon/chart/mini-area';
import { G2PieModule } from '@delon/chart/pie';
import { G2TimelineModule } from '@delon/chart/timeline';
import { G2CardModule } from '@delon/chart/card';
import { G2CustomModule } from '@delon/chart/custom';
export const SHARED_G2_MODULES = [G2BarModule, G2PieModule, G2TimelineModule, G2MiniAreaModule, G2CardModule];
export const SHARED_G2_MODULES = [G2BarModule, G2PieModule, G2TimelineModule, G2MiniAreaModule, G2CardModule, G2CustomModule];