Merge branch 'main' of github.com:hainatravel/dashboard

feature/2.0-sales-trade
LiaoYijun 3 years ago
commit 564b959974

@ -1,122 +1,120 @@
import './App.css'; import "./App.css";
import React, {useContext} from 'react'; import React, { useContext } from "react";
import { import { HomeOutlined, TeamOutlined, DashboardOutlined, FileProtectOutlined, CustomerServiceTwoTone, SnippetsTwoTone, DollarOutlined, AreaChartOutlined, WechatOutlined, UserOutlined } from "@ant-design/icons";
HomeOutlined, import { Layout, Menu, Image, Spin } from "antd";
TeamOutlined, import { BrowserRouter, Route, Routes, NavLink } from "react-router-dom";
DashboardOutlined, import Home from "./views/Home";
FileProtectOutlined, import Dashboard from "./views/Dashboard";
CustomerServiceTwoTone, import Orders from "./views/Orders";
DollarOutlined, import Orders_sub from "./views/Orders_sub";
AreaChartOutlined, import ProtectedRoute from "./views/ProtectedRoute";
WechatOutlined, import Customer_care_inchina from "./charts/Customer_care_inchina";
UserOutlined import Customer_care_potential from "./charts/Customer_care_potential";
} from '@ant-design/icons'; import Customer_care_regular from "./charts/Customer_care_regular";
import {Layout, Menu, Image, Spin} from 'antd'; import Wechat_session from "./charts/Wechat_session";
import {BrowserRouter, Route, Routes, NavLink} from "react-router-dom" import WhatsApp_session from "./charts/WhatsApp_session";
import Home from "./views/Home" import Credit_card_bill from "./views/Credit_card_bill";
import Dashboard from "./views/Dashboard" import exchange_rate from "./charts/ExchangeRate";
import Orders from "./views/Orders" import Sale from "./views/Sale";
import Orders_sub from "./views/Orders_sub" import Logo from "./logo.png";
import ProtectedRoute from "./views/ProtectedRoute" import { stores_Context } from "./config";
import Customer_care_inchina from "./charts/Customer_care_inchina" import { observer } from "mobx-react";
import Customer_care_potential from "./charts/Customer_care_potential" import ExchangeRate from "./charts/ExchangeRate";
import Customer_care_regular from "./charts/Customer_care_regular"
import Wechat_session from "./charts/Wechat_session"
import WhatsApp_session from "./charts/WhatsApp_session"
import Credit_card_bill from "./views/Credit_card_bill"
import Logo from './logo.png'
import {stores_Context} from "./config";
import {observer} from "mobx-react";
const App = () => { const App = () => {
const { Content, Footer, Sider } = Layout;
const { auth_store } = useContext(stores_Context);
const menu_items = [
{ key: 1, label: <NavLink to="/">主页</NavLink>, icon: <HomeOutlined /> },
{
key: 2,
label: "市场",
icon: <AreaChartOutlined />,
children: [
{ key: 21, label: <NavLink to="/orders">订单数据</NavLink>, icon: <FileProtectOutlined /> },
{ key: 22, label: <NavLink to="/dashboard">仪表盘</NavLink>, icon: <DashboardOutlined /> },
],
},
{
key: 5,
label: "销售",
icon: <SnippetsTwoTone />,
children: [{ key: 51, label: <NavLink to="/sale">业绩数据</NavLink> }],
},
{
key: 3,
label: "客运",
icon: <WechatOutlined />,
children: [
{ key: 31, label: <NavLink to="/customer_care_potential">潜力客户</NavLink> },
{ key: 32, label: <NavLink to="/customer_care_regular">老客户</NavLink> },
{ key: 33, label: <NavLink to="/customer_care_inchina">在华客户</NavLink> },
{ key: 34, label: <NavLink to="/wechat_session">微信会话存档</NavLink> },
{ key: 35, label: <NavLink to="/whatsapp_session">WhatsApp会话存档</NavLink> },
],
},
{
key: 4,
label: "财务",
icon: <DollarOutlined />,
children: [
{ key: 41, label: <NavLink to="/credit_card_bill">信用卡账单</NavLink> },
{ key: 42, label: <NavLink to="/exchange_rate">汇率</NavLink> },
],
},
];
const {Content, Footer, Sider} = Layout; return (
const {auth_store} = useContext(stores_Context); <BrowserRouter>
<Layout
const menu_items = [ style={{
{key: 1, label: <NavLink to="/">主页</NavLink>, icon: <HomeOutlined/>}, minHeight: "100vh",
{ }}>
key: 2, label: '市场', icon: <AreaChartOutlined/>, <Sider collapsible={true} breakpoint="lg">
children: [ <Image src={Logo} preview={false} />
{key: 21, label: <NavLink to="/orders">订单数据</NavLink>, icon: <FileProtectOutlined/>,}, <Menu theme="dark" defaultSelectedKeys={["1"]} defaultOpenKeys={["2", "3", "4", "5"]} mode="inline" items={menu_items} />
{key: 22, label: <NavLink to="/dashboard">仪表盘</NavLink>, icon: <DashboardOutlined/>}, </Sider>
] <Layout className="site-layout">
}, <Content
{ style={{
key: 3, label: '客运', icon: <WechatOutlined/>, padding: 16,
children: [ minHeight: 480,
{key: 31, label: <NavLink to="/customer_care_potential">潜力客户</NavLink>}, }}>
{key: 32, label: <NavLink to="/customer_care_regular">老客户</NavLink>}, <Routes>
{key: 33, label: <NavLink to="/customer_care_inchina">在华客户</NavLink>}, <Route path="/" element={<Home />} />
{key: 34, label: <NavLink to="/wechat_session">微信会话存档</NavLink>}, <Route element={<ProtectedRoute auth={["admin", "director_bu", "marketing"]} />}>
{key: 35, label: <NavLink to="/whatsapp_session">WhatsApp会话存档</NavLink>}, <Route path="/orders" element={<Orders />} />
] <Route path="/orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<Orders_sub />} />
}, <Route path="/dashboard" element={<Dashboard />} />
{ </Route>
key: 4, <Route element={<ProtectedRoute auth={["admin", "director_bu", "customer_care"]} />}>
label: '财务', <Route path="/customer_care_inchina" element={<Customer_care_inchina />} />
icon: <DollarOutlined/>, <Route path="/customer_care_regular" element={<Customer_care_regular />} />
children: [ <Route path="/customer_care_potential" element={<Customer_care_potential />} />
{key: 41, label: <NavLink to="/credit_card_bill">信用卡账单</NavLink>}, <Route path="/whatsapp_session" element={<WhatsApp_session />} />
] <Route path="/wechat_session" element={<Wechat_session />} />
}, </Route>
<Route element={<ProtectedRoute auth={["admin", "director_bu", "financial"]} />}>
<Route path="/credit_card_bill" element={<Credit_card_bill />} />
]; <Route path="/exchange_rate" element={<ExchangeRate />} />
</Route>
return ( <Route element={<ProtectedRoute auth={["admin", "director_bu", "sale"]} />}>
<BrowserRouter> <Route path="/sale" element={<Sale />} />
<Layout </Route>
style={{ </Routes>
minHeight: '100vh', </Content>
}} <Footer
> style={{
<Sider collapsible={false} defaultCollapsed={false} breakpoint="lg" textAlign: "center",
collapsedWidth="0"> }}>
<Image src={Logo} preview={false}/> <UserOutlined /> {auth_store.user.name} ({auth_store.user.userid})<br />
<Menu theme="dark" defaultSelectedKeys={['1']} defaultOpenKeys={['2', '3','4']} mode="inline" Hainatravel Dashboard ©2022 Created by IT
items={menu_items}/> </Footer>
</Sider> </Layout>
<Layout className="site-layout"> </Layout>
<Content style={{ </BrowserRouter>
padding: 16, );
minHeight: 480, };
}}>
<Routes>
<Route path="/" element={<Home/>}/>
<Route element={<ProtectedRoute auth={['admin', 'director_bu', 'marketing']}/>}>
<Route path="/orders" element={<Orders/>}/>
<Route path="/orders_sub/:ordertype/:ordertype_sub/:ordertype_title"
element={<Orders_sub/>}/>
<Route path="/dashboard" element={<Dashboard/>}/>
</Route>
<Route element={<ProtectedRoute auth={['admin', 'director_bu', 'customer_care']}/>}>
<Route path="/customer_care_inchina" element={<Customer_care_inchina/>}/>
<Route path="/customer_care_regular" element={<Customer_care_regular/>}/>
<Route path="/customer_care_potential" element={<Customer_care_potential/>}/>
<Route path="/whatsapp_session" element={<WhatsApp_session/>}/>
<Route path="/wechat_session" element={<Wechat_session/>}/>
</Route>
<Route element={<ProtectedRoute auth={['admin', 'director_bu', 'financial']}/>}>
<Route path="/credit_card_bill" element={<Credit_card_bill/>}/>
</Route>
</Routes>
</Content>
<Footer
style={{
textAlign: 'center',
}}
>
<UserOutlined/> {auth_store.user.name} ({auth_store.user.userid})<br/>
Hainatravel Dashboard ©2022 Created by IT
</Footer>
</Layout>
</Layout>
</BrowserRouter>
);
}
export default observer(App); export default observer(App);

