You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dashboard/src/views/Orders.js

505 lines
17 KiB
JavaScript

import React, { Component } from "react";
import { Row, Col, Button, Tabs, Table, Divider, Space } from "antd";
import { ContainerOutlined, CarryOutOutlined, BlockOutlined, SmileOutlined, TagsOutlined, GlobalOutlined, SearchOutlined, FullscreenOutlined, DingtalkOutlined } from "@ant-design/icons";
import { stores_Context } from "../config";
import { Line, Pie } from "@ant-design/charts";
import SiteSelect from "../charts/SiteSelect";
import { observer } from "mobx-react";
import DatePickerCharts from "../charts/DatePickerCharts";
import * as config from "../config";
import { NavLink } from "react-router-dom";
import * as comm from "../utils/commons";
import { utils, writeFileXLSX } from "xlsx";
class Orders extends Component {
static contextType = stores_Context;
constructor(props) {
super(props);
}
format_data(data) {
const { date_picker_store, orders_store } = this.context;
let result = { dataSource: [], columns: [] };
if (!comm.empty(data)) {
let ordercountTotal1 = data.ordercountTotal1;
let ordercountTotal2 = data.ordercountTotal2;
if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) {
//有比较的数据
result.columns = [
{
title: "",
children: [
{
title: (
<span>
<div>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
</div>
<div>
{date_picker_store.start_date_cp.format(config.DATE_FORMAT)}~{date_picker_store.end_date_cp.format(config.DATE_FORMAT)}
</div>
</span>
),
dataIndex: "OrderType",
render: (text, record) => <NavLink to={`/orders_sub/${orders_store.active_tab_key}/${record.OrderTypeSN}/${record.OrderType}`}>{text}</NavLink>,
},
],
},
{
title: "数量",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.OrderCount_vs, ordercountTotal1.OrderCount_diff, ordercountTotal1.OrderCount, ordercountTotal2.OrderCount),
dataIndex: "OrderCount",
},
],
},
{
title: "成交数",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.CJCount_vs, ordercountTotal1.CJCount_diff, ordercountTotal1.CJCount, ordercountTotal2.CJCount),
dataIndex: "CJCount",
},
],
},
{
title: "成交人数",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.CJPersonNum_vs, ordercountTotal1.CJPersonNum_diff, ordercountTotal1.CJPersonNum, ordercountTotal2.CJPersonNum),
dataIndex: "CJPersonNum",
},
],
},
{
title: "成交率",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.CJrate_vs, ordercountTotal1.CJrate_diff, ordercountTotal1.CJrate, ordercountTotal2.CJrate),
dataIndex: "CJrate",
},
],
},
{
title: "成交毛利(预计)",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.YJLY_vs, ordercountTotal1.YJLY_diff, ordercountTotal1.YJLY, ordercountTotal2.YJLY),
dataIndex: "YJLY",
},
],
},
{
title: "单个订单价值",
children: [
{
title: comm.show_vs_tag(ordercountTotal1.Ordervalue_vs, ordercountTotal1.Ordervalue_diff, ordercountTotal1.Ordervalue, ordercountTotal2.Ordervalue),
dataIndex: "Ordervalue",
},
],
},
];
//1.找出两个数组OrderType相同的数据做比较显示 2.找出两组数据OrderType都不相同的数据做显示
let has_same_type = false; //数组1在数组2中是否找到相同的类型
for (let item of data.ordercount1) {
has_same_type = false;
//数组1在数组2中相同的类型
for (let item2 of data.ordercount2) {
if (item.OrderType == item2.OrderType) {
has_same_type = true;
result.dataSource.push({
key: item.key,
OrderType: item.OrderType,
OrderTypeSN: item.OrderTypeSN,
OrderCount: comm.show_vs_tag(item.OrderCount_vs, item.OrderCount_diff, item.OrderCount, item2.OrderCount),
CJCount: comm.show_vs_tag(item.CJCount_vs, item.CJCount_diff, item.CJCount, item2.CJCount),
CJPersonNum: comm.show_vs_tag(item.CJPersonNum_vs, item.CJPersonNum_diff, item.CJPersonNum, item2.CJPersonNum),
CJrate: comm.show_vs_tag(item.CJrate_vs, item.CJrate_diff, item.CJrate, item2.CJrate),
YJLY: comm.show_vs_tag(item.YJLY_vs, item.YJLY_diff, item.YJLY, item2.YJLY),
Ordervalue: comm.show_vs_tag(item.Ordervalue_vs, item.Ordervalue_diff, item.Ordervalue, item2.Ordervalue),
});
}
}
//数组1中不在数组2的类型
if (has_same_type == false) {
result.dataSource.push({
key: item.key,
OrderType: item.OrderType,
OrderTypeSN: item.OrderTypeSN,
OrderCount: comm.show_vs_tag(comm.formatPercent(item.OrderCount), item.OrderCount, item.OrderCount, 0),
CJCount: comm.show_vs_tag(comm.formatPercent(item.CJCount), item.CJCount, item.CJCount, 0),
CJPersonNum: comm.show_vs_tag(comm.formatPercent(item.CJPersonNum), item.CJPersonNum, item.CJPersonNum, 0),
CJrate: comm.show_vs_tag(item.CJrate, item.CJrate, item.CJrate, 0),
YJLY: comm.show_vs_tag(comm.formatPercent(item.YJLY), item.YJLY, item.YJLY, 0),
Ordervalue: comm.show_vs_tag(comm.formatPercent(item.Ordervalue), item.Ordervalue, item.Ordervalue, 0),
});
}
}
//数组2中不在数组1的类型
for (let item2 of data.ordercount2) {
has_same_type = false;
for (let item of data.ordercount1) {
if (item.OrderType == item2.OrderType) {
has_same_type = true;
}
}
if (has_same_type == false) {
result.dataSource.push({
key: item2.key,
OrderType: item2.OrderType,
OrderTypeSN: item2.OrderTypeSN,
OrderCount: comm.show_vs_tag(comm.formatPercent(-item2.OrderCount), -item2.OrderCount, 0, item2.OrderCount),
CJCount: comm.show_vs_tag(comm.formatPercent(-item2.CJCount), -item2.CJCount, 0, item2.CJCount),
CJPersonNum: comm.show_vs_tag(comm.formatPercent(-item2.CJPersonNum), -item2.CJPersonNum, 0, item2.CJPersonNum),
CJrate: comm.show_vs_tag(-item2.CJrate, -item2.CJrate, 0, item2.CJrate),
YJLY: comm.show_vs_tag(comm.formatPercent(-item2.YJLY), -item2.YJLY, 0, item2.YJLY),
Ordervalue: comm.show_vs_tag(comm.formatPercent(-item2.Ordervalue), -item2.Ordervalue, 0, item2.Ordervalue),
});
}
}
} else {
result.columns = [
{
title: "",
children: [
{
title: (
<span>
<div>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
</div>
</span>
),
dataIndex: "OrderType",
render: (text, record) => <NavLink to={`/orders_sub/${orders_store.active_tab_key}/${record.OrderTypeSN}/${record.OrderType}`}>{text}</NavLink>,
},
],
},
{
title: "数量",
children: [{ title: ordercountTotal1.OrderCount, dataIndex: "OrderCount" }],
sorter: (a, b) => b.OrderCount - a.OrderCount,
},
{
title: "成交数",
children: [{ title: ordercountTotal1.CJCount, dataIndex: "CJCount" }],
sorter: (a, b) => b.CJCount - a.CJCount,
},
{
title: "成交人数",
children: [{ title: ordercountTotal1.CJPersonNum, dataIndex: "CJPersonNum" }],
sorter: (a, b) => b.CJPersonNum - a.CJPersonNum,
},
{
title: "成交率",
children: [{ title: ordercountTotal1.CJrate, dataIndex: "CJrate" }],
sorter: (a, b) => parseInt(b.CJrate) - parseInt(a.CJrate),
},
{
title: "成交毛利(预计)",
children: [{ title: ordercountTotal1.YJLY, dataIndex: "YJLY" }],
sorter: (a, b) => parseFloat(b.YJLY.replace(/,/g, "")) - parseFloat(a.YJLY.replace(/,/g, "")),
},
{
title: "单个订单价值",
children: [{ title: ordercountTotal1.Ordervalue, dataIndex: "Ordervalue" }],
sorter: (a, b) => parseFloat(b.Ordervalue.replace(/,/g, "")) - parseFloat(a.Ordervalue.replace(/,/g, "")),
},
];
result.dataSource = data.ordercount1;
}
}
return result;
}
render() {
const { orders_store } = this.context;
const table_data = orders_store.orderCountData_Form ? this.format_data(orders_store.orderCountData_Form) : [];
const data_source = orders_store.orderCountData ? orders_store.orderCountData : [];
const avg_line_y = data_source.length ? Math.round(data_source.reduce((a, b) => a + b.yField, 0) / data_source.length) : 0; //平均值,显示一条平均线
const pie_data = comm.empty(orders_store.orderCountData_Form) ? [] : orders_store.orderCountData_Form.ordercount1; //饼图的显示
const pie_data2 = comm.empty(orders_store.orderCountData_Form) ? [] : orders_store.orderCountData_Form.ordercount2;
const config = {
data: data_source,
padding: "auto",
xField: "xField",
yField: "yField",
seriesField: "seriesField",
xAxis: {
type: "timeCat",
},
point: {
size: 4,
shape: "cicle",
},
annotations: [
{
type: "text",
position: ["start", avg_line_y],
content: avg_line_y,
offsetX: -15,
style: {
fill: "#F4664A",
textBaseline: "bottom",
},
},
{
type: "line",
start: [-10, avg_line_y],
end: ["max", avg_line_y],
style: {
stroke: "#F4664A",
lineDash: [2, 2],
},
},
],
label: {}, //显示标签
legend: {
itemValue: {
formatter: (text, item) => {
const items = data_source.filter(d => d.seriesField === item.value); //按站点筛选
return items.length ? items.reduce((a, b) => a + b.yField, 0) : ""; //计算总数
},
},
},
tooltip: {
// customContent: (title, items) => {
// const data = items[0]?.data || {};
// return `<div>${title}</div><div>${data.seriesField} ${data.yField}</div>`;
// }
title: (title, datum) => {
return title + " " + comm.getWeek(datum.xField); //显示周几
},
},
smooth: true,
};
const pie_config = {
appendPadding: 10,
data: [],
angleField: "OrderCount",
colorField: "OrderType",
radius: 0.8,
label: {
type: "outer",
content: "{name} {value} \n {percentage}",
},
legend: false, //不显示图例
interactions: [
{
type: "element-selected",
},
{
type: "element-active",
},
],
};
return (
<div>
<Row gutter={{ sm: 16, lg: 32 }}>
<Col md={24} lg={10} xxl={12}></Col>
<Col md={24} lg={14} xxl={12}>
<Row>
<Col md={24} lg={6} xxl={4}>
<SiteSelect store={orders_store} />
</Col>
<Col md={24} lg={12} xxl={10}>
<DatePickerCharts />
</Col>
<Col md={24} lg={6} xxl={10}>
<Button
type="primary"
icon={<SearchOutlined />}
loading={orders_store.loading}
onClick={() => {
orders_store.getOrderCount();
orders_store.onChange_Tabs(orders_store.active_tab_key);
}}>
统计
</Button>
</Col>
</Row>
</Col>
</Row>
<Row gutter={[16, { sm: 16, lg: 32 }]}>
<Col span={24}>
<Line {...config} />
</Col>
<Col span={24}>
<Tabs activeKey={orders_store.active_tab_key} onChange={active_key => orders_store.onChange_Tabs(active_key)}>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
来源类型
</span>
}
key="Form">
<Table id="table_to_xlsx_form" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_form").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "来源类型.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<CarryOutOutlined />
产品类型
</span>
}
key="Product">
<Table id="table_to_xlsx_product" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_product").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "产品类型.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<SmileOutlined />
国籍
</span>
}
key="Country">
<Table id="table_to_xlsx_country" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_country").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "国籍.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<TagsOutlined />
线路
</span>
}
key="line">
<Table id="table_to_xlsx_line" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_line").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "线路.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<GlobalOutlined />
目的地
</span>
}
key="city">
<Table id="table_to_xlsx_city" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_city").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "目的地.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<BlockOutlined />
页面类型
</span>
}
key="LineClass">
<Table id="table_to_xlsx_LineClass" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_LineClass").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "页面类型.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FullscreenOutlined />
客群类别
</span>
}
key="GuestGroupType">
<Table id="table_to_xlsx_GuestGroupType" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_GuestGroupType").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "客群类别.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<DingtalkOutlined />
出行动机
</span>
}
key="TravelMotivation">
<Table id="table_to_xlsx_TravelMotivation" dataSource={table_data.dataSource} columns={table_data.columns} size="small" pagination={false} scroll={{ x: "100%" }} />
<Divider orientation="right" plain>
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx_TravelMotivation").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "出行动机.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
</Tabs>
<Row>
<Col sm={24} lg={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col sm={24} lg={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</Col>
</Row>
</div>
);
}
}
export default observer(Orders);