Files
bbq/src/app/routes/datatable/components/dataindex/dataindex.component.ts
Taric Xin 69c846b93a edit
2022-04-21 16:40:56 +08:00

462 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ChangeDetectorRef, 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';
import { CurrencyPipe } from '@angular/common';
import { LOGS } from '_mock';
import { G2CustomComponent } from '@delon/chart/custom';
import { G2BarData } from '@delon/chart/bar';
import { GeometryLabelCfg } from '@antv/g2/lib/interface';
@Component({
selector: 'app-datatable-dataindex',
templateUrl: './dataindex.component.html',
styleUrls: ['./dataindex.component.less'],
providers: [CurrencyPipe]
})
export class DatatableDataindexComponent implements OnInit {
@ViewChild('g2custom', { static: false }) g2custom!: G2CustomComponent;
@ViewChild('RegionalPerforman', { static: false }) RegionalPerforman!: G2CustomComponent;
@ViewChild('BillDirectProportion', { static: false }) BillDirectProportion!: G2CustomComponent;
@ViewChild('SaleProportion', { static: false }) SaleProportion!: G2CustomComponent;
salesData: any[] = [];
totalAdvanceDeposit: { totalAmount: string; list: G2MiniAreaData[] } = { totalAmount: '0', list: this.genData() };
totalPerformanceVolume: { totalAmount: string; list: G2MiniAreaData[] } = { totalAmount: '0', list: this.genData() };
totalFreight: { totalAmount: string; list: G2MiniAreaData[] } = { totalAmount: '0', list: this.genData() };
totalSurcharge: { totalAmount: string; list: G2MiniAreaData[] } = { totalAmount: '0', list: this.genData() };
billTypeDatas: any = [
{ item: '货源单', count: 0, percent: 0 },
{ item: '合同单', count: 0, percent: 0 }
];
regionalPerformanceCompletion: DataPerformanceTrendVO[] = [];
constructor(private service: DataService, private currency: CurrencyPipe) {}
ngOnInit(): void {
this.initMiniAreaData();
this.initOthersData();
}
private initMiniAreaData() {
// 客户预存款总额
this.service.request(this.service.$api_total_advance_deposit).subscribe((res: DataTotalVO) => {
if (res) {
this.totalAdvanceDeposit = this.formatMiniAreaData(res);
}
});
// 业绩量总额
this.service.request(this.service.$api_total_performance_volume).subscribe((res: DataTotalVO) => {
if (res) {
this.totalPerformanceVolume = this.formatMiniAreaData(res);
}
});
// 司机应付总额
this.service.request(this.service.$api_total_freight).subscribe((res: DataTotalVO) => {
if (res) {
this.totalFreight = this.formatMiniAreaData(res);
}
});
// 业绩量总额
this.service.request(this.service.$api_total_surcharge).subscribe((res: DataTotalVO) => {
if (res) {
this.totalSurcharge = this.formatMiniAreaData(res);
}
});
}
private initOthersData() {
// 订单类型比例
this.service.request(this.service.$api_getBillTypeProportion).subscribe(res => {
if (res) {
this.billTypeDatas = this.formatCoordinateData(res);
this.initBillChart(this.g2custom['el'].nativeElement as any);
}
});
// 大区业绩完成情况
this.service.request(this.service.$api_getBillAmount).subscribe((res: DataPerformanceTrendVO[]) => {
if (res) {
this.regionalPerformanceCompletion = res.map(item => ({ ...item, time: new Date(item.time)?.getTime() }));
this.initRegionalPerformanceChart(this.RegionalPerforman['el'].nativeElement as any, this.regionalPerformanceCompletion);
}
});
// 订单类型比例
this.service.request(this.service.$api_getWayBillDirectProportion).subscribe(res => {
if (res) {
const billTypeDatas = this.formatCoordinateData(res.map((item: any) => ({ ...item, billType: item.wayBillType })));
this.initBillChart(this.BillDirectProportion['el'].nativeElement as any, billTypeDatas);
}
});
// 统计订单结算金额-趋势
this.service.request(this.service.$api_get_bill_payment_amount).subscribe(res => {
if (res) {
this.salesData = this.formatBarData(res);
this.initBiaxialChart(this.SaleProportion['el'].nativeElement as any, this.salesData);
}
});
}
handleClick(data: G2MiniAreaClickItem): void {
this.service.msgSrv.info(`${data.item.x} - ${data.item.y}`);
}
/**
* 构建订单类型秘鲁图
* @param el
*/
private initBillChart(el: HTMLElement, datas?: any[]): void {
const data = datas || this.billTypeDatas;
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: any, index: any) => {
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')
};
}
}
});
innerView
.annotation()
.text({
position: ['50%', '50%'],
content: data[0].item,
style: {
fontSize: 20,
fill: '#8c8c8c',
textAlign: 'center'
},
offsetY: -20
})
.text({
position: ['50%', '50%'],
content: data[0].count,
style: {
fontSize: 28,
fill: '#8c8c8c',
textAlign: 'center'
},
offsetY: 20
});
innerView.render(true);
// 移除图例点击过滤交互
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'
},
offsetY: 20
});
innerView.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
innerView.annotation().clear(true);
innerView.render(true);
lastItem = null;
}
}
/**
* 构建大区业绩完成情况柱折双轴图
* @param el
* @param data
*/
private initRegionalPerformanceChart(el: HTMLElement, data: DataPerformanceTrendVO[]) {
const chart = new Chart({
container: el,
autoFit: true,
height: 400
});
chart.data(data);
chart.scale({
time: {
alias: '日期',
type: 'time'
},
quantity: {
alias: '金额',
min: 0,
sync: true, // 将 pv 字段数值同 time 字段数值进行同步
nice: true
}
});
chart.axis('quantity', {
title: {}
});
chart.tooltip({
showCrosshairs: true,
shared: true
});
// 声明需要进行自定义图例字段: 'item'
chart.legend({
offsetY: 10,
position: 'bottom', // 配置图例显示位置
custom: true, // 关键字段,告诉 G2要使用自定义的图例
items: [
{
name: '订单金额 (元)', // 对应 itemName
value: '' // 对应 itemValue
}
],
itemValue: {
style: {
fill: '#999'
} // 配置 itemValue 样式
}
});
chart.line().position('time*quantity').color('#4FAAEB');
chart.render();
}
/**
* 构建业绩完成情况柱折双轴图
* @param el
* @param data
*/
private initBiaxialChart(el: HTMLElement, data: any[]) {
const chart = new Chart({
container: el,
autoFit: true,
height: 400
});
chart.data(data);
// 设置坐标轴
chart.scale({
pre: { alias: '同期业绩完成率', min: 0, max: 1, formatter: val => val * 100 + '%' },
pre2: { alias: '业绩完成率', min: 0, max: 1, formatter: val => val * 100 + '%' },
quantity: { alias: '业绩量 (万)', min: 0, max: 1000000 }
});
// 设置
chart.legend({
custom: true,
items: [
{ value: 'quantity', name: '业绩量 (万)', marker: { symbol: 'hyphen', style: { stroke: '#3182bd', r: 15, lineWidth: 5 } } },
{ value: 'pre2', name: '业绩完成率', marker: { symbol: 'hyphen', style: { stroke: '#fdae6b', r: 15, lineWidth: 5 } } },
{ value: 'pre', name: '同期业绩完成率', marker: { symbol: 'hyphen', style: { stroke: '#ff4d4f', r: 15, lineWidth: 5 } } }
]
});
chart.axis('pre', {
grid: null,
title: null,
label: {
formatter: val => +val * 100 + '%'
}
});
chart.axis('pre2', false);
chart.tooltip({
shared: true
});
chart.interval().position('time*quantity').label('quantity').color('#3182bd');
chart
.line()
.position('time*pre')
.label('pre', val => ({ content: (val * 100).toFixed(0) + '%' }))
.color('#ff4d4f')
.size(3);
chart.point().position('time*pre').color('#ff4d4f').size(3).shape('circle');
chart
.line()
.position('time*pre2')
.label('pre2', val => ({ content: (val * 100).toFixed(0) + '%' }))
.color('#fdae6b')
.size(3);
chart.point().position('time*pre2').color('#fdae6b').size(3).shape('circle');
chart.interaction('active-region');
chart.removeInteraction('legend-filter'); // 自定义图例,移除默认的分类图例筛选交互
chart.render();
}
private formatMiniAreaData(data: DataTotalVO) {
return {
totalAmount: `${this.currency.transform(data.totalAmount || 0)}`,
list: data.list?.map(item => ({
x: item.time,
y: item.quantity
}))
};
}
/**
* 初始化饼图数据格式
* @param data
* @returns
*/
private formatCoordinateData(data: DataBillTypeProportion[]): any[] {
const total = data.map(item => item.quantity).reduce((pre, next) => pre + next);
const rs: any[] = [];
data.forEach(item => {
rs.push({
item: (BILLTYPE as any)[item.billType],
count: item.quantity,
percent: Number((item.quantity / total).toFixed(2))
});
});
return rs;
}
private formatBarData(data: DataPerformanceTrendVO[]): any[] {
return data.map(item => ({
time: item.time,
quantity: item.quantity,
color: undefined,
pre: Math.floor(Math.random() * 100) / 100,
pre2: Math.floor(Math.random() * 100) / 100
}));
}
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() * 1)
});
}
return res;
}
}
interface DataTotalVO {
totalAmount: number;
list: DataPerformanceTrendVO[];
}
interface DataPerformanceTrendVO {
quantity: number;
time: number;
}
interface DataBillTypeProportion {
billType: BILLTYPE;
quantity: number;
}
enum BILLTYPE {
'HY' = '货源单',
'HT' = '合同单',
'ZF' = '直付',
'CDZ' = '车队长'
}