@ -95,7 +95,7 @@ const Customer_care_inchina = () => {
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>
<Divider orientation="right"><a <Divider orientation="right" plain><a
onClick={() => { onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]); const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]);
writeFileXLSX(wb, "在华客人.xlsx"); writeFileXLSX(wb, "在华客人.xlsx");

@ -89,7 +89,7 @@ const Customer_care_potential = () => {
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>
<Divider orientation="right"><a <Divider orientation="right" plain><a
onClick={() => { onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]); const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]);
writeFileXLSX(wb, "潜力客户.xlsx"); writeFileXLSX(wb, "潜力客户.xlsx");

@ -94,7 +94,7 @@ const Customer_care_regular = () => {
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>
<Divider orientation="right"><a <Divider orientation="right" plain><a
onClick={() => { onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]); const wb = utils.table_to_book(document.getElementById("table_to_xlsx").getElementsByTagName('table')[0]);
writeFileXLSX(wb, "老客户.xlsx"); writeFileXLSX(wb, "老客户.xlsx");

@ -0,0 +1,76 @@
import React, { Component } from "react";
import { Table, Button, Space, Radio } from "antd";
import { SearchOutlined } from "@ant-design/icons";
import GroupSelect from "./GroupSelect";
import DatePickerCharts from "./DatePickerCharts";
import { stores_Context } from "../config";
import { observer } from "mobx-react";
import * as comm from "../utils/commons";
import { Line } from "@ant-design/charts";
import * as config from "../config";
class ExchangeRate extends Component {
static contextType = stores_Context;
constructor(props) {
super(props);
}
render() {
const { dashboard_store, date_picker_store } = this.context;
const { exchangeRate_data } = dashboard_store;
const line_data_source = comm.empty(exchangeRate_data.data) ? [] : exchangeRate_data.data.CurrencyData1;
const line_config = {
data: line_data_source,
padding: "auto",
xField: "er_date",
yField: "er_htrate",
seriesField: "er_currency",
xAxis: {
type: "timeCat",
},
point: {
size: 4,
shape: "cicle",
},
label: {}, //显示标签
tooltip: {
// customContent: (title, items) => {
// const data = items[0]?.data || {};
// return `<div>${title}</div><div>${data.seriesField} ${data.yField}</div>`;
// },
// itemTpl: '<li class="g2-tooltip-list-item"><span style="background-color:{color};" class="g2-tooltip-marker"></span><span class="g2-tooltip-name">{name}</span>: <span class="g2-tooltip-value">{value}</span></li>',
customItems: items => {
let result_arr = [];
items.forEach(item => {
item.value = item.data.er_htrate + " | " + item.data.er_bankrate;
return result_arr.push(item);
});
return result_arr; //return [{color:'red',name:'sss',value:22},{color:'red',name:'aaaa',value:22}];
},
},
smooth: true,
};
return (
<div>
<h2>汇率 HT|Bank</h2>
<Space size="large">
<DatePickerCharts hide_vs={true} />
<Button
type="primary"
icon={<SearchOutlined />}
loading={exchangeRate_data.loading}
onClick={() => {
exchangeRate_data.asyncFetch(date_picker_store.start_date.format(config.DATE_FORMAT), date_picker_store.end_date.format(config.DATE_FORMAT));
}}>
统计
</Button>
</Space>
<Line {...line_config} />
</div>
);
}
}
export default observer(ExchangeRate);

@ -14,13 +14,15 @@ class GroupSelect extends Component {
<div> <div>
<Select <Select
mode={store.group_select_mode} mode={store.group_select_mode}
allowClear
style={{width: '100%',}} style={{width: '100%',}}
placeholder="选择小组" placeholder="选择小组"
value={store.groups} value={store.groups}
onChange={(value) => store.group_handleChange(value)} onChange={(value) => store.group_handleChange(value)}
> >
{this.props.show_all ? <Select.Option key="0" value="ALL">ALL 小组</Select.Option> : ''} {this.props.show_all ? <Select.Option key="0" value="ALL">ALL 小组</Select.Option> : ''}
<Select.Option key="31" value="1,2,28,7">GH事业部</Select.Option>
<Select.Option key="32" value="8,9,11,12,20,21">国际事业部</Select.Option>
<Select.Option key="33" value="10,18,16,30">孵化学院</Select.Option>
<Select.Option key="1" value="1">CH直销</Select.Option> <Select.Option key="1" value="1">CH直销</Select.Option>
<Select.Option key="2" value="2">CH大客户</Select.Option> <Select.Option key="2" value="2">CH大客户</Select.Option>
<Select.Option key="28" value="28">AH</Select.Option> <Select.Option key="28" value="28">AH</Select.Option>

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
export const stores_Context = React.createContext(); export const stores_Context = React.createContext();
export const DATE_FORMAT = 'YYYY-MM-DD'; export const DATE_FORMAT = "YYYY-MM-DD";
export const HT_HOST = 'https://p9axztuwd7x8a7.mycht.cn'; //export const HT_HOST = 'https://p9axztuwd7x8a7.mycht.cn';
//export const HT_HOST = 'http://202.103.68.100:890';//889正式库 export const HT_HOST = "http://202.103.68.100:890"; //889正式库

@ -13,7 +13,7 @@ class AuthStore {
} }
auth = ['admin']; //开发时候用,正式环境留空 auth = ['admin']; //开发时候用,正式环境留空
user = {name:'ycc',userid:'12345678'};//开发时候用,正式环境留空 user = {name:'loading',userid:'...'};//开发时候用,正式环境留空
has_permission(requireds) { has_permission(requireds) {
if (Object.keys(requireds).length == 0) { if (Object.keys(requireds).length == 0) {

@ -1,198 +1,219 @@
import {makeAutoObservable, runInAction} from "mobx"; import { makeAutoObservable, runInAction } from "mobx";
import * as config from "../config"; import * as config from "../config";
class DashboardStore { class DashboardStore {
constructor(rootStore) {
constructor(rootStore) { this.rootStore = rootStore;
this.rootStore = rootStore; makeAutoObservable(this);
makeAutoObservable(this); }
}
loading = false;
loading = false; site_select_mode = "multiple"; //是否多选站点
site_select_mode = 'multiple';//是否多选站点 webcode = ["CHT", "AH", "GH"];
webcode = ['CHT', 'AH', 'GH'];
//订单统计 begin
//订单统计 begin orders_data = {
orders_data = { loading: false,
loading: false, data: [],
data: [], getOrderCount_all: this.getOrderCount_all.bind(this),
getOrderCount_all: this.getOrderCount_all.bind(this), };
}
getOrderCount_all() {
getOrderCount_all() { //统计所有站点订单数量 //统计所有站点订单数量
this.orders_data.loading = true; this.orders_data.loading = true;
const date_picker_store = this.rootStore.date_picker_store; const date_picker_store = this.rootStore.date_picker_store;
let url = '/service-web/QueryData/GetOrderCount' let url = "/service-web/QueryData/GetOrderCount";
url += '?WebCode=all&COLI_ApplyDate1=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&COLI_ApplyDate2=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59'; url += "?WebCode=all&COLI_ApplyDate1=" + date_picker_store.start_date.format(config.DATE_FORMAT) + "&COLI_ApplyDate2=" + date_picker_store.end_date.format(config.DATE_FORMAT) + "%2023:59:59";
fetch(config.HT_HOST + url) fetch(config.HT_HOST + url)
.then((response) => response.json()) .then(response => response.json())
.then((json) => { .then(json => {
runInAction(() => { runInAction(() => {
this.orders_data.data = json.ordercount1; this.orders_data.data = json.ordercount1;
this.orders_data.loading = false; this.orders_data.loading = false;
}) });
}) })
.catch((error) => { .catch(error => {
this.orders_data.loading = false; this.orders_data.loading = false;
console.log('fetch data failed', error); console.log("fetch data failed", error);
}); });
} }
//订单统计 end //订单统计 end
// 临时订单 begin // 临时订单 begin
ordersTemp_data = { ordersTemp_data = {
data: [], data: [],
data_detail: [], data_detail: [],
loading: false, loading: false,
loading_detail: false, loading_detail: false,
show_table: false, show_table: false,
site_select_mode: 'multiple', site_select_mode: "multiple",
webcode: ['CHT', 'AH', 'GH'], webcode: ["CHT", "AH", "GH"],
handleChange_webcode: this.handleChange_site_select.bind(this), handleChange_webcode: this.handleChange_site_select.bind(this),
asyncFetch: this.get_CountOrdersData.bind(this), asyncFetch: this.get_CountOrdersData.bind(this),
asyncFetch_detail: this.get_CountOrdersData_detail.bind(this), asyncFetch_detail: this.get_CountOrdersData_detail.bind(this),
} };
handleChange_site_select(value) { handleChange_site_select(value) {
this.ordersTemp_data.webcode = value; this.ordersTemp_data.webcode = value;
} }
get_CountOrdersData() { get_CountOrdersData() {
this.ordersTemp_data.loading = true; this.ordersTemp_data.loading = true;
this.ordersTemp_data.show_table = false; this.ordersTemp_data.show_table = false;
const date_picker_store = this.rootStore.date_picker_store; const date_picker_store = this.rootStore.date_picker_store;
let url = '/service-baseinfo/QueryWebData?type=orders_temp&db=1'; let url = "/service-baseinfo/QueryWebData?type=orders_temp&db=1";
const website_code = "'" + this.ordersTemp_data.webcode.join("','") + "'"; const website_code = "'" + this.ordersTemp_data.webcode.join("','") + "'";
url += '&WebSite=' + website_code + '&ApplyDateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&ApplyDateEnd=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59'; url += "&WebSite=" + website_code + "&ApplyDateStart=" + date_picker_store.start_date.format(config.DATE_FORMAT) + "&ApplyDateEnd=" + date_picker_store.end_date.format(config.DATE_FORMAT) + "%2023:59:59";
fetch(config.HT_HOST + url) fetch(config.HT_HOST + url)
.then((response) => response.json()) .then(response => response.json())
.then((json) => { .then(json => {
runInAction(() => { runInAction(() => {
this.ordersTemp_data.data = json.data; this.ordersTemp_data.data = json.data;
this.ordersTemp_data.loading = false; this.ordersTemp_data.loading = false;
}) });
}) })
.catch((error) => { .catch(error => {
this.ordersTemp_data.loading = false; this.ordersTemp_data.loading = false;
console.log('fetch data failed', error); console.log("fetch data failed", error);
}); });
} }
get_CountOrdersData_detail() { get_CountOrdersData_detail() {
this.ordersTemp_data.loading_detail = true; this.ordersTemp_data.loading_detail = true;
this.ordersTemp_data.show_table = true; this.ordersTemp_data.show_table = true;
const date_picker_store = this.rootStore.date_picker_store; const date_picker_store = this.rootStore.date_picker_store;
let url = '/service-baseinfo/QueryWebData?type=orders_temp_detail&db=1'; let url = "/service-baseinfo/QueryWebData?type=orders_temp_detail&db=1";
const website_code = "'" + this.ordersTemp_data.webcode.join("','") + "'"; const website_code = "'" + this.ordersTemp_data.webcode.join("','") + "'";
url += '&WebSite=' + website_code + '&ApplyDateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&ApplyDateEnd=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59'; url += "&WebSite=" + website_code + "&ApplyDateStart=" + date_picker_store.start_date.format(config.DATE_FORMAT) + "&ApplyDateEnd=" + date_picker_store.end_date.format(config.DATE_FORMAT) + "%2023:59:59";
fetch(config.HT_HOST + url) fetch(config.HT_HOST + url)
.then((response) => response.json()) .then(response => response.json())
.then((json) => { .then(json => {
runInAction(() => { runInAction(() => {
this.ordersTemp_data.data_detail = json.data; this.ordersTemp_data.data_detail = json.data;
this.ordersTemp_data.loading_detail = false; this.ordersTemp_data.loading_detail = false;
}) });
}) })
.catch((error) => { .catch(error => {
this.ordersTemp_data.loading_detail = false; this.ordersTemp_data.loading_detail = false;
console.log('fetch data failed', error); console.log("fetch data failed", error);
}); });
} }
// 临时订单 end // 临时订单 end
// 移动成交 beign
// 移动成交 beign handleChange_webcode = value => {
handleChange_webcode = (value) => { this.webcode = value;
this.webcode = value; };
};
handleChange_group_select(value) {
handleChange_group_select(value) { this.mobile_data.groups = value;
this.mobile_data.groups = value; }
};
onChange_datetype(e) {
onChange_datetype(e) { this.mobile_data.date_type = e.target.value;
this.mobile_data.date_type = e.target.value; }
};
get_CountYDOrder() {
get_CountYDOrder() { const date_picker_store = this.rootStore.date_picker_store;
const date_picker_store = this.rootStore.date_picker_store; this.mobile_data.loading = true;
this.mobile_data.loading = true; let url = "/service-tourdesign/CountYDOrder?DEI_SNList=" + this.mobile_data.groups.toString();
let url = '/service-tourdesign/CountYDOrder?DEI_SNList=' + this.mobile_data.groups.toString(); if (this.mobile_data.date_type == "applyDate") {
if (this.mobile_data.date_type == 'applyDate') { url += "&ApplydateCheck=1&OrderStartdateCheck=0";
url += '&ApplydateCheck=1&OrderStartdateCheck=0'; } else {
} else { url += "&ApplydateCheck=0&OrderStartdateCheck=1";
url += '&ApplydateCheck=0&OrderStartdateCheck=1'; }
} url += "&ApplydateStart=" + date_picker_store.start_date.format(config.DATE_FORMAT) + "&ApplydateEnd=" + date_picker_store.end_date.format(config.DATE_FORMAT) + "%2023:59:59";
url += '&ApplydateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&ApplydateEnd=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59'; url += "&OrderStartdateStart=" + date_picker_store.start_date.format(config.DATE_FORMAT) + "&OrderStartdateEnd=" + date_picker_store.end_date.format(config.DATE_FORMAT) + "%2023:59:59";
url += '&OrderStartdateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&OrderStartdateEnd=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59'; fetch(config.HT_HOST + url)
fetch(config.HT_HOST + url) .then(response => response.json())
.then((response) => response.json()) .then(json => {
.then((json) => { let table_data = [];
let table_data = [] json &&
json && json.map((item, index) => { json.map((item, index) => {
table_data.push({ table_data.push({
key: index, key: index,
department_name: item.DEI_DepartmentName, department_name: item.DEI_DepartmentName,
mobile_order: item.YDOrderNum + '/' + item.OrderNum + ' (' + (item.OrderNumRate * 100).toFixed(1) + '%)', mobile_order: item.YDOrderNum + "/" + item.OrderNum + " (" + (item.OrderNumRate * 100).toFixed(1) + "%)",
mobile_deal: item.YDOrderNumSUC + ' / ' + item.OrderNumSUC + ' (' + (item.OrderNumSUCRate * 100).toFixed(1) + '%)', mobile_deal: item.YDOrderNumSUC + " / " + item.OrderNumSUC + " (" + (item.OrderNumSUCRate * 100).toFixed(1) + "%)",
mobile_gross: item.YDML + ' / ' + item.ML + ' (' + (item.MLRate * 100).toFixed(1) + '%)', mobile_gross: item.YDML + " / " + item.ML + " (" + (item.MLRate * 100).toFixed(1) + "%)",
}) });
}) });
runInAction(() => { runInAction(() => {
this.mobile_data.data = table_data; this.mobile_data.data = table_data;
this.mobile_data.loading = false; this.mobile_data.loading = false;
}) });
}) })
.catch((error) => { .catch(error => {
this.mobile_data.loading = false; this.mobile_data.loading = false;
console.log('fetch data failed', error); console.log("fetch data failed", error);
}); });
}; }
mobile_data = { mobile_data = {
loading: false, loading: false,
data: [], data: [],
group_select_mode: 'multiple',//是否多选分组 group_select_mode: "multiple", //是否多选分组
groups: ['1', '2', '28', '7', '8', '9', '11', '12', '20', '21'], groups: ["1", "2", "28", "7", "8", "9", "11", "12", "20", "21", "18"],
columns: [ columns: [
{ {
title: '市场', title: "市场",
dataIndex: 'department_name', dataIndex: "department_name",
key: 'department_name', key: "department_name",
}, },
{ {
title: '移动订单/总订单', title: "移动订单/总订单",
dataIndex: 'mobile_order', dataIndex: "mobile_order",
key: 'mobile_order', key: "mobile_order",
}, },
{ {
title: '移动成交/总成交', title: "移动成交/总成交",
dataIndex: 'mobile_deal', dataIndex: "mobile_deal",
key: 'mobile_deal', key: "mobile_deal",
}, },
{ {
title: '移动毛利/总毛利', title: "移动毛利/总毛利",
dataIndex: 'mobile_gross', dataIndex: "mobile_gross",
key: 'mobile_gross', key: "mobile_gross",
}, },
], ],
date_type: 'applyDate', date_type: "applyDate",
group_handleChange: this.handleChange_group_select.bind(this), group_handleChange: this.handleChange_group_select.bind(this),
onChange_datetype: this.onChange_datetype.bind(this), onChange_datetype: this.onChange_datetype.bind(this),
asyncFetch: this.get_CountYDOrder.bind(this), asyncFetch: this.get_CountYDOrder.bind(this),
} };
// 移动成交 end // 移动成交 end
// 汇率变化 begin
exchangeRate_data = {
loading: false,
data: [],
asyncFetch: this.get_currency_exchange_rate.bind(this),
};
get_currency_exchange_rate(Currdate1_start, Currdate1_end) {
const date_picker_store = this.rootStore.date_picker_store;
this.exchangeRate_data.loading = true;
let url = "/service-web/QueryData/GetCurrency?Currency=ALL";
url += "&Currdate1=" + Currdate1_start + "&Currdate2=" + Currdate1_end + "%2023:59:59";
fetch(config.HT_HOST + url)
.then(response => response.json())
.then(json => {
runInAction(() => {
this.exchangeRate_data.data = json;
this.exchangeRate_data.loading = false;
});
})
.catch(error => {
this.exchangeRate_data.loading = false;
console.log("fetch data failed", error);
});
}
// 汇率变化 end
} }
export default DashboardStore; export default DashboardStore;

@ -6,6 +6,7 @@ import CustomerStore from "./CustomerStore";
import AuthStore from "./AuthStore"; import AuthStore from "./AuthStore";
import ChatSessionStore from "./ChatSessionStore"; import ChatSessionStore from "./ChatSessionStore";
import FinancialStore from "./FinancialStore"; import FinancialStore from "./FinancialStore";
import SaleStore from "./SaleStore";
import WechatStore from "./Wechat"; import WechatStore from "./Wechat";
import WhatsAppStore from "./WhatsApp"; import WhatsAppStore from "./WhatsApp";
@ -19,6 +20,7 @@ class Index {
this.auth_store = new AuthStore(this); this.auth_store = new AuthStore(this);
this.chat_session_store = new ChatSessionStore(this); this.chat_session_store = new ChatSessionStore(this);
this.financial_store = new FinancialStore(this); this.financial_store = new FinancialStore(this);
this.sale_store = new SaleStore(this);
this.wechatStore = new WechatStore(this); this.wechatStore = new WechatStore(this);
this.whatsAppStore = new WhatsAppStore(this); this.whatsAppStore = new WhatsAppStore(this);
makeAutoObservable(this); makeAutoObservable(this);

@ -0,0 +1,61 @@
import { makeAutoObservable, runInAction } from "mobx";
import * as dd from "dingtalk-jsapi";
import * as config from "../config";
import * as comm from "../utils/commons";
//销售数据
class SaleStore {
constructor(rootStore) {
this.rootStore = rootStore;
makeAutoObservable(this);
}
loading = false;
active_tab_key = "overview"; //当前选择的标签
group_select_mode = false;
date_type = "applyDate";
groups = ["1,2,28,7"];
date_title='date_title';//日期段,只用于显示,防止日期选择控件的变化导致页面刷新
//选择事业部
group_handleChange(value) {
this.groups = value;
}
//切换标签页
onChange_Tabs(active_key) {
this.active_tab_key = active_key;
//this.getOrderCountByType_sub(ordertype, ordertype_sub, this.active_tab_key_sub);
}
//下单日期或者出发日期
onChange_datetype(e) {
this.date_type = e.target.value;
}
//获取业绩信息
getxxxxx(ordertype, ordertype_sub) {
// this.loading = true;
// const date_picker_store = this.rootStore.date_picker_store;
// let url = '/service-web/QueryData/GetOrderCount'
// url += `?OrderType=${ordertype}&OrderType_val=${ordertype_sub}`;
// url += '&WebCode=' + this.webcode + '&COLI_ApplyDate1=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&COLI_ApplyDate2=' + date_picker_store.end_date.format(config.DATE_FORMAT) + '%2023:59:59';
// if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) {
// url += '&COLI_ApplyDateold1=' + date_picker_store.start_date_cp.format(config.DATE_FORMAT) + '&COLI_ApplyDateold2=' + date_picker_store.end_date_cp.format(config.DATE_FORMAT) + '%2023:59:59';
// }
// fetch(config.HT_HOST + url)
// .then((response) => response.json())
// .then((json) => {
// runInAction(() => {
// this.orderCountData_type = this.format_data_source(json, date_picker_store.start_date, date_picker_store.start_date_cp);
// this.loading = false;
// })
// })
// .catch((error) => {
// this.loading = false;
// console.log('fetch data failed', error);
// });
}
}
export default SaleStore;

@ -207,8 +207,7 @@ export function show_vs_tag(vs, vs_diff, data1, data2) {
}// else { }// else {
// tag = <Tag icon={< CaretUpOutlined/>} color="lime">{vs} {vs_diff}</Tag> // tag = <Tag icon={< CaretUpOutlined/>} color="lime">{vs} {vs_diff}</Tag>
// } // }
return <span><div>{data1} vs {data2}</div> return <span><div>{data1} vs {data2} </div> {tag} </span>
{tag}</span>
} }
//数组去掉重复 //数组去掉重复

@ -1,298 +1,361 @@
import React, {Component, useContext} from 'react'; import React, { Component, useContext } from "react";
import {observer} from 'mobx-react'; import { observer } from "mobx-react";
import {Row, Col, Button, Tabs, Table, Divider} from 'antd'; import { Row, Col, Button, Tabs, Table, Divider } from "antd";
import {stores_Context} from '../config' import { stores_Context } from "../config";
import {utils, writeFileXLSX} from "xlsx"; import { utils, writeFileXLSX } from "xlsx";
import {NavLink, useNavigate} from "react-router-dom"; import { NavLink, useNavigate } from "react-router-dom";
import { import { SlackOutlined, ContainerOutlined, CarryOutOutlined, SearchOutlined, GithubOutlined } from "@ant-design/icons";
SlackOutlined, import BillTypeSelect from "../charts/BillTypeSelect";
ContainerOutlined, import GroupSelect from "../charts/GroupSelect";
CarryOutOutlined, import Business_unit from "../charts/Business_unit";
SearchOutlined, import DatePickerCharts from "../charts/DatePickerCharts";
GithubOutlined import { Line, Pie } from "@ant-design/charts";
} from '@ant-design/icons'; import * as comm from "../utils/commons";
import BillTypeSelect from '../charts/BillTypeSelect'
import GroupSelect from '../charts/GroupSelect'
import Business_unit from '../charts/Business_unit'
import DatePickerCharts from '../charts/DatePickerCharts'
import {Line} from "@ant-design/charts";
import * as comm from '../utils/commons'
import * as config from "../config"; import * as config from "../config";
const Credit_card_bill = () => { const Credit_card_bill = () => {
const { financial_store, date_picker_store } = useContext(stores_Context);
const { bill_type_data, credit_card_data } = financial_store;
const {financial_store, date_picker_store} = useContext(stores_Context); const format_data = data => {
const {bill_type_data, credit_card_data} = financial_store; let result = { dataSource: [], columns: [] };
if (!comm.empty(data)) {
const format_data = ((data) => { if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) {
let result = {dataSource: [], columns: []} //有比较的数据
if (!comm.empty(data)) { let total_data1 = data.BillTypeDataTotal1;
if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) { //有比较的数据 let total_data2 = data.BillTypeDataTotal2;
let total_data1 = data.BillTypeDataTotal1; result.columns = [
let total_data2 = data.BillTypeDataTotal2; {
result.columns = [ title: "项目类型",
{ children: [
title: '项目类型', {
children: [{ title: "",
title: '', dataIndex: "cb_billtype",
dataIndex: 'cb_billtype', render: (text, record) => (
render: (text, record) => <a onClick={() => { <a
credit_card_data.set_bill_filtered(text);//切换到明细页 onClick={() => {
credit_card_data.set_active_tab('detail_data'); credit_card_data.set_bill_filtered(text); //切换到明细页
}}>{text}</a> credit_card_data.set_active_tab("detail_data");
}], }}>
sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype), {text}
}, </a>
{ ),
title: '美金', },
children: [{ ],
title: comm.show_vs_tag(total_data1.usd_vs, total_data1.usd_diff, total_data1.cb_usd, total_data2.cb_usd), sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype),
dataIndex: 'cb_usd' },
}], {
}, title: "美金",
{ children: [
title: '人民币', {
children: [{ title: comm.show_vs_tag(total_data1.usd_vs, total_data1.usd_diff, total_data1.cb_usd, total_data2.cb_usd),
title: comm.show_vs_tag(total_data1.rmb_vs, total_data1.rmb_diff, total_data1.cb_rmb, total_data2.cb_rmb), dataIndex: "cb_usd",
dataIndex: 'cb_rmb' },
}], ],
}, },
]; {
for (let item of data.BillTypeData1) { title: "人民币",
for (let item2 of data.BillTypeData2) { children: [
if (item.cb_billtype == item2.cb_billtype) { {
result.dataSource.push({ title: comm.show_vs_tag(total_data1.rmb_vs, total_data1.rmb_diff, total_data1.cb_rmb, total_data2.cb_rmb),
key: item.key, dataIndex: "cb_rmb",
cb_billtype: item.cb_billtype, },
groups: item.groups, ],
cb_usd: comm.show_vs_tag(item.usd_vs, item.usd_diff, item.cb_usd, item2.cb_usd), },
cb_rmb: comm.show_vs_tag(item.rmb_vs, item.rmb_diff, item.cb_rmb, item2.cb_rmb), ];
}) for (let item of data.BillTypeData1) {
} for (let item2 of data.BillTypeData2) {
} if (item.cb_billtype == item2.cb_billtype) {
} result.dataSource.push({
} else { key: item.key,
result.columns = [ cb_billtype: item.cb_billtype,
{ groups: item.groups,
title: '项目类型', cb_usd: comm.show_vs_tag(item.usd_vs, item.usd_diff, item.cb_usd, item2.cb_usd),
children: [{ cb_rmb: comm.show_vs_tag(item.rmb_vs, item.rmb_diff, item.cb_rmb, item2.cb_rmb),
title: '', });
dataIndex: 'cb_billtype', }
render: (text, record) => <a onClick={() => { }
credit_card_data.set_bill_filtered(text);//切换到明细页 }
credit_card_data.set_active_tab('detail_data'); } else {
}}>{text}</a> result.columns = [
}], {
sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype), title: "项目类型",
}, children: [
{ {
title: '美金', title: "",
children: [{title: data.BillTypeDataTotal1.cb_usd, dataIndex: 'cb_usd'}], dataIndex: "cb_billtype",
sorter: (a, b) => parseFloat(b.cb_usd.replace(/,/g, '')) - parseFloat(a.cb_usd.replace(/,/g, '')), render: (text, record) => (
}, <a
{ onClick={() => {
title: '人民币', credit_card_data.set_bill_filtered(text); //切换到明细页
children: [{title: data.BillTypeDataTotal1.cb_rmb, dataIndex: 'cb_rmb'}], credit_card_data.set_active_tab("detail_data");
sorter: (a, b) => parseFloat(b.cb_rmb.replace(/,/g, '')) - parseFloat(a.cb_rmb.replace(/,/g, '')), }}>
}, {text}
] </a>
result.dataSource = data.BillTypeData1; ),
} },
} ],
return result; sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype),
}) },
{
const filters_array = (data_array) => { title: "美金",
return comm.unique(data_array).map(item => { children: [{ title: data.BillTypeDataTotal1.cb_usd, dataIndex: "cb_usd" }],
return {text: item, value: item} sorter: (a, b) => parseFloat(b.cb_usd.replace(/,/g, "")) - parseFloat(a.cb_usd.replace(/,/g, "")),
}); },
} {
title: "人民币",
children: [{ title: data.BillTypeDataTotal1.cb_rmb, dataIndex: "cb_rmb" }],
sorter: (a, b) => parseFloat(b.cb_rmb.replace(/,/g, "")) - parseFloat(a.cb_rmb.replace(/,/g, "")),
},
];
result.dataSource = data.BillTypeData1;
}
}
return result;
};
const format_data_detail = ((data) => { const filters_array = data_array => {
let result = {dataSource: [], columns: []} return comm.unique(data_array).map(item => {
if (!comm.empty(data)) { return { text: item, value: item };
let show_vs = false; });
let usd_totle1, usd_totle2, usd_diff, usd_vs, rmb_totle1, rmb_totle2, rmb_diff, rmb_vs = 0; };
usd_totle1 = Math.round(data.billdate1.reduce((a, b) => a + b.cb_usd, 0));
rmb_totle1 = Math.round(data.billdate1.reduce((a, b) => a + b.cb_rmb, 0));
if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) { //有比较的数据
show_vs = true;
//计算汇总的变化
usd_totle2 = Math.round(data.billdate2.reduce((a, b) => a + b.cb_usd, 0));
usd_diff = usd_totle1 - usd_totle2;
usd_vs = comm.formatPercent(usd_diff / usd_totle1);
rmb_totle2 = Math.round(data.billdate2.reduce((a, b) => a + b.cb_rmb, 0));
rmb_diff = rmb_totle1 - rmb_totle2;
rmb_vs = comm.formatPercent(rmb_diff / rmb_totle1);
}
if (show_vs) { //有比较的数据
result.dataSource.push(...data.billdate1, ...data.billdate2);
} else {
result.dataSource.push(...data.billdate1);
}
result.columns = [
{
title: '项目类型',
children: [{
title: '',
dataIndex: 'cb_billtype',
}],
sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype),
filters: filters_array(result.dataSource.map((item) => {
return item.cb_billtype
})),
filteredValue: credit_card_data.filteredValue || null,
onFilter: (value, record) => record.cb_billtype.indexOf(value) === 0,
},
{
title: '项目',
children: [{
title: '',
dataIndex: 'cb_bill',
}],
sorter: (a, b) => a.cb_bill.localeCompare(b.cb_bill),
},
{
title: '美金',
children: [{
title: show_vs ? comm.show_vs_tag(usd_vs, usd_diff, usd_totle1, usd_totle2) : usd_totle1,
dataIndex: 'cb_usd'
}],
sorter: (a, b) => b.cb_usd - a.cb_usd,
},
{
title: '人民币',
children: [{
title: show_vs ? comm.show_vs_tag(rmb_vs, rmb_diff, rmb_totle1, rmb_totle2) : rmb_totle1,
dataIndex: 'cb_rmb'
}],
sorter: (a, b) => b.cb_rmb - a.cb_rmb,
},
{ const format_data_detail = data => {
title: '交易日期', let result = { dataSource: [], columns: [] };
children: [{title: '', dataIndex: 'cb_datetime'}], if (!comm.empty(data)) {
}, let show_vs = false;
{ let usd_totle1,
title: '账期', usd_totle2,
children: [{title: '', dataIndex: 'cb_billdate'}], usd_diff,
}, usd_vs,
{ rmb_totle1,
title: '事业部', rmb_totle2,
children: [{title: '', dataIndex: 'cb_business_unit'}], rmb_diff,
sorter: (a, b) => a.cb_business_unit.localeCompare(b.cb_business_unit), rmb_vs = 0;
}, usd_totle1 = Math.round(data.billdate1.reduce((a, b) => a + b.cb_usd, 0));
{ rmb_totle1 = Math.round(data.billdate1.reduce((a, b) => a + b.cb_rmb, 0));
title: '小组', if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) {
children: [{title: '', dataIndex: 'cb_group'}], //有比较的数据
sorter: (a, b) => a.cb_group.localeCompare(b.cb_group), show_vs = true;
}, //计算汇总的变化
] usd_totle2 = Math.round(data.billdate2.reduce((a, b) => a + b.cb_usd, 0));
usd_diff = usd_totle1 - usd_totle2;
usd_vs = comm.formatPercent(usd_diff / usd_totle1);
rmb_totle2 = Math.round(data.billdate2.reduce((a, b) => a + b.cb_rmb, 0));
rmb_diff = rmb_totle1 - rmb_totle2;
rmb_vs = comm.formatPercent(rmb_diff / rmb_totle1);
}
if (show_vs) {
//有比较的数据
result.dataSource.push(...data.billdate1, ...data.billdate2);
} else {
result.dataSource.push(...data.billdate1);
}
result.columns = [
{
title: "项目类型",
children: [
{
title: "",
dataIndex: "cb_billtype",
},
],
sorter: (a, b) => a.cb_billtype.localeCompare(b.cb_billtype),
filters: filters_array(
result.dataSource.map(item => {
return item.cb_billtype;
})
),
filteredValue: credit_card_data.filteredValue || null,
onFilter: (value, record) => record.cb_billtype.indexOf(value) === 0,
},
{
title: "项目",
children: [
{
title: "",
dataIndex: "cb_bill",
},
],
sorter: (a, b) => a.cb_bill.localeCompare(b.cb_bill),
},
{
title: "美金",
children: [
{
title: show_vs ? comm.show_vs_tag(usd_vs, usd_diff, usd_totle1, usd_totle2) : usd_totle1,
dataIndex: "cb_usd",
},
],
sorter: (a, b) => b.cb_usd - a.cb_usd,
},
{
title: "人民币",
children: [
{
title: show_vs ? comm.show_vs_tag(rmb_vs, rmb_diff, rmb_totle1, rmb_totle2) : rmb_totle1,
dataIndex: "cb_rmb",
},
],
sorter: (a, b) => b.cb_rmb - a.cb_rmb,
},
} {
title: "交易日期",
children: [{ title: "", dataIndex: "cb_datetime" }],
},
{
title: "账期",
children: [{ title: "", dataIndex: "cb_billdate" }],
},
{
title: "事业部",
children: [{ title: "", dataIndex: "cb_business_unit" }],
sorter: (a, b) => a.cb_business_unit.localeCompare(b.cb_business_unit),
},
{
title: "小组",
children: [{ title: "", dataIndex: "cb_group" }],
sorter: (a, b) => a.cb_group.localeCompare(b.cb_group),
},
];
}
return result; return result;
}) };
const credit_card_bills = !comm.empty(credit_card_data.data) ? format_data_detail(credit_card_data.data) : format_data_detail([]); //格式化数据,饼图只支持数字模式
const credit_card_bills_by_type = !comm.empty(credit_card_data.data_by_type) ? format_data(credit_card_data.data_by_type) : format_data([]); const format_data_for_pie = data => {
let result_arr = [];
if (!comm.empty(data)) {
data.map(item => {
item.cb_usd_number = parseFloat(item.cb_usd.replace(/,/g, ""));
result_arr.push(item);
});
}
return result_arr;
};
const line_config = { const credit_card_bills = !comm.empty(credit_card_data.data) ? format_data_detail(credit_card_data.data) : format_data_detail([]);
data: credit_card_bills.dataSource, const credit_card_bills_by_type = !comm.empty(credit_card_data.data_by_type) ? format_data(credit_card_data.data_by_type) : format_data([]);
padding: 'auto',
xField: 'cb_datetime',
yField: 'cb_usd',
seriesField: 'groups',
xAxis: {
type: 'timeCat',
},
point: {
size: 4,
shape: 'cicle',
},
label: {},//显示标签
legend: {
itemValue: {
formatter: (text, item) => {
const items = credit_card_bills.dataSource.filter((d) => d.groups === item.value);//按站点筛选
return items.length ? Math.round(items.reduce((a, b) => a + b.cb_usd, 0)) : '';//计算总数
},
},
},
// tooltip: {
// customContent: (title, items) => {
// const data = items[0]?.data || {};
// return `<div>${title}</div><div>${data.seriesField} ${data.yField}</div>`;
// }
// },
smooth: true,
};
return ( const pie_config = {
<div> appendPadding: 10,
<Row> data: [],
<Col span={11}> angleField: "cb_usd_number",
<h2>信用卡账单</h2> colorField: "cb_billtype",
</Col> radius: 0.8,
<Col span={10}> label: {
<Row> type: "outer",
<Col span={12}> content: "{name} \n {percentage}",
<BillTypeSelect store={bill_type_data} show_all={true}/> },
<Business_unit store={credit_card_data} show_all={true}/> tooltip: {
{/*<GroupSelect store={credit_card_data} show_all={true}/>*/} customItems: items => {
</Col> let result_arr = [];
<Col span={12}> items.forEach(item => {
<DatePickerCharts/> item.value = "$" + item.data.cb_usd + " | ¥" + item.data.cb_rmb;
</Col> return result_arr.push(item);
</Row> });
</Col> return result_arr;
<Col span={1}></Col> },
<Col span={2}> },
<Button type="primary" icon={<SearchOutlined/>} size='large' loading={credit_card_data.loading} legend: false, //不显示图例
onClick={() => { interactions: [
financial_store.get_credit_card_bills(); {
financial_store.get_credit_card_bills_by_type(); type: "element-selected",
financial_store.set_bill_filtered(false); },
}}>统计</Button> {
</Col> type: "element-active",
</Row> },
],
};
<Row> return (
<Col span={24}> <div>
<Line {...line_config} /> <Row>
</Col> <Col span={11}>
<Col className="gutter-row" span={24}> <h2>信用卡账单</h2>
<Tabs activeKey={credit_card_data.active_tab} onChange={credit_card_data.set_active_tab}> </Col>
<Tabs.TabPane tab={<span><CarryOutOutlined/>项目汇总</span>} key="summarized_data"> <Col span={10}>
<Table id="table_by_type" dataSource={credit_card_bills_by_type.dataSource} <Row>
columns={credit_card_bills_by_type.columns} <Col span={12}>
pagination={false} <BillTypeSelect store={bill_type_data} show_all={true} />
size="small"/> <Business_unit store={credit_card_data} show_all={true} />
<Divider orientation="right"><a </Col>
onClick={() => { <Col span={12}>
const wb = utils.table_to_book(document.getElementById("table_by_type").getElementsByTagName('table')[0]); <DatePickerCharts />
writeFileXLSX(wb, "项目汇总.xlsx"); </Col>
}}>导出excel</a></Divider> </Row>
</Tabs.TabPane> </Col>
<Tabs.TabPane tab={<span><ContainerOutlined/>明细</span>} key="detail_data"> <Col span={1}></Col>
<Table id="table_by_detail" dataSource={credit_card_bills.dataSource} <Col span={2}>
columns={credit_card_bills.columns} <Button
pagination={false} type="primary"
onChange={credit_card_data.set_table_handleChange} icon={<SearchOutlined />}
size="small"/> size="large"
<Divider orientation="right"><a loading={credit_card_data.loading}
onClick={() => { onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_by_detail").getElementsByTagName('table')[0]); financial_store.get_credit_card_bills();
writeFileXLSX(wb, "明细.xlsx"); financial_store.get_credit_card_bills_by_type();
}}>导出excel</a></Divider> financial_store.set_bill_filtered(false);
</Tabs.TabPane> }}>
</Tabs> 统计
</Col> </Button>
</Row> </Col>
</div> </Row>
);
} <Row>
<Col span={12}>
<Pie {...pie_config} data={format_data_for_pie(credit_card_data.data_by_type.BillTypeData1)} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={format_data_for_pie(credit_card_data.data_by_type.BillTypeData2)} />
</Col>
<Col className="gutter-row" span={24}>
<Tabs activeKey={credit_card_data.active_tab} onChange={credit_card_data.set_active_tab}>
<Tabs.TabPane
tab={
<span>
<CarryOutOutlined />
项目汇总
</span>
}
key="summarized_data">
<Table id="table_by_type" dataSource={credit_card_bills_by_type.dataSource} columns={credit_card_bills_by_type.columns} pagination={false} size="small" />
<Divider orientation="right">
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_by_type").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "项目汇总.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
明细
</span>
}
key="detail_data">
<Table id="table_by_detail" dataSource={credit_card_bills.dataSource} columns={credit_card_bills.columns} pagination={false} onChange={credit_card_data.set_table_handleChange} size="small" />
<Divider orientation="right">
<a
onClick={() => {
const wb = utils.table_to_book(document.getElementById("table_by_detail").getElementsByTagName("table")[0]);
writeFileXLSX(wb, "明细.xlsx");
}}>
导出excel
</a>
</Divider>
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
</div>
);
};
export default observer(Credit_card_bill); export default observer(Credit_card_bill);

