diff --git a/README.md b/README.md
index ed55e83..b4a6edb 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,14 @@
# dashboard
海纳的数据化管理系统
+
+### ant-design
+https://ant-design.antgroup.com/components/select-cn
+
+### charts.ant.design
+https://charts.ant.design/zh/examples/column/basic#basic
+
+### antv-g2plot
+https://antv-g2plot.gitee.io/zh/examples/pie/basic/#legend-interaction
+
+### momentjs
+http://momentjs.cn/docs/
\ No newline at end of file
diff --git a/src/config.js b/src/config.js
index b44be47..02b6d3c 100644
--- a/src/config.js
+++ b/src/config.js
@@ -2,5 +2,4 @@ import React from "react";
export const stores_Context = React.createContext();
export const DATE_FORMAT = "YYYY-MM-DD";
-//export const HT_HOST = 'https://p9axztuwd7x8a7.mycht.cn';
-export const HT_HOST = "http://202.103.68.100:890"; //889正式库
+export const HT_HOST = process.env.NODE_ENV == "production" ? "https://p9axztuwd7x8a7.mycht.cn" : "http://202.103.68.100:890";
\ No newline at end of file
diff --git a/src/stores/AuthStore.js b/src/stores/AuthStore.js
index 7e28d1b..0d1b910 100644
--- a/src/stores/AuthStore.js
+++ b/src/stores/AuthStore.js
@@ -1,61 +1,59 @@
-import {makeAutoObservable, runInAction} from "mobx";
-import * as dd from 'dingtalk-jsapi';
+import { makeAutoObservable, runInAction } from "mobx";
+import * as dd from "dingtalk-jsapi";
import * as config from "../config";
-
//权限管理
class AuthStore {
-
- constructor(rootStore) {
- this.rootStore = rootStore;
- makeAutoObservable(this);
- //this.get_auth(); //放到钉钉环境才能开启
- }
-
- auth = ['admin']; //开发时候用,正式环境留空
- user = {name:'loading',userid:'...'};//开发时候用,正式环境留空
-
- has_permission(requireds) {
- if (Object.keys(requireds).length == 0) {
- return true;
- }
- let has_permission = requireds.filter(item => this.auth.includes(item));
- if (Object.keys(has_permission).length !== 0) {
- return true;
- }
- return false;
- }
-
- //请求权限
- get_auth() {
- let _this = this;
- const CORPID = 'ding48bce8fd3957c96b';//企业的id
- dd.runtime.permission.requestAuthCode({
- corpId: CORPID,
- onSuccess: function (res) {
- console.log(res);
- let code = res.code;
- let url = '/dingtalk/dingtalkwork/Getusers_auth?code=' + code;
- //请求获取HT接口获取用户权限和用户信息
- fetch(config.HT_HOST + url)
- .then((response) => response.json())
- .then((json) => {
- runInAction(() => {
- _this.user = json.result;
- _this.auth = json.result.authlist;
- })
- })
- .catch((error) => {
- console.log('fetch data failed', error);
- });
- },
- onFail: function (err) {
- console.log(err)
- }
- });
- }
+ constructor(rootStore) {
+ this.rootStore = rootStore;
+ makeAutoObservable(this);
+ if (process.env.NODE_ENV == "production") {
+ this.get_auth(); //放到钉钉环境才能开启
+ }
+ }
+
+ auth = ["admin"]; //开发时候用,正式环境留空
+ user = { name: "loading", userid: "..." }; //开发时候用,正式环境留空
+
+ has_permission(requireds) {
+ if (Object.keys(requireds).length == 0) {
+ return true;
+ }
+ let has_permission = requireds.filter(item => this.auth.includes(item));
+ if (Object.keys(has_permission).length !== 0) {
+ return true;
+ }
+ return false;
+ }
+
+ //请求权限
+ get_auth() {
+ let _this = this;
+ const CORPID = "ding48bce8fd3957c96b"; //企业的id
+ dd.runtime.permission.requestAuthCode({
+ corpId: CORPID,
+ onSuccess: function (res) {
+ console.log(res);
+ let code = res.code;
+ let url = "/dingtalk/dingtalkwork/Getusers_auth?code=" + code;
+ //请求获取HT接口获取用户权限和用户信息
+ fetch(config.HT_HOST + url)
+ .then(response => response.json())
+ .then(json => {
+ runInAction(() => {
+ _this.user = json.result;
+ _this.auth = json.result.authlist;
+ });
+ })
+ .catch(error => {
+ console.log("fetch data failed", error);
+ });
+ },
+ onFail: function (err) {
+ console.log(err);
+ },
+ });
+ }
}
-
export default AuthStore;
-
diff --git a/src/stores/OrdersStore.js b/src/stores/OrdersStore.js
index b7bebb9..c197cc2 100644
--- a/src/stores/OrdersStore.js
+++ b/src/stores/OrdersStore.js
@@ -30,7 +30,7 @@ class OrdersStore {
const date_picker_store = this.rootStore.date_picker_store;
let _start_date = moment(date_picker_store.start_date.format(config.DATE_FORMAT));
let _end_date = moment(date_picker_store.end_date.format(config.DATE_FORMAT));
- return _end_date.diff(_start_date, "days");
+ return _end_date.diff(_start_date, "days")+1;
}
handleChange_webcode = (value) => {
diff --git a/src/stores/SaleStore.js b/src/stores/SaleStore.js
index ce9c480..4530435 100644
--- a/src/stores/SaleStore.js
+++ b/src/stores/SaleStore.js
@@ -55,9 +55,9 @@ class SaleStore {
this.date_title += ` ${date2_start}~${date2_end}`;
}
fetch(config.HT_HOST + url)
- .then((response) => response.json())
- .then((json) => {
- result=json.result1;
+ .then(response => response.json())
+ .then(json => {
+ result = json.result1;
// if (!comm.empty(json.result2) && !comm.empty(date_moment.start_date_cp)) {
// let diff_days = date_moment.start_date.diff(date_moment.start_date_cp, "days");
// for (let item of json.result2) {
@@ -74,7 +74,7 @@ class SaleStore {
this.loading = false;
});
})
- .catch((error) => {
+ .catch(error => {
this.loading = false;
console.log("fetch data failed", error);
});
@@ -97,8 +97,8 @@ class SaleStore {
this.date_title += ` ${date2_start}~${date2_end}`;
}
fetch(config.HT_HOST + url)
- .then((response) => response.json())
- .then((json) => {
+ .then(response => response.json())
+ .then(json => {
if (!comm.empty(json.result2) && !comm.empty(date_moment.start_date_cp)) {
} else {
if (this.active_tab_key == "All") {
@@ -155,11 +155,6 @@ class SaleStore {
},
],
},
- {
- title: "首次报价回复率",
- children: [{ title: "", dataIndex: "FirstRspRate" }],
- sorter: (a, b) => parseInt(b.FirstRspRate) - parseInt(a.FirstRspRate),
- },
{
title: "报价次数",
children: [{ title: json.result1.reduce((a, b) => a + b.PriceTime, 0), dataIndex: "PriceTime" }],
@@ -202,11 +197,69 @@ class SaleStore {
},
];
result.dataSource = json.result1;
+ } else if (this.active_tab_key == "ResponseRateWhatsApp") {
+ result.columns = [
+ {
+ title: "",
+ children: [
+ {
+ title: "",
+ dataIndex: "OPI_Name",
+ },
+ ],
+ },
+ {
+ title: "首次回复率",
+ children: [{ title: "", dataIndex: "firstReplayRate" }],
+ sorter: (a, b) => parseInt(b.firstReplayRate) - parseInt(a.firstReplayRate),
+ },
+ {
+ title: "一次报价率",
+ children: [{ title: '', dataIndex: "FirstQuotationRate" }],
+ sorter: (a, b) => b.FirstQuotationRate - a.FirstQuotationRate,
+ },
+ {
+ title: "一次报价回复率",
+ children: [{ title: '', dataIndex: "FirstQuotationReplayRate" }],
+ sorter: (a, b) => b.FirstQuotationReplayRate - a.FirstQuotationReplayRate,
+ },
+ {
+ title: "一次报价回复周期",
+ children: [{ title: '', dataIndex: "FirstQuotationReplaytimeAVG" }],
+ sorter: (a, b) => b.FirstQuotationReplaytimeAVG - a.FirstQuotationReplaytimeAVG,
+ },
+ {
+ title: "二次报价率",
+ children: [{ title: '', dataIndex: "SecondQuotationRate" }],
+ sorter: (a, b) => b.SecondQuotationRate - a.SecondQuotationRate,
+ },
+ {
+ title: "二次报价回复率",
+ children: [{ title: '', dataIndex: "SecondQuotationReplayRate" }],
+ sorter: (a, b) => b.SecondQuotationReplayRate - a.SecondQuotationReplayRate,
+ },
+ {
+ title: "二次报价回复周期",
+ children: [{ title: '', dataIndex: "SecondQuotationReplaytimeAVG" }],
+ sorter: (a, b) => b.SecondQuotationReplaytimeAVG - a.SecondQuotationReplaytimeAVG,
+ },
+ {
+ title: "成团率",
+ children: [{ title: '', dataIndex: "COLI_SuccessRate" }],
+ sorter: (a, b) => b.COLI_SuccessRate - a.COLI_SuccessRate,
+ },
+ {
+ title: "成团周期",
+ children: [{ title: '', dataIndex: "COLI_ConfirmTimeAVG" }],
+ sorter: (a, b) => b.COLI_ConfirmTimeAVG - a.COLI_ConfirmTimeAVG,
+ },
+ ];
+ result.dataSource = json.result1;
} else {
//if (this.active_tab_key == "Country")
//获取类型的项目,去掉重复,作为列名
let type_name_arr = [];
- json.result1.map((item) => {
+ json.result1.map(item => {
type_name_arr[item.SubTypeSN] = { SubTypeSN: item.SubTypeSN, SubTypeName: item.SubTypeName };
});
@@ -215,17 +268,17 @@ class SaleStore {
for (let item of json.result1) {
let op_sn = "OP_" + item.OPI_SN; //顾问的SN
- let items = json.result1.filter((d) => d.OPI_SN == item.OPI_SN); //筛选出有当前顾问的记录
+ let items = json.result1.filter(d => d.OPI_SN == item.OPI_SN); //筛选出有当前顾问的记录
let total_data_value = items.length ? items.reduce((a, b) => a + b.COLI_YJLY, 0) : ""; //记录累加
if (comm.empty(type_data[op_sn])) {
type_data[op_sn] = [{ key: item.OPI_SN }, { T_name: item.OPI_Name }, { T_total: total_data_value }];
}
type_data[op_sn].push({ ["T_" + item.SubTypeSN]: item.COLI_YJLY });
}
- Object.values(type_data).map((item) => {
+ Object.values(type_data).map(item => {
type_data_arr.push(
Object.assign(
- ...item.map((it) => {
+ ...item.map(it => {
return it;
})
)
@@ -237,7 +290,7 @@ class SaleStore {
);
Object.values(type_name_arr).map((item, index) => {
let data_index = "T_" + item.SubTypeSN;
- let items = type_data_arr.filter((d) => d[data_index]); //筛选出有对应类型的记录
+ let items = type_data_arr.filter(d => d[data_index]); //筛选出有对应类型的记录
let total_data_value = items.length ? items.reduce((a, b) => a + b[data_index], 0) : ""; //记录累加
result.columns.push({
title: item.SubTypeName,
@@ -253,7 +306,7 @@ class SaleStore {
this.loading_table = false;
});
})
- .catch((error) => {
+ .catch(error => {
this.loading_table = false;
console.log("fetch data failed", error);
});
@@ -275,8 +328,8 @@ class SaleStore {
this.date_title += ` ${date2_start}~${date2_end}`;
}
fetch(config.HT_HOST + url)
- .then((response) => response.json())
- .then((json) => {
+ .then(response => response.json())
+ .then(json => {
if (!comm.empty(json.result2) && !comm.empty(date_moment.start_date_cp)) {
} else {
result.columns = [
@@ -315,7 +368,7 @@ class SaleStore {
//数据处理,把相同类型放入同一个数组
let type_data = [];
!comm.empty(json.result1) &&
- Object.values(json.result1).map((item) => {
+ Object.values(json.result1).map(item => {
let subtype_sn = "type_" + item.subType;
if (comm.empty(type_data[subtype_sn])) {
type_data[subtype_sn] = { subType: item.subType, subType_name: item.subTypeVal, data: [item] };
@@ -331,7 +384,7 @@ class SaleStore {
this.spinning = false;
});
})
- .catch((error) => {
+ .catch(error => {
this.spinning = false;
console.log("fetch data failed", error);
});
diff --git a/src/views/Sale.js b/src/views/Sale.js
index 4b47cee..5964396 100644
--- a/src/views/Sale.js
+++ b/src/views/Sale.js
@@ -1,5 +1,5 @@
import React, { useContext, useEffect } from "react";
-import { Row, Col, Button, Tabs, Table, Space, Radio, Select } from "antd";
+import { Row, Col, Button, Tabs, Table, Divider, Radio, Select } from "antd";
import { ContainerOutlined, SearchOutlined,UserSwitchOutlined } from "@ant-design/icons";
import { stores_Context } from "../config";
import { Column, Pie } from "@ant-design/charts";
@@ -9,6 +9,7 @@ import { NavLink, useParams } from "react-router-dom";
import * as comm from "../utils/commons";
import * as config from "../config";
import GroupSelect from "../charts/GroupSelect";
+import { utils, writeFileXLSX } from "xlsx";
const Sale = () => {
const { sale_store, date_picker_store } = useContext(stores_Context);
@@ -140,6 +141,13 @@ const Sale = () => {
回复率
}
+ key="ResponseRateWhatsApp">
+
+ 沟通数据
+
+ }
key="ResponseRateByWL">
{
- record.key} loading={sale_store.loading_table} pagination={false} scroll={{ x: "100%" }} />
+ record.key} loading={sale_store.loading_table} pagination={false} scroll={{ x: "100%" }} />
+
+ {
+ const wb = utils.table_to_book(document.getElementById("table_to_xlsx_sale").getElementsByTagName("table")[0]);
+ writeFileXLSX(wb, "sale.xlsx");
+ }}>
+ 导出excel
+
+
{sale_store.active_tab_key == "All" ? : ""}
diff --git a/src/views/Sale_sub.js b/src/views/Sale_sub.js
index a2be3bd..ed7a97d 100644
--- a/src/views/Sale_sub.js
+++ b/src/views/Sale_sub.js
@@ -30,13 +30,13 @@ const Sale_sub = () => {
{!comm.empty(type_data.dataSource) &&
- type_data.dataSource.map((item) => {
+ type_data.dataSource.map(item => {
return (
-
+
{item.subType_name}
- record.key} loading={sale_store.loading_table} pagination={false} scroll={{ x: "100%" }} />
+ record.key} loading={sale_store.loading_table} pagination={false} scroll={{ x: "100%" }} />
);
})}