@ -1,38 +1,39 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Col, Row} from "antd"; import { Col, Row } from "antd";
import OrdersTempTable from "../charts/OrdersTempTable"; import OrdersTempTable from "../charts/OrdersTempTable";
import MobileDeal from "../charts/MobileDeal"; import MobileDeal from "../charts/MobileDeal";
import Orders from "../charts/Orders"; import Orders from "../charts/Orders";
import ExchangeRate from "../charts/ExchangeRate";
class Dashboard extends Component { class Dashboard extends Component {
constructor(props) {
super(props);
}
constructor(props) { render() {
super(props); return (
} <div>
<div>
<Row>
<Col span={24}>
<Orders />
</Col>
render() { <Col span={24}>
<ExchangeRate />
</Col>
<Col span={12}>
<OrdersTempTable />
</Col>
return ( <Col span={12}>
<div> <MobileDeal />
<div </Col>
> </Row>
<Row gutter={[16, {xs: 8, sm: 16, md: 24, lg: 32}]}> </div>
<Col className="gutter-row" span={24}> </div>
<Orders/> );
</Col> }
<Col className="gutter-row" span={12}>
<OrdersTempTable/>
</Col>
<Col className="gutter-row" span={12}>
<MobileDeal/>
</Col>
</Row>
</div>
</div>
);
}
} }
export default Dashboard; export default Dashboard;

@ -1,278 +1,521 @@
import React, {Component} from 'react'; import React, { Component } from "react";
import {Row, Col, Button, Tabs, Table} from 'antd'; import { Row, Col, Button, Tabs, Table, Divider } from "antd";
import { import { ContainerOutlined, CarryOutOutlined, BlockOutlined, SmileOutlined, TagsOutlined, GlobalOutlined, SearchOutlined, FullscreenOutlined, DingtalkOutlined } from "@ant-design/icons";
ContainerOutlined, CarryOutOutlined, BlockOutlined, import { stores_Context } from "../config";
SmileOutlined, TagsOutlined, GlobalOutlined, import { Line, Pie } from "@ant-design/charts";
SearchOutlined,
} from '@ant-design/icons';
import {stores_Context} from '../config'
import {Line} from "@ant-design/charts";
import SiteSelect from "../charts/SiteSelect"; import SiteSelect from "../charts/SiteSelect";
import {observer} from 'mobx-react'; import { observer } from "mobx-react";
import DatePickerCharts from '../charts/DatePickerCharts' import DatePickerCharts from "../charts/DatePickerCharts";
import * as config from "../config"; import * as config from "../config";
import {NavLink} from "react-router-dom"; import { NavLink } from "react-router-dom";
import * as comm from "../utils/commons" import * as comm from "../utils/commons";
import { utils, writeFileXLSX } from "xlsx";
class Orders extends Component { class Orders extends Component {
static contextType = stores_Context;
static contextType = stores_Context; constructor(props) {
super(props);
}
constructor(props) { // componentDidMount() {
super(props); // const {orders_store} = this.context;
} // orders_store.getOrderCount();
// orders_store.onChange_Tabs(orders_store.active_tab_key);
// }
// componentDidMount() { format_data(data) {
// const {orders_store} = this.context; const { date_picker_store, orders_store } = this.context;
// orders_store.getOrderCount(); let result = { dataSource: [], columns: [] };
// orders_store.onChange_Tabs(orders_store.active_tab_key); 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",
},
],
},
];
for (let item of data.ordercount1) {
for (let item2 of data.ordercount2) {
if (item.OrderType == item2.OrderType) {
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),
});
}
}
}
} 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, "")),
},
format_data(data) { {
const {date_picker_store, orders_store} = this.context; title: "单个订单价值",
let result = {dataSource: [], columns: []} children: [{ title: ordercountTotal1.Ordervalue, dataIndex: "Ordervalue" }],
if (!comm.empty(data)) { sorter: (a, b) => parseFloat(b.Ordervalue.replace(/,/g, "")) - parseFloat(a.Ordervalue.replace(/,/g, "")),
let ordercountTotal1 = data.ordercountTotal1; },
let ordercountTotal2 = data.ordercountTotal2; ];
if (date_picker_store.start_date_cp && date_picker_store.end_date_cp) { //有比较的数据 result.dataSource = data.ordercount1;
result.columns = [ }
{ }
title: '', return result;
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'
}],
},
{ render() {
title: '单个订单价值', const { orders_store } = this.context;
children: [{ const table_data = orders_store.orderCountData_Form ? this.format_data(orders_store.orderCountData_Form) : [];
title: comm.show_vs_tag(ordercountTotal1.Ordervalue_vs, ordercountTotal1.Ordervalue_diff, ordercountTotal1.Ordervalue, ordercountTotal2.Ordervalue), const data_source = orders_store.orderCountData ? orders_store.orderCountData : [];
dataIndex: 'Ordervalue' 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;
];
for (let item of data.ordercount1) {
for (let item2 of data.ordercount2) {
if (item.OrderType == item2.OrderType) {
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),
})
}
}
}
} 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) => b.YJLY - a.YJLY,
},
{ const config = {
title: '单个订单价值', data: data_source,
children: [{title: ordercountTotal1.Ordervalue, dataIndex: 'Ordervalue'}], padding: "auto",
sorter: (a, b) => b.Ordervalue - a.Ordervalue, xField: "xField",
}, yField: "yField",
]; seriesField: "seriesField",
result.dataSource = data.ordercount1; xAxis: {
} type: "timeCat",
} },
return result; 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",
},
],
};
render() { return (
const {orders_store} = this.context; <div>
const table_data = orders_store.orderCountData_Form ? this.format_data(orders_store.orderCountData_Form) : []; <Row>
const data_source = orders_store.orderCountData ? orders_store.orderCountData : []; <Col span={14}></Col>
const avg_line_y=data_source.length ? Math.round((data_source.reduce((a, b) => a + b.yField, 0))/data_source.length):0;//平均值,显示一条平均线 <Col span={2}>
const config = { <SiteSelect store={orders_store} />
data: data_source, </Col>
padding: 'auto', <Col span={6}>
xField: 'xField', <DatePickerCharts />
yField: 'yField', </Col>
seriesField: 'seriesField', <Col span={2}>
xAxis: { <Button
type: 'timeCat', type="primary"
}, icon={<SearchOutlined />}
point: { loading={orders_store.loading}
size: 4, onClick={() => {
shape: 'cicle', orders_store.getOrderCount();
}, orders_store.onChange_Tabs(orders_store.active_tab_key);
annotations: [ }}>
{ 统计
type: 'text', </Button>
position: ['start', avg_line_y], </Col>
content: avg_line_y, </Row>
offsetX: -15, <Row gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}>
style: { <Col span={24}>
fill: '#F4664A', <Line {...config} />
textBaseline: 'bottom', </Col>
}
},
{
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,
};
<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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</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} />
<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>
<Row>
<Col span={12}>
<Pie {...pie_config} data={pie_data} />
</Col>
<Col span={12}>
<Pie {...pie_config} data={pie_data2} />
</Col>
</Row>
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
</div>
);
}
}
return ( export default observer(Orders);
<div>
<Row>
<Col span={14}>
</Col>
<Col span={2}>
<SiteSelect store={orders_store}/>
</Col>
<Col span={6}>
<DatePickerCharts/>
</Col>
<Col span={2}>
<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>
<Row gutter={[16, {xs: 8, sm: 16, md: 24, 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 dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><CarryOutOutlined/>产品类型</span>} key="Product">
<Table dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><SmileOutlined/>国籍</span>} key="Country">
<Table dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><TagsOutlined/>线路</span>} key="line">
<Table dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><GlobalOutlined/>目的地</span>} key="city">
<Table dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><BlockOutlined/>页面类型</span>} key="LineClass">
<Table dataSource={table_data.dataSource} columns={table_data.columns} size="small"/>
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
</div>
);
}
}
export
default
observer(Orders);

@ -1,236 +1,274 @@
import React, {useContext, useEffect} from 'react'; import React, { useContext, useEffect } from "react";
import {Row, Col, Button, Tabs, Table, Space} from 'antd'; import { Row, Col, Button, Tabs, Table, Space, Divider } from "antd";
import { import { ContainerOutlined, SearchOutlined } from "@ant-design/icons";
ContainerOutlined, import { stores_Context } from "../config";
SearchOutlined, import { Line } from "@ant-design/charts";
} from '@ant-design/icons'; import { observer } from "mobx-react";
import {stores_Context} from '../config' import DatePickerCharts from "../charts/DatePickerCharts";
import {Line} from "@ant-design/charts"; import { NavLink, useParams } from "react-router-dom";
import {observer} from 'mobx-react';
import DatePickerCharts from '../charts/DatePickerCharts'
import {NavLink, useParams} from "react-router-dom";
import * as comm from "../utils/commons"; import * as comm from "../utils/commons";
import * as config from "../config"; import * as config from "../config";
const Orders_sub = () => { const Orders_sub = () => {
const { ordertype, ordertype_sub, ordertype_title } = useParams();
const { orders_store, date_picker_store } = useContext(stores_Context);
useEffect(() => {
orders_store.getOrderCount_type(ordertype, ordertype_sub);
orders_store.getOrderCountByType_sub(ordertype, ordertype_sub, orders_store.active_tab_key_sub);
}, []);
const {ordertype, ordertype_sub, ordertype_title} = useParams(); const data_source = orders_store.orderCountData_type;
const {orders_store, date_picker_store} = useContext(stores_Context); const avg_line_y = data_source.length ? Math.round(data_source.reduce((a, b) => a + b.yField, 0) / data_source.length) : 0; //平均值,显示一条平均线
const line = {
data: data_source,
padding: "auto",
xField: "xField",
yField: "yField",
seriesField: "seriesField",
xAxis: {
type: "timeCat",
},
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],
},
},
],
tooltip: {
title: (title, datum) => {
return title + " " + comm.getWeek(datum.xField); //显示周几
},
},
label: {}, //显示标签
legend: {
title: {
text: ordertype_title,
},
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) : ""; //计算总数
},
},
},
smooth: true,
};
useEffect(() => { const format_data = data => {
orders_store.getOrderCount_type(ordertype, ordertype_sub); let result = { dataSource: [], columns: [] };
orders_store.getOrderCountByType_sub(ordertype, ordertype_sub, orders_store.active_tab_key_sub); if (!comm.empty(data)) {
}, []) result.columns = [
{
title: "页面",
children: [
{
title: "",
dataIndex: "request_uri",
},
],
},
{
title: "访问量",
children: [
{
title: data.reduce((a, b) => a + b.viewCount, 0),
dataIndex: "viewCount",
},
],
},
];
result.dataSource = data;
}
return result;
};
const data_source = orders_store.orderCountData_type; const format_data_detail = data => {
const avg_line_y = data_source.length ? Math.round((data_source.reduce((a, b) => a + b.yField, 0)) / data_source.length) : 0;//平均值,显示一条平均线 let result = { dataSource: [], columns: [] };
const line = { if (!comm.empty(data)) {
data: data_source, result.columns = [
padding: 'auto', {
xField: 'xField', title: "订单号",
yField: 'yField', dataIndex: "COLI_ID",
seriesField: 'seriesField', key: "COLI_ID",
xAxis: { },
type: 'timeCat', {
}, title: "网站",
annotations: [ dataIndex: "COLI_WebCode",
{ key: "COLI_WebCode",
type: 'text', },
position: ['start', avg_line_y], {
content: avg_line_y, title: "成行",
offsetX: -15, dataIndex: "COLI_Success",
style: { key: "COLI_Success",
fill: '#F4664A', render: (text, record) => <span>{text == 1 ? "是" : "否"}</span>,
textBaseline: 'bottom', sorter: (a, b) => b.COLI_Success - a.COLI_Success,
} },
}, // {
{ // title: "人数(成/童/婴)",
type: 'line', // dataIndex: "COLI_PersonNum",
start: [-10, avg_line_y], // key: "COLI_PersonNum",
end: ['max', avg_line_y], // render: (text, record) => (
style: { // <span>
stroke: '#F4664A', // {record.COLI_PersonNum}/{record.COLI_ChildNum}/{record.COLI_BabyNum}
lineDash: [2, 2], // </span>
}, // ),
}, // },
], {
tooltip: { title: "预计利润",
title: (title, datum) => { dataIndex: "CGI_YJLY",
return title+' '+ comm.getWeek(datum.xField);//显示周几 key: "CGI_YJLY",
}, },
}, {
label: {},//显示标签 title: "预定时间",
legend: { dataIndex: "COLI_ApplyDate",
title: { key: "COLI_ApplyDate",
text: ordertype_title, },
}, {
itemValue: { title: "出发日期",
formatter: (text, item) => { dataIndex: "COLI_OrderStartDate",
const items = data_source.filter((d) => d.seriesField === item.value);//按站点筛选 key: "COLI_OrderStartDate",
return items.length ? items.reduce((a, b) => a + b.yField, 0) : '';//计算总数 },
}, {
}, title: "客人需求",
}, dataIndex: "COLI_CustomerRequest",
smooth: true, key: "COLI_CustomerRequest",
}; ellipsis: true,
},
{
title: "订单内容",
dataIndex: "COLI_OrderDetailText",
key: "COLI_OrderDetailText",
ellipsis: true,
},
Table.EXPAND_COLUMN,
];
result.dataSource = data;
}
return result;
};
const format_data = ((data) => { const table_data = format_data_detail(orders_store.orderCountData_Form_sub.ordercount1);
let result = {dataSource: [], columns: []} const table_data2 = format_data_detail(orders_store.orderCountData_Form_sub.ordercount2);
if (!comm.empty(data)) { const table_data_p = format_data(orders_store.orderCountData_Form_sub.ordercount1);
result.columns = [ const table_data2_p = format_data(orders_store.orderCountData_Form_sub.ordercount2);
{
title: '页面',
children: [{
title: '',
dataIndex: 'request_uri'
}],
},
{
title: '访问量',
children: [{
title: data.reduce((a, b) => a + b.viewCount, 0),
dataIndex: 'viewCount'
}],
}
];
result.dataSource = data;
}
return result;
})
const format_data_detail = ((data) => { return (
let result = {dataSource: [], columns: []} <div>
if (!comm.empty(data)) { <Row>
result.columns = [ <Col span={14}>
{ <NavLink to={`/orders`}>返回</NavLink>
title: '订单号', </Col>
dataIndex: 'COLI_ID', <Col span={2}></Col>
key: 'COLI_ID', <Col span={6}>
}, <DatePickerCharts />
{ </Col>
title: '网站', <Col span={2}>
dataIndex: 'COLI_WebCode', <Button
key: 'COLI_WebCode', type="primary"
}, icon={<SearchOutlined />}
{ loading={orders_store.loading}
title: '成行', onClick={() => {
dataIndex: 'COLI_Success', orders_store.getOrderCount_type(ordertype, ordertype_sub);
key: 'COLI_Success', orders_store.getOrderCountByType_sub(ordertype, ordertype_sub, orders_store.active_tab_key_sub);
render: (text, record) => <span>{text == 1 ? '是' : '否'}</span>, }}>
}, 统计
{ </Button>
title: '预定时间', </Col>
dataIndex: 'COLI_ApplyDate', </Row>
key: 'COLI_ApplyDate', <Row gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}>
}, <Col className="gutter-row" span={24}>
{ <Line {...line} />
title: '订单内容', </Col>
dataIndex: 'COLI_OrderDetailText',
key: 'COLI_OrderDetailText',
ellipsis: true,
},
Table.EXPAND_COLUMN,
];
result.dataSource = data;
}
return result;
})
<Col className="gutter-row" span={24}>
<Tabs activeKey={orders_store.active_tab_key_sub} onChange={active_key => orders_store.onChange_Tabs_sub(ordertype, ordertype_sub, active_key)}>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
订单内容
</span>
}
key="detail">
<Row>
<Col span={24}>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
<Table
dataSource={table_data.dataSource}
columns={table_data.columns}
size="small"
rowKey={record => record.key}
expandable={{
expandedRowRender: record => (
<pre>
<Divider orientation="left" plain>
客户需求
</Divider>
{record.COLI_CustomerRequest}
<Divider orientation="left" plain>
订单内容
</Divider>
{record.COLI_OrderDetailText}
</pre>
),
}}
/>
</Col>
let table_data, table_data2 = format_data(false); <Col span={24}>
switch (orders_store.active_tab_key_sub) { {date_picker_store.start_date_cp ? date_picker_store.start_date_cp.format(config.DATE_FORMAT) + "~" + date_picker_store.end_date_cp.format(config.DATE_FORMAT) : ""}
case "detail": <Table
table_data = format_data_detail(orders_store.orderCountData_Form_sub.ordercount1); dataSource={table_data2.dataSource}
table_data2 = format_data_detail(orders_store.orderCountData_Form_sub.ordercount2); columns={table_data2.columns}
break; size="small"
case "page": rowKey={record => record.key}
table_data = format_data(orders_store.orderCountData_Form_sub.ordercount1); expandable={{
table_data2 = format_data(orders_store.orderCountData_Form_sub.ordercount2); expandedRowRender: record => <pre>{record.COLI_OrderDetailText}</pre>,
break; }}
} />
</Col>
</Row>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
访问路径
</span>
}
key="page">
<Row>
<Col span={24}>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
<Table dataSource={table_data_p.dataSource} rowKey={record => record.key} columns={table_data_p.columns} size="small" />
</Col>
return ( <Col span={24}>
<div> {date_picker_store.start_date_cp ? date_picker_store.start_date_cp.format(config.DATE_FORMAT) + "~" + date_picker_store.end_date_cp.format(config.DATE_FORMAT) : ""}
<Row> <Table dataSource={table_data2_p.dataSource} rowKey={record => record.key} columns={table_data2_p.columns} size="small" />
<Col span={14}> </Col>
<NavLink to={`/orders`}>返回</NavLink> </Row>
</Col> </Tabs.TabPane>
<Col span={2}> </Tabs>
</Col>
</Col> </Row>
<Col span={6}> </div>
<DatePickerCharts/> );
</Col> };
<Col span={2}>
<Button type="primary" icon={<SearchOutlined/>} loading={orders_store.loading} onClick={() => {
orders_store.getOrderCount_type(ordertype, ordertype_sub);
orders_store.getOrderCountByType_sub(ordertype, ordertype_sub, orders_store.active_tab_key_sub);
}}>统计</Button>
</Col>
</Row>
<Row gutter={[16, {xs: 8, sm: 16, md: 24, lg: 32}]}>
<Col className="gutter-row" span={24}>
<Line {...line} />
</Col>
<Col className="gutter-row" span={24}>
<Tabs activeKey={orders_store.active_tab_key_sub}
onChange={(active_key) => orders_store.onChange_Tabs_sub(ordertype, ordertype_sub, active_key)}>
<Tabs.TabPane tab={<span><ContainerOutlined/>订单内容</span>} key="detail">
<Row>
<Col span={11}>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
<Table dataSource={table_data.dataSource}
columns={table_data.columns} size="small" rowKey={record => record.COLI_ID}
expandable={{
expandedRowRender: (record) => (
<pre>{record.COLI_OrderDetailText}</pre>
),
}}
/>
</Col>
<Col span={2}></Col>
<Col span={11}>
{date_picker_store.start_date_cp ? date_picker_store.start_date_cp.format(config.DATE_FORMAT) + '~' + date_picker_store.end_date_cp.format(config.DATE_FORMAT) : ''}
<Table dataSource={table_data2.dataSource}
columns={table_data2.columns} size="small" rowKey={record => record.COLI_ID}
expandable={{
expandedRowRender: (record) => (
<pre>{record.COLI_OrderDetailText}</pre>
),
}}
/>
</Col>
</Row>
</Tabs.TabPane>
<Tabs.TabPane tab={<span><ContainerOutlined/>访问路径</span>} key="page">
<Row>
<Col span={11}>
{date_picker_store.start_date.format(config.DATE_FORMAT)}~{date_picker_store.end_date.format(config.DATE_FORMAT)}
<Table dataSource={table_data.dataSource} rowKey={record => record.COLI_ID}
columns={table_data.columns} size="small"/>
</Col>
<Col span={2}></Col>
<Col span={11}>
{date_picker_store.start_date_cp ? date_picker_store.start_date_cp.format(config.DATE_FORMAT) + '~' + date_picker_store.end_date_cp.format(config.DATE_FORMAT) : ''}
<Table dataSource={table_data2.dataSource} rowKey={record => record.COLI_ID}
columns={table_data2.columns} size="small"/>
</Col>
</Row>
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
</div>
);
}
export default observer(Orders_sub); export default observer(Orders_sub);

@ -0,0 +1,92 @@
import React, { useContext, useEffect } from "react";
import { Row, Col, Button, Tabs, Table, Space, Radio } from "antd";
import { ContainerOutlined, SearchOutlined } from "@ant-design/icons";
import { stores_Context } from "../config";
import { Line } from "@ant-design/charts";
import { observer } from "mobx-react";
import DatePickerCharts from "../charts/DatePickerCharts";
import { NavLink, useParams } from "react-router-dom";
import * as comm from "../utils/commons";
import * as config from "../config";
import GroupSelect from "../charts/GroupSelect";
const Sale = () => {
const { sale_store, date_picker_store } = useContext(stores_Context);
return (
<div>
<Row>
<Col span={13}></Col>
<Col span={8}>
<Row>
<Col span={12}>
<GroupSelect store={sale_store} />
<Radio.Group value={sale_store.date_type} onChange={e => sale_store.onChange_datetype(e)}>
<Radio value="applyDate">下单日期</Radio>
<Radio value="startDate">走团日期</Radio>
</Radio.Group>
</Col>
<Col span={12}>
<DatePickerCharts />
</Col>
</Row>
</Col>
<Col span={1}></Col>
<Col span={2}>
<Button type="primary" icon={<SearchOutlined />} loading={sale_store.loading} onClick={() => {}}>
统计
</Button>
</Col>
</Row>
<Row>
<Col className="gutter-row" span={24}>
{/* <Line {...line} /> */}
</Col>
<Col className="gutter-row" span={24}>
<Tabs activeKey={sale_store.active_tab_key} onChange={active_key => sale_store.onChange_Tabs(active_key)}>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
概览
</span>
}
key="overview">
<Row>
<Col span={24}>
{sale_store.date_title}
{/* <Table
dataSource={table_data.dataSource}
columns={table_data.columns}
size="small"
rowKey={record => record.key}
expandable={{
expandedRowRender: record => <pre>{record.COLI_OrderDetailText}</pre>,
}}
/> */}
</Col>
</Row>
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<ContainerOutlined />
国籍
</span>
}
key="page">
<Row>
<Col span={24}>
{sale_store.date_title}
{/* <Table dataSource={table_data_p.dataSource} rowKey={record => record.key} columns={table_data_p.columns} size="small" /> */}
</Col>
</Row>
</Tabs.TabPane>
</Tabs>
</Col>
</Row>
</div>
);
};
export default observer(Sale);
Loading…
Cancel
Save