From f6134e7b4b5011f99c31397ae936b787de634960 Mon Sep 17 00:00:00 2001 From: YCC Date: Fri, 1 Sep 2023 16:39:35 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9F=B1=E7=8A=B6?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/SaleStore.js | 817 ++++++++++++++++++++-------------------- src/views/Sale.jsx | 502 ++++++++++++++---------- 2 files changed, 711 insertions(+), 608 deletions(-) diff --git a/src/stores/SaleStore.js b/src/stores/SaleStore.js index 66baf58..0ed662f 100644 --- a/src/stores/SaleStore.js +++ b/src/stores/SaleStore.js @@ -1,425 +1,442 @@ -import { makeAutoObservable, runInAction } from "mobx"; -import moment from "moment"; -import * as config from "../config"; -import * as comm from "../utils/commons"; -import { NavLink } from "react-router-dom"; +import { makeAutoObservable, runInAction } from 'mobx'; +import moment from 'moment'; +import * as config from '../config'; +import * as comm from '../utils/commons'; +import { NavLink } from 'react-router-dom'; import { groupsMappedByCode } from './../libs/ht'; // 销售数据 class SaleStore { - constructor(rootStore) { - this.rootStore = rootStore; - makeAutoObservable(this); - } + constructor(rootStore) { + this.rootStore = rootStore; + makeAutoObservable(this); + } - loading = false; - loading_table = false; - spinning = false; // 加载状态 - active_tab_key = "All"; // 当前选择的标签 - group_select_mode = false; - groups = [groupsMappedByCode.GH.key]; // 默认GH事业部 - filter_country=[];// 筛选国籍 - filter_guest_type=[];// 筛选客户关系 - site_select_mode = false; // 是否多选站点 - include_tickets = "1"; // 是否包含门票,1是含有,0不含 - webcode = "ALL"; - date_type = "ConfirmDate"; - ml_data = []; // 毛利数据 - type_data = []; // 类型的数据 - type_data_sub = []; // 类型的子维度数据 - date_title = "date_title"; // 日期段,只用于显示,防止日期选择控件的变化导致页面刷新 + loading = false; + loading_table = false; + spinning = false; // 加载状态 + active_tab_key = 'All'; // 当前选择的标签 + group_select_mode = false; + groups = [groupsMappedByCode.GH.key]; // 默认GH事业部 + filter_country = []; // 筛选国籍 + filter_guest_type = []; // 筛选客户关系 + site_select_mode = false; // 是否多选站点 + include_tickets = '1'; // 是否包含门票,1是含有,0不含 + webcode = 'ALL'; + date_type = 'ConfirmDate'; + ml_data = []; // 毛利数据 + type_data = []; // 类型的数据 + type_data_sub = []; // 类型的子维度数据 + date_title = 'date_title'; // 日期段,只用于显示,防止日期选择控件的变化导致页面刷新 - // 是否包含门票 - handleChange_include_tickets = value => { - this.include_tickets = value; - }; + // 是否包含门票 + handleChange_include_tickets = (value) => { + this.include_tickets = value; + }; - // 选择事业部 - group_handleChange(value) { - this.groups = value; - } + // 选择事业部 + group_handleChange(value) { + this.groups = value; + } - // 选择站点 - handleChange_webcode = value => { - this.webcode = value; - }; + // 选择站点 + handleChange_webcode = (value) => { + this.webcode = value; + }; - // 切换标签页 - onChange_Tabs(active_key) { - this.active_tab_key = active_key; - } + // 切换标签页 + onChange_Tabs(active_key) { + this.active_tab_key = active_key; + } - // 下单日期或者出发日期 - onChange_datetype(value) { - this.date_type = value; - } + // 下单日期或者出发日期 + onChange_datetype(value) { + this.date_type = value; + } - // 选择客源国 - onChange_Country(value) { - this.filter_country = value; - } + // 选择客源国 + onChange_Country(value) { + this.filter_country = value; + } - // 选择成员关系 - onChange_GuestGroupType(value) { - this.filter_guest_type = value; - } + // 选择成员关系 + onChange_GuestGroupType(value) { + this.filter_guest_type = value; + } - // 获取业绩信息 - get_department_order_ml(date_moment) { - let result = []; - const date1_start = date_moment.start_date.format(config.DATE_FORMAT); - const date1_end = date_moment.end_date.format(config.DATE_FORMAT); - const date2_start = comm.empty(date_moment.start_date_cp) ? "" : date_moment.start_date_cp.format(config.DATE_FORMAT); - const date2_end = comm.empty(date_moment.end_date_cp) ? "" : date_moment.end_date_cp.format(config.DATE_FORMAT); - this.loading = true; - this.date_title = `${date1_start}~${date1_end}`; - let url = "/service-web/QueryData/GetDepartmentOrderML"; - url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; - url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; - if (date2_start && date2_end) { - url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; - this.date_title += ` ${date2_start}~${date2_end}`; - } - fetch(config.HT_HOST + url) - .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) { - // result.push({ - // COLI_Date: moment(item.COLI_Date).add(diff_days, "days").format(config.DATE_FORMAT), - // COLI_YJLY: item.COLI_YJLY, - // groups: item.groups, - // key: item.key, - // }); - // } - // } - runInAction(() => { - this.ml_data = result; - this.loading = false; - }); - }) - .catch(error => { - this.loading = false; - console.log("fetch data failed", error); - }); - } + // 获取业绩信息 + get_department_order_ml(date_moment) { + let result = []; + const date1_start = date_moment.start_date.format(config.DATE_FORMAT); + const date1_end = date_moment.end_date.format(config.DATE_FORMAT); + const date2_start = comm.empty(date_moment.start_date_cp) ? '' : date_moment.start_date_cp.format(config.DATE_FORMAT); + const date2_end = comm.empty(date_moment.end_date_cp) ? '' : date_moment.end_date_cp.format(config.DATE_FORMAT); + this.loading = true; + this.date_title = `${date1_start}~${date1_end}`; + let url = '/service-web/QueryData/GetDepartmentOrderML'; + url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; + url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; + if (date2_start && date2_end) { + url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; + this.date_title += ` ${date2_start}~${date2_end}`; + } + fetch(config.HT_HOST + url) + .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) { + // result.push({ + // COLI_Date: moment(item.COLI_Date).add(diff_days, "days").format(config.DATE_FORMAT), + // COLI_YJLY: item.COLI_YJLY, + // groups: item.groups, + // key: item.key, + // }); + // } + // } + runInAction(() => { + this.ml_data = result; + this.loading = false; + }); + }) + .catch((error) => { + this.loading = false; + console.log('fetch data failed', error); + }); + } - // 按类型获取业绩 - get_department_order_ml_by_type(date_moment) { - const result = { dataSource: [], columns: [] }; - const date1_start = date_moment.start_date.format(config.DATE_FORMAT); - const date1_end = date_moment.end_date.format(config.DATE_FORMAT); - const date2_start = comm.empty(date_moment.start_date_cp) ? "" : date_moment.start_date_cp.format(config.DATE_FORMAT); - const date2_end = comm.empty(date_moment.end_date_cp) ? "" : date_moment.end_date_cp.format(config.DATE_FORMAT); - this.loading_table = true; - this.date_title = `${date1_start}~${date1_end}`; - let url = "/service-web/QueryData/GetDepartmentOrderMLByType"; - url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&OrderType=${this.active_tab_key}&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; - url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; - if (date2_start && date2_end) { - url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; - this.date_title += ` ${date2_start}~${date2_end}`; - } - fetch(config.HT_HOST + url) - .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") { - result.columns = [ - { - title: "", - children: [ - { - title: "", - dataIndex: "OPI_Name", - }, - ], - }, - { - title: "毛利", - children: [{ title: json.result1.reduce((a, b) => a + comm.price_to_number(b.COLI_ML), 0), dataIndex: "COLI_ML" }], - sorter: (a, b) => comm.price_to_number(b.COLI_ML) - comm.price_to_number(a.COLI_ML), - }, - { - title: "成行率", - children: [{ title: comm.formatPercent(json.result1.reduce((a, b) => a + b.COLI_CJCount, 0) / json.result1.reduce((a, b) => a + b.COLI_OrderCount, 0)), dataIndex: "COLI_CJrate" }], - sorter: (a, b) => parseInt(b.COLI_CJrate) - parseInt(a.COLI_CJrate), - }, - { - title: "成团数", - children: [{ title: json.result1.reduce((a, b) => a + b.COLI_CJCount, 0), dataIndex: "COLI_CJCount" }], - sorter: (a, b) => b.COLI_CJCount - a.COLI_CJCount, - }, - { - title: "订单数", - children: [{ title: json.result1.reduce((a, b) => a + b.COLI_OrderCount, 0), dataIndex: "COLI_OrderCount" }], - sorter: (a, b) => b.COLI_OrderCount - a.COLI_OrderCount, - }, - { - title: "单团毛利", - children: [{ title: "", dataIndex: "COLI_SingleML" }], - sorter: (a, b) => comm.price_to_number(b.COLI_SingleML) - comm.price_to_number(a.COLI_SingleML), - }, - { - title: "成团周期", - children: [{ title: "", dataIndex: "COLI_Cycle" }], - sorter: (a, b) => b.COLI_Cycle - a.COLI_Cycle, - }, - ]; - result.dataSource = json.result1; - } else if (this.active_tab_key === "ResponseRateByWL") { - result.columns = [ - { - title: "", - children: [ - { - title: "", - dataIndex: "OPI_Name", - }, - ], - }, - { - title: "报价次数", - children: [{ title: json.result1.reduce((a, b) => a + b.PriceTime, 0), dataIndex: "PriceTime" }], - sorter: (a, b) => b.PriceTime - a.PriceTime, - }, - { - title: "邮件发送次数", - children: [{ title: json.result1.reduce((a, b) => a + b.mailSendTime, 0), dataIndex: "mailSendTime" }], - sorter: (a, b) => b.mailSendTime - a.mailSendTime, - }, - { - title: "WhatsApp客人会话次数", - children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppGuestChatCount, 0), dataIndex: "WhatsAppGuestChatCount" }], - sorter: (a, b) => b.WhatsAppGuestChatCount - a.WhatsAppGuestChatCount, - }, - { - title: "WhatsApp外联会话次数", - children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppWLChatCount, 0), dataIndex: "WhatsAppWLChatCount" }], - sorter: (a, b) => b.WhatsAppWLChatCount - a.WhatsAppWLChatCount, - }, - { - title: "WhatsApp新增客户数", - children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppNewGuestCount, 0), dataIndex: "WhatsAppNewGuestCount" }], - sorter: (a, b) => b.WhatsAppNewGuestCount - a.WhatsAppNewGuestCount, - }, - { - title: "微信客人会话次数", - children: [{ title: json.result1.reduce((a, b) => a + b.WXGuestChatCount, 0), dataIndex: "WXGuestChatCount" }], - sorter: (a, b) => b.WXGuestChatCount - a.WXGuestChatCount, - }, - { - title: "微信外联会话次数", - children: [{ title: json.result1.reduce((a, b) => a + b.WXWLChatCount, 0), dataIndex: "WXWLChatCount" }], - sorter: (a, b) => b.WXWLChatCount - a.WXWLChatCount, - }, - { - title: "微信新增客户数", - children: [{ title: json.result1.reduce((a, b) => a + b.WXNewGuestCount, 0), dataIndex: "WXNewGuestCount" }], - sorter: (a, b) => b.WXNewGuestCount - a.WXNewGuestCount, - }, - ]; - result.dataSource = json.result1; - } else if (this.active_tab_key === "ResponseRateWhatsApp") { - result.columns = [ - { - title: "", - children: [ - { - title: "", - dataIndex: "OPI_Name", - }, - ], - }, - { - title: "首次回复率", - children: [{ title: "", dataIndex: "firstReplayRate", render: (text, record) => {text} }], - sorter: (a, b) => parseInt(b.firstReplayRate) - parseInt(a.firstReplayRate), - }, - { - title: "一次报价率", - children: [{ title: "", dataIndex: "FirstQuotationRate", render: (text, record) => {text} }], - sorter: (a, b) => parseInt(b.FirstQuotationRate) - parseInt(a.FirstQuotationRate), - }, - { - title: "一次报价回复率", - children: [{ title: "", dataIndex: "FirstQuotationReplayRate", render: (text, record) => {text} }], - sorter: (a, b) => parseInt(b.FirstQuotationReplayRate) - parseInt(a.FirstQuotationReplayRate), - }, - { - title: "一次报价回复周期", - children: [{ title: "", dataIndex: "FirstQuotationReplaytimeAVG" }], - sorter: (a, b) => b.FirstQuotationReplaytimeAVG - a.FirstQuotationReplaytimeAVG, - }, - { - title: "二次报价率", - children: [{ title: "", dataIndex: "SecondQuotationRate", render: (text, record) => {text} }], - sorter: (a, b) => parseInt(b.SecondQuotationRate) - parseInt(a.SecondQuotationRate), - }, - { - title: "二次报价回复率", - children: [{ title: "", dataIndex: "SecondQuotationReplayRate", render: (text, record) => {text} }], - sorter: (a, b) => parseInt(b.SecondQuotationReplayRate) - parseInt(a.SecondQuotationReplayRate), - }, - { - title: "二次报价回复周期", - children: [{ title: "", dataIndex: "SecondQuotationReplaytimeAVG" }], - sorter: (a, b) => b.SecondQuotationReplaytimeAVG - a.SecondQuotationReplaytimeAVG, - }, - { - title: "成团率", - children: [{ title: "", dataIndex: "COLI_SuccessRate" }], - sorter: (a, b) => parseInt(b.COLI_SuccessRate) - parseInt(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") - // 获取类型的项目,去掉重复,作为列名 - const type_name_arr = []; - json.result1.map(item => { - type_name_arr[item.SubTypeSN] = { SubTypeSN: item.SubTypeSN, SubTypeName: item.SubTypeName }; + // 按类型获取业绩 + get_department_order_ml_by_type(date_moment) { + const result = { dataSource: [], columns: [] }; + const date1_start = date_moment.start_date.format(config.DATE_FORMAT); + const date1_end = date_moment.end_date.format(config.DATE_FORMAT); + const date2_start = comm.empty(date_moment.start_date_cp) ? '' : date_moment.start_date_cp.format(config.DATE_FORMAT); + const date2_end = comm.empty(date_moment.end_date_cp) ? '' : date_moment.end_date_cp.format(config.DATE_FORMAT); + this.loading_table = true; + this.date_title = `${date1_start}~${date1_end}`; + let url = '/service-web/QueryData/GetDepartmentOrderMLByType'; + url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&OrderType=${this.active_tab_key}&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; + url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; + if (date2_start && date2_end) { + url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; + this.date_title += ` ${date2_start}~${date2_end}`; + } + fetch(config.HT_HOST + url) + .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') { + result.columns = [ + { + title: '', + children: [ + { + title: '', + dataIndex: 'OPI_Name', + }, + ], + }, + { + title: '毛利', + children: [{ title: json.result1.reduce((a, b) => a + comm.price_to_number(b.COLI_ML), 0), dataIndex: 'COLI_ML' }], + sorter: (a, b) => comm.price_to_number(b.COLI_ML) - comm.price_to_number(a.COLI_ML), + }, + { + title: '成行率', + children: [{ title: comm.formatPercent(json.result1.reduce((a, b) => a + b.COLI_CJCount, 0) / json.result1.reduce((a, b) => a + b.COLI_OrderCount, 0)), dataIndex: 'COLI_CJrate' }], + sorter: (a, b) => parseInt(b.COLI_CJrate) - parseInt(a.COLI_CJrate), + }, + { + title: '成团数', + children: [{ title: json.result1.reduce((a, b) => a + b.COLI_CJCount, 0), dataIndex: 'COLI_CJCount' }], + sorter: (a, b) => b.COLI_CJCount - a.COLI_CJCount, + }, + { + title: '订单数', + children: [{ title: json.result1.reduce((a, b) => a + b.COLI_OrderCount, 0), dataIndex: 'COLI_OrderCount' }], + sorter: (a, b) => b.COLI_OrderCount - a.COLI_OrderCount, + }, + { + title: '单团毛利', + children: [{ title: '', dataIndex: 'COLI_SingleML' }], + sorter: (a, b) => comm.price_to_number(b.COLI_SingleML) - comm.price_to_number(a.COLI_SingleML), + }, + { + title: '成团周期', + children: [{ title: '', dataIndex: 'COLI_Cycle' }], + sorter: (a, b) => b.COLI_Cycle - a.COLI_Cycle, + }, + ]; + result.dataSource = json.result1; + } else if (this.active_tab_key === 'ResponseRateByWL') { + result.columns = [ + { + title: '', + children: [ + { + title: '', + dataIndex: 'OPI_Name', + }, + ], + }, + { + title: '报价次数', + children: [{ title: json.result1.reduce((a, b) => a + b.PriceTime, 0), dataIndex: 'PriceTime' }], + sorter: (a, b) => b.PriceTime - a.PriceTime, + }, + { + title: '邮件发送次数', + children: [{ title: json.result1.reduce((a, b) => a + b.mailSendTime, 0), dataIndex: 'mailSendTime' }], + sorter: (a, b) => b.mailSendTime - a.mailSendTime, + }, + { + title: 'WhatsApp客人会话次数', + children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppGuestChatCount, 0), dataIndex: 'WhatsAppGuestChatCount' }], + sorter: (a, b) => b.WhatsAppGuestChatCount - a.WhatsAppGuestChatCount, + }, + { + title: 'WhatsApp外联会话次数', + children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppWLChatCount, 0), dataIndex: 'WhatsAppWLChatCount' }], + sorter: (a, b) => b.WhatsAppWLChatCount - a.WhatsAppWLChatCount, + }, + { + title: 'WhatsApp新增客户数', + children: [{ title: json.result1.reduce((a, b) => a + b.WhatsAppNewGuestCount, 0), dataIndex: 'WhatsAppNewGuestCount' }], + sorter: (a, b) => b.WhatsAppNewGuestCount - a.WhatsAppNewGuestCount, + }, + { + title: '微信客人会话次数', + children: [{ title: json.result1.reduce((a, b) => a + b.WXGuestChatCount, 0), dataIndex: 'WXGuestChatCount' }], + sorter: (a, b) => b.WXGuestChatCount - a.WXGuestChatCount, + }, + { + title: '微信外联会话次数', + children: [{ title: json.result1.reduce((a, b) => a + b.WXWLChatCount, 0), dataIndex: 'WXWLChatCount' }], + sorter: (a, b) => b.WXWLChatCount - a.WXWLChatCount, + }, + { + title: '微信新增客户数', + children: [{ title: json.result1.reduce((a, b) => a + b.WXNewGuestCount, 0), dataIndex: 'WXNewGuestCount' }], + sorter: (a, b) => b.WXNewGuestCount - a.WXNewGuestCount, + }, + ]; + result.dataSource = json.result1; + } else if (this.active_tab_key === 'ResponseRateWhatsApp') { + result.columns = [ + { + title: '', + children: [ + { + title: '', + dataIndex: 'OPI_Name', + }, + ], + }, + { + title: '首次回复率', + children: [{ title: '', dataIndex: 'firstReplayRate', render: (text, record) => {text} }], + sorter: (a, b) => parseInt(b.firstReplayRate) - parseInt(a.firstReplayRate), + }, + { + title: '一次报价率', + children: [{ title: '', dataIndex: 'FirstQuotationRate', render: (text, record) => {text} }], + sorter: (a, b) => parseInt(b.FirstQuotationRate) - parseInt(a.FirstQuotationRate), + }, + { + title: '一次报价回复率', + children: [ + { + title: '', + dataIndex: 'FirstQuotationReplayRate', + render: (text, record) => {text}, + }, + ], + sorter: (a, b) => parseInt(b.FirstQuotationReplayRate) - parseInt(a.FirstQuotationReplayRate), + }, + { + title: '一次报价回复周期', + children: [{ title: '', dataIndex: 'FirstQuotationReplaytimeAVG' }], + sorter: (a, b) => b.FirstQuotationReplaytimeAVG - a.FirstQuotationReplaytimeAVG, + }, + { + title: '二次报价率', + children: [ + { + title: '', + dataIndex: 'SecondQuotationRate', + render: (text, record) => {text}, + }, + ], + sorter: (a, b) => parseInt(b.SecondQuotationRate) - parseInt(a.SecondQuotationRate), + }, + { + title: '二次报价回复率', + children: [ + { + title: '', + dataIndex: 'SecondQuotationReplayRate', + render: (text, record) => {text}, + }, + ], + sorter: (a, b) => parseInt(b.SecondQuotationReplayRate) - parseInt(a.SecondQuotationReplayRate), + }, + { + title: '二次报价回复周期', + children: [{ title: '', dataIndex: 'SecondQuotationReplaytimeAVG' }], + sorter: (a, b) => b.SecondQuotationReplaytimeAVG - a.SecondQuotationReplaytimeAVG, + }, + { + title: '成团率', + children: [{ title: '', dataIndex: 'COLI_SuccessRate' }], + sorter: (a, b) => parseInt(b.COLI_SuccessRate) - parseInt(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") + // 获取类型的项目,去掉重复,作为列名 + const type_name_arr = []; + json.result1.map((item) => { + type_name_arr[item.SubTypeSN] = { SubTypeSN: item.SubTypeSN, SubTypeName: item.SubTypeName }; return item; - }); + }); - const type_data = []; - const type_data_arr = []; + const type_data = []; + const type_data_arr = []; - for (const item of json.result1) { - const op_sn = "OP_" + item.OPI_SN; // 顾问的SN - const items = json.result1.filter(d => String(d.OPI_SN) === String(item.OPI_SN)); // 筛选出有当前顾问的记录 - const 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 => { - type_data_arr.push( - Object.assign( - ...item.map(it => { - return it; - }) - ) - ); + for (const item of json.result1) { + const op_sn = 'OP_' + item.OPI_SN; // 顾问的SN + const items = json.result1.filter((d) => String(d.OPI_SN) === String(item.OPI_SN)); // 筛选出有当前顾问的记录 + const 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) => { + type_data_arr.push( + Object.assign( + ...item.map((it) => { + return it; + }) + ) + ); return item; - }); - result.columns.push( - { title: "顾问", children: [{ title: "", dataIndex: "T_name", render: (text, record) => {text} }] }, - { title: "合计", children: [{ title: type_data_arr.reduce((a, b) => a + b.T_total, 0), dataIndex: "T_total" }], sorter: (a, b) => b.T_total - a.T_total } - ); - Object.values(type_name_arr).map((item, index) => { - const data_index = "T_" + item.SubTypeSN; - const items = type_data_arr.filter(d => d[data_index]); // 筛选出有对应类型的记录 - const total_data_value = items.length ? items.reduce((a, b) => a + b[data_index], 0) : ""; // 记录累加 - result.columns.push({ - title: item.SubTypeName, - children: [{ title: total_data_value, dataIndex: data_index }], - sorter: (a, b) => b[data_index] - a[data_index], - }); + }); + result.columns.push( + { title: '顾问', children: [{ title: '', dataIndex: 'T_name', render: (text, record) => {text} }] }, + { title: '合计', children: [{ title: type_data_arr.reduce((a, b) => a + b.T_total, 0), dataIndex: 'T_total' }], sorter: (a, b) => b.T_total - a.T_total } + ); + Object.values(type_name_arr).map((item, index) => { + const data_index = 'T_' + item.SubTypeSN; + const items = type_data_arr.filter((d) => d[data_index]); // 筛选出有对应类型的记录 + const total_data_value = items.length ? items.reduce((a, b) => a + b[data_index], 0) : ''; // 记录累加 + result.columns.push({ + title: item.SubTypeName, + children: [{ title: total_data_value, dataIndex: data_index }], + sorter: (a, b) => b[data_index] - a[data_index], + }); return item; - }); - result.dataSource = type_data_arr; - } - } - runInAction(() => { - this.type_data = result; - this.loading_table = false; - }); - }) - .catch(error => { - this.loading_table = false; - console.log("fetch data failed", error); - }); - } + }); + result.dataSource = type_data_arr; + } + } + runInAction(() => { + this.type_data = result; + this.loading_table = false; + }); + }) + .catch((error) => { + this.loading_table = false; + console.log('fetch data failed', error); + }); + } - // 子维度查询 - get_department_order_ml_by_type_sub(date_moment, type_sub) { - this.spinning = true; - const result = { dataSource: [], columns: [] }; - const date1_start = date_moment.start_date.format(config.DATE_FORMAT); - const date1_end = date_moment.end_date.format(config.DATE_FORMAT); - const date2_start = comm.empty(date_moment.start_date_cp) ? "" : date_moment.start_date_cp.format(config.DATE_FORMAT); - const date2_end = comm.empty(date_moment.end_date_cp) ? "" : date_moment.end_date_cp.format(config.DATE_FORMAT); - let url = "/service-web/QueryData/GetDepartmentOrderMLByType_sub"; - url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&subType=${type_sub}&subTypeVal=-1&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; - url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; - if (date2_start && date2_end) { - url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; - this.date_title += ` ${date2_start}~${date2_end}`; - } - fetch(config.HT_HOST + url) - .then(response => response.json()) - .then(json => { - if (!comm.empty(json.result2) && !comm.empty(date_moment.start_date_cp)) { - } else { - result.columns = [ - { - title: "", - dataIndex: "OPI_Name", - }, - { - title: "毛利", - dataIndex: "COLI_ML", - sorter: (a, b) => b.COLI_ML - a.COLI_ML, - }, - { - title: "成行率", - dataIndex: "COLI_CJrate", - sorter: (a, b) => parseFloat(b.COLI_CJrate) - parseFloat(a.COLI_CJrate), - }, - { - title: "成团数", - dataIndex: "COLI_CJCount", - }, - { - title: "订单数", - dataIndex: "COLI_OrderCount", - sorter: (a, b) => b.COLI_OrderCount - a.COLI_OrderCount, - }, - { - title: "单团毛利", - dataIndex: "COLI_SingleML", - }, - { - title: "成团周期", - dataIndex: "COLI_Cycle", - }, - ]; - // 数据处理,把相同类型放入同一个数组 - const type_data = []; - !comm.empty(json.result1) && - Object.values(json.result1).map(item => { - const 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] }; - } else { - type_data[subtype_sn].data.push(item); - } + // 子维度查询 + get_department_order_ml_by_type_sub(date_moment, type_sub) { + this.spinning = true; + const result = { dataSource: [], columns: [] }; + const date1_start = date_moment.start_date.format(config.DATE_FORMAT); + const date1_end = date_moment.end_date.format(config.DATE_FORMAT); + const date2_start = comm.empty(date_moment.start_date_cp) ? '' : date_moment.start_date_cp.format(config.DATE_FORMAT); + const date2_end = comm.empty(date_moment.end_date_cp) ? '' : date_moment.end_date_cp.format(config.DATE_FORMAT); + let url = '/service-web/QueryData/GetDepartmentOrderMLByType_sub'; + url += `?DepartmentList=${this.groups.toString()}&DateType=${this.date_type}&subType=${type_sub}&subTypeVal=-1&WebCode=${this.webcode}&IncludeTickets=${this.include_tickets}`; + url += `&Date1=${date1_start}&Date2=${date1_end}%2023:59:59`; + if (date2_start && date2_end) { + url += `&OldDate1=${date2_start}&OldDate2=${date2_end}%2023:59:59`; + this.date_title += ` ${date2_start}~${date2_end}`; + } + fetch(config.HT_HOST + url) + .then((response) => response.json()) + .then((json) => { + if (!comm.empty(json.result2) && !comm.empty(date_moment.start_date_cp)) { + } else { + result.columns = [ + { + title: '', + dataIndex: 'OPI_Name', + }, + { + title: '毛利', + dataIndex: 'COLI_ML', + sorter: (a, b) => b.COLI_ML - a.COLI_ML, + }, + { + title: '成行率', + dataIndex: 'COLI_CJrate', + sorter: (a, b) => parseFloat(b.COLI_CJrate) - parseFloat(a.COLI_CJrate), + }, + { + title: '成团数', + dataIndex: 'COLI_CJCount', + }, + { + title: '订单数', + dataIndex: 'COLI_OrderCount', + sorter: (a, b) => b.COLI_OrderCount - a.COLI_OrderCount, + }, + { + title: '单团毛利', + dataIndex: 'COLI_SingleML', + }, + { + title: '成团周期', + dataIndex: 'COLI_Cycle', + }, + ]; + // 数据处理,把相同类型放入同一个数组 + const type_data = []; + !comm.empty(json.result1) && + Object.values(json.result1).map((item) => { + const 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] }; + } else { + type_data[subtype_sn].data.push(item); + } return item; - }); - result.dataSource = Object.values(type_data); - } - - runInAction(() => { - this.type_data_sub = result; - this.spinning = false; - }); - }) - .catch(error => { - this.spinning = false; - console.log("fetch data failed", error); - }); - } + }); + result.dataSource = Object.values(type_data); + } + runInAction(() => { + this.type_data_sub = result; + this.spinning = false; + }); + }) + .catch((error) => { + this.spinning = false; + console.log('fetch data failed', error); + }); + } } export default SaleStore; diff --git a/src/views/Sale.jsx b/src/views/Sale.jsx index 09be56c..7452982 100644 --- a/src/views/Sale.jsx +++ b/src/views/Sale.jsx @@ -1,122 +1,197 @@ -import React, { useContext, useEffect } from "react"; -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"; -import { observer } from "mobx-react"; -import DatePickerCharts from "../components/search/DatePickerCharts"; -import DataTypeSelect from "../components/search/DataTypeSelect"; -import { NavLink, useParams } from "react-router-dom"; -import * as comm from "../utils/commons"; -import * as config from "../config"; -import SiteSelect from "../components/search/SiteSelect"; -import GroupSelect from "../components/search/GroupSelect"; -import { utils, writeFileXLSX } from "xlsx"; +import React, { useContext, useEffect } from 'react'; +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, Treemap } from '@ant-design/charts'; +import { observer } from 'mobx-react'; +import DatePickerCharts from '../components/search/DatePickerCharts'; +import DataTypeSelect from '../components/search/DataTypeSelect'; +import { NavLink, useParams } from 'react-router-dom'; +import * as comm from '../utils/commons'; +import * as config from '../config'; +import SiteSelect from '../components/search/SiteSelect'; +import GroupSelect from '../components/search/GroupSelect'; +import { utils, writeFileXLSX } from 'xlsx'; const Sale = () => { - const { sale_store, date_picker_store } = useContext(stores_Context); + const { sale_store, date_picker_store } = useContext(stores_Context); - const ml_data = sale_store.ml_data; // 毛利数据 - const type_data = comm.empty(sale_store.type_data) ? { dataSource: [], columns: [] } : sale_store.type_data; // 毛利数据 + //const ml_data = sale_store.ml_data; // 毛利数据 + const type_data = comm.empty(sale_store.type_data) ? { dataSource: [], columns: [] } : sale_store.type_data; // 毛利数据 - const column_config = { - data: ml_data, - xField: "COLI_Date", - yField: "COLI_YJLY", - seriesField: "groups", - label: { - position: "top", - }, - legend: { - itemValue: { - formatter: (text, item) => { - const items = ml_data.filter(d => d.groups === item.value); // 按分组筛选 - return items.length ? items.reduce((a, b) => a + b.COLI_YJLY, 0) : ""; // 计算总数 - }, - }, - }, - tooltip: { - // customContent: (title, items) => { - // const data = items[0]?.data || {}; - // return `
${title}
${data.seriesField} ${data.yField}
`; - // } - title: (title, datum) => { - return title + " " + comm.getWeek(datum.COLI_Date); // 显示周几 - }, - }, - }; + // const column_config = { + // data: type_data.dataSource, + // xField: 'OPI_Name', + // yField: 'COLI_ML2', + // //seriesField: "OPI_Name", + // label: { + // position: 'top', + // }, + // xAxis: { + // label: { + // autoHide: false, + // autoRotate: true, + // }, + // }, + // // legend: { + // // itemValue: { + // // formatter: (text, item) => { + // // const items = ml_data.filter(d => d.groups === item.value); // 按分组筛选 + // // return items.length ? items.reduce((a, b) => a + b.COLI_ML, 0) : ""; // 计算总数 + // // }, + // // }, + // // }, + // // tooltip: { + // // customContent: (title, items) => { + // // const data = items[0].data || {};console.log(data); + // // return `
${title}
wwwwwww
`; + // // }, + // // title: (title, datum) => { + // // return title; // + " " + comm.getWeek(datum.COLI_Date); // 显示周几 + // // }, + // // }, + // }; - // 格式化数据,饼图只支持数字模式 - const format_data_for_pie = (data = []) => { - return data.map(item => ({...item, COLI_ML_number: comm.price_to_number(item.COLI_ML)})); - }; + const column_config_create = (tab_name) => { + let config_data = { + //seriesField: "OPI_Name", + label: { + position: 'top', + }, + xAxis: { + label: { + autoHide: false, + autoRotate: true, + }, + }, + // legend: { + // itemValue: { + // formatter: (text, item) => { + // const items = ml_data.filter(d => d.groups === item.value); // 按分组筛选 + // return items.length ? items.reduce((a, b) => a + b.COLI_ML, 0) : ""; // 计算总数 + // }, + // }, + // }, + // tooltip: { + // customContent: (title, items) => { + // const data = items[0].data || {};console.log(data); + // return `
${title}
wwwwwww
`; + // }, + // title: (title, datum) => { + // return title; // + " " + comm.getWeek(datum.COLI_Date); // 显示周几 + // }, + // },}; + }; + switch (tab_name) { + case 'All': + config_data.data = type_data.dataSource; + config_data.xField = 'OPI_Name'; + config_data.yField = 'COLI_ML2'; + break; + case 'ResponseRateWhatsApp': + config_data.data = type_data.dataSource; + config_data.xField = 'OPI_Name'; + config_data.yField = 'COLI_ConfirmTimeAVG'; + break; + case 'ResponseRateByWL': + config_data.data = type_data.dataSource; + config_data.xField = 'OPI_Name'; + config_data.yField = 'PriceTime'; + break; + default: + config_data.data = []; + break; + } + return config_data; + }; + const column_config = column_config_create(sale_store.active_tab_key); - const pie_config = { - appendPadding: 10, - data: format_data_for_pie(type_data.dataSource), - angleField: "COLI_ML_number", - colorField: "OPI_Name", - radius: 0.8, - label: { - type: "outer", - content: "{name} {value} \n {percentage}", - }, - legend: false, // 不显示图例 - interactions: [ - { - type: "element-selected", - }, - { - type: "element-active", - }, - ], - }; + // 直方图,先隐藏 + // const format_data_for_treemap=(data=[])=>{ + // const children_array= data.map(item => ({...item, name: item.OPI_Name,value:item.COLI_ML2})); + // return { + // name: 'root', + // children:children_array, + // }; + // }; - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - + // const treemap_config={ + // data:format_data_for_treemap(type_data.dataSource), + // colorField: 'OPI_Name', + // }; + + //格式化数据,饼图只支持数字模式 + const format_data_for_pie = (data = []) => { + return data.map((item) => ({ ...item, COLI_ML_number: comm.price_to_number(item.COLI_ML) })); + }; + + const pie_config = { + appendPadding: 10, + data: format_data_for_pie(type_data.dataSource), + angleField: 'COLI_ML_number', + colorField: 'OPI_Name', + radius: 0.8, + label: { + type: 'outer', + content: '{name} {value} \n {percentage}', + }, + legend: false, // 不显示图例 + interactions: [ + { + type: 'element-selected', + }, + { + type: 'element-active', + }, + ], + }; - {/* + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + - - - - - - - + + + + - - { - sale_store.onChange_Tabs(active_key); - sale_store.get_department_order_ml_by_type(date_picker_store); - }}> - - 总览 - - } - key="All"> - - 回复率 - - } - key="ResponseRateWhatsApp"> - - 沟通数据 - - } - key="ResponseRateByWL"> - - 国籍 - - } - key="Country"> - - - 产品类型 - - } - key="Product"> - - - 出行目的 - - } - key="TravelMotivation"> - - - 成员关系 - - } - key="GuestGroupType"> - - - - 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" ? : ""} - - - - - - ); + + { + sale_store.onChange_Tabs(active_key); + sale_store.get_department_order_ml_by_type(date_picker_store); + }} + > + + 总览 + + } + key="All" + > + + 回复率 + + } + key="ResponseRateWhatsApp" + > + + 沟通数据 + + } + key="ResponseRateByWL" + > + + 国籍 + + } + key="Country" + > + + + 产品类型 + + } + key="Product" + > + + + 出行目的 + + } + key="TravelMotivation" + > + + + 成员关系 + + } + key="GuestGroupType" + > + + + +
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' ? : ''} + + {/* + + */} + + + + + ); }; export default observer(Sale); From a816e9a9de0756a08f93c9ba96bf6a6005bf4e00 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Sat, 9 Sep 2023 02:00:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?todo:=20KPI=20=E8=AE=BE=E7=BD=AE=E5=92=8C?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 5 +- src/mock/2.0/trade.json | 12 +++- src/stores/Index.js | 3 +- src/stores/KPI.js | 106 +++++++++++++++++++++++++++ src/utils/commons.js | 19 +++++ src/utils/request.js | 3 +- src/views/KPI.jsx | 156 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 src/stores/KPI.js create mode 100644 src/views/KPI.jsx diff --git a/src/App.jsx b/src/App.jsx index 9689a1b..28f12ec 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -10,7 +10,7 @@ import { DollarOutlined, AreaChartOutlined, WechatOutlined, - UserOutlined, + UserOutlined, FlagOutlined, } from '@ant-design/icons'; import { Layout, Menu, Image, Spin } from 'antd'; import { BrowserRouter, Route, Routes, NavLink } from 'react-router-dom'; @@ -35,6 +35,7 @@ import Logo from './logo.png'; import { stores_Context } from './config'; import { observer } from 'mobx-react'; import ExchangeRate from './charts/ExchangeRate'; +import KPI from './views/KPI'; const App = () => { const { Content, Footer, Sider } = Layout; @@ -119,6 +120,7 @@ const App = () => { }, ], }, + { key: 'kpi', label: 目标, icon: }, ]; return ( @@ -159,6 +161,7 @@ const App = () => { > } /> + } /> }> } /> } /> diff --git a/src/mock/2.0/trade.json b/src/mock/2.0/trade.json index 12d533c..a6bcb13 100644 --- a/src/mock/2.0/trade.json +++ b/src/mock/2.0/trade.json @@ -104,19 +104,19 @@ {} ] }, - "get|/service-web/QueryData/Getkpi": { + "get|/service-Analyse2/getkpi/test": { "errcode": 0, "errmsg": "", "loading": false, "data": null, - "result1|10": [ + "result|10": [ { "object|1": "@pick([\"dept\",\"sales\", \"group\"])", "subject|1": "@pick([\"OrderCount\",\"SumML\", \"AvgML\", \"SuccessRate\"])", "object_id": "@integer(10,100)", "object_name": "@cname", "date_type": "@pick([\"ConfirmDate\",\"startDate\", \"applyDate\"])", - "start_date": "@date(\"yyyy-MM-dd\")", + "start_date": "@date(\"2023-MM-dd\")", "end_date": "@datetime(\"yyyy-MM-dd HH:mm:ss\")", "value": "@integer(99,9999)", "key": "@increment" @@ -124,5 +124,11 @@ "result2": [ {} ] + }, + "post|/service-Analyse2/setkpi_multi/test": { + "errcode": 0, + "errmsg": "", + "loading": false, + "data": null } } diff --git a/src/stores/Index.js b/src/stores/Index.js index d7948a2..45aed26 100644 --- a/src/stores/Index.js +++ b/src/stores/Index.js @@ -11,7 +11,7 @@ import WechatStore from "./Wechat"; import WhatsAppStore from "./WhatsApp"; import CustomerServicesStore from "./CustomerServices"; import TradeStore from "./Trade"; - +import KPI from "./KPI"; class Index { constructor() { this.dashboard_store = new DashboardStore(this); @@ -26,6 +26,7 @@ class Index { this.whatsAppStore = new WhatsAppStore(this); this.customerServicesStore = new CustomerServicesStore(this); this.TradeStore = new TradeStore(this); + this.KPIStore = new KPI(this); makeAutoObservable(this); } diff --git a/src/stores/KPI.js b/src/stores/KPI.js new file mode 100644 index 0000000..ec63aa2 --- /dev/null +++ b/src/stores/KPI.js @@ -0,0 +1,106 @@ +import { makeAutoObservable, runInAction, toJS } from 'mobx'; +import * as req from '../utils/request'; +import { isEmpty, sortBy, groupBy } from '../utils/commons'; +import moment from 'moment'; + +const currentYear = moment().year(); + +class KPI { + constructor(appStore) { + this.appStore = appStore; + makeAutoObservable(this); + } + + saveOrUpdate() { + console.log('ssssssssssss'); + console.log(this.pageData); + const tableData = this.pageData.reduce((r, curObj) => { + const allMonth = new Array(12).fill(1).map((_, index) => { + const mIndex = index+1; + const startM = moment([this.settingYear, index, 1]); + const pick = (({ + object, object_name, object_id, subject,date_type, + }) => ({ + object, object_name, object_id, subject,date_type, + }))(curObj); + return { + ...pick, + start_date: startM.format('YYYY-MM-DD'), + end_date: startM.endOf('M').format('YYYY-MM-DD HH:mm:ss'), + value: curObj[`M${mIndex}`], + // ...(curObj[`M${mIndex}_id`] ? { kpi_id: curObj[`M${mIndex}_id`] } : {}), + kpi_id: curObj[`M${mIndex}_id`] || undefined, + key: undefined, + }; + }); + console.log('cccccccccc', allMonth); + return r.concat(allMonth); + }, []); + console.log('ppppp', tableData); + const data = { + 'kpis': tableData + // [ + // { + // 'kpi_id': '1', + // 'object': 'sales', + // 'subject': 'orderCount', + // 'object_name': '刘莎', + // 'object_id': '15', + // 'date_type': 'confirmDate', + // 'start_date': '2024-01-01', + // 'end_date': '2024-03-31 23:59', + // 'value': '10000', + // }, + // ], + }; + // req.postJSON('/service-Analyse2/setkpi_multi/test', data).then((json) => { + req.postJSON('/service-Analyse2/setkpi_multi', data).then((json) => { + if (json.errcode === 0) { + runInAction(() => { + console.log({ loading: false, ...json }, 'post kpi'); + }); + } + }); + } + + getList() { + const param = { + date_type: 'confirmDate', + start_date: '2024-01-01', + end_date: '2024-12-01', + }; + // req.fetchJSON('/service-Analyse2/getkpi/test', param).then((json) => { + req.fetchJSON('/service-Analyse2/getkpi', param).then((json) => { + if (json.errcode === 0) { + runInAction(() => { + const result = json.result.map((row) => ({ ...row, yearIndex: moment(row.start_date).year(), monthIndex: moment(row.start_date).month() + 1 })); + const byYear = groupBy(result, (ele) => ele.yearIndex); + const yearData = {}; + Object.keys(byYear).map((_yearVal) => { + const _objRet = groupBy(byYear[_yearVal], (ele) => `${ele.object_id}`); + Object.keys(_objRet).map((_obj) => { + _objRet[_obj] = _objRet[_obj].reduce((r, v) => ({ ...r, ...v, [`M${v.monthIndex}`]: v.value, [`M${v.monthIndex}_id`]: v.kpi_id }), {}); + return _obj; + }); + Object.assign(yearData, { [_yearVal]: Object.values(_objRet) }); + return _yearVal; + }); + console.log(111, yearData); + this.pageData = yearData[this.settingYear]; + }); + } + }); + } + + handleTableEdit(data) { + console.log('handle change ', data); + this.pageData = data; + } + + settingYear = 2024; + data = []; + objectData = []; + + pageData = []; +} +export default KPI; diff --git a/src/utils/commons.js b/src/utils/commons.js index e1c856d..5dddfc1 100644 --- a/src/utils/commons.js +++ b/src/utils/commons.js @@ -315,3 +315,22 @@ export function merge(...objects) { return result; } + +/** + * 数组分组 + * - 相当于 lodash 的 _.groupBy + * + * https://www.lodashjs.com/docs/lodash.groupBy#_groupbycollection-iteratee_identity + */ +export function groupBy(array, callback) { + return array.reduce((groups, item) => { + const key = callback(item); + + if (!groups[key]) { + groups[key] = []; + } + + groups[key].push(item); + return groups; + }, {}); +} diff --git a/src/utils/request.js b/src/utils/request.js index 663f389..e9289eb 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -51,7 +51,8 @@ export function postForm(url, data) { } export function postJSON(url, obj) { - return fetch(url, { + const host = /^https?:\/\//i.test(url) ? '': HT_HOST; + return fetch(`${host}${url}`, { method: 'POST', body: JSON.stringify(obj), headers: { diff --git a/src/views/KPI.jsx b/src/views/KPI.jsx new file mode 100644 index 0000000..557386c --- /dev/null +++ b/src/views/KPI.jsx @@ -0,0 +1,156 @@ +import { useContext, useEffect, useState } from 'react'; +import { observer } from 'mobx-react'; +// import type { ProColumns } from '@ant-design/pro-components'; +import { EditableProTable, ProCard, ProFormField } from '@ant-design/pro-components'; +import { Button, Table, Switch } from 'antd'; +import { stores_Context } from '../config'; +import { isEmpty } from './../utils/commons'; + +export default observer((props) => { + const { KPIStore } = useContext(stores_Context); + const { settingYear, pageData, } = KPIStore; + useEffect(() => { + // KPIStore.saveOrUpdate(); + KPIStore.getList(); + return () => {}; + }, []); + const [editOpen, setEditOpen] = useState(false); // test: + const [editableRowsKeys, setEditableRowKeys] = useState([]); + const monthCol = new Array(12).fill(1).map((_, index) => { + return { + title: `${index + 1}月`, + dataIndex: `M${index + 1}`, + valueType: 'percent', + width: '5em', + formItemProps: { + initialValue: [8, 9].includes(index) ? 10 : 8, + }, + fieldProps: { min: 0, max: 100, style: { width: '4em' } }, + }; + }); + const initialRow = monthCol.reduce((r, v) => ({...r, [v.dataIndex]: v.formItemProps.initialValue}), {}); + const columns = [ + { + title: '对象', + dataIndex: 'object_name', + valueType: 'select', + // ...valueEnum + }, + // { + // title: 'Name', + // dataIndex: 'title', + // //...form rules + // formItemProps: { + // rules: [ + // { + // required: true, + // whitespace: true, + // message: '此项是必填项', + // }, + // ], + // }, + // }, + { + title: '目标', + dataIndex: 'value', + valueType: 'digit', + fieldProps: { style: { width: '100%' } }, + formItemProps: { + style: { width: '100%' }, + }, + }, + ...monthCol, + { + title: '完成进度', + dataIndex: 'place', + valueType: 'percent', + editable: false, + width: '6em', + }, + { + title: '操作', + valueType: 'option', + // width: 250, + render: () => { + return null; + }, + }, + ]; + const onChange = (...argrs) => { + console.log(argrs, 'who who who'); + setEditableRowKeys(argrs[0].map((ele) => ele.key)); + // KPIStore.setEditableRowsKeys(argrs[0].map((ele) => ele.key)); + KPIStore.handleTableEdit(argrs[0]); + }; + return ( + <> + ({ + key: pageData.length+1, // Number(Date.now().toString()), + ...initialRow, + object_name: '', + value:0 + }), + } + : false + } + toolBarRender={() => { + return [ + { + setEditOpen(e); + setEditableRowKeys(e ? pageData.map((ele) => ele.key) : []); + // KPIStore.setEditableRowsKeys(e ? pageData.map((ele) => ele.key) : []); + }} + />, + , + ]; + }} + editable={{ + type: 'multiple', + editableKeys: editableRowsKeys, + actionRender: (row, config, defaultDoms) => { + // console.log(row, config, defaultDoms); + return [defaultDoms.delete]; + }, + onValuesChange: (record, recordList) => { + console.log('on edit'); + onChange(recordList); + }, + onChange: (editableKeys, editableRows) => { + onChange(editableRows); + // KPIStore.setEditableRowsKeys() + } + }} + /> + + ); +}); From 6307a8c41cb7f22932e155d916a2805ee69444c8 Mon Sep 17 00:00:00 2001 From: YCC Date: Fri, 15 Sep 2023 14:03:05 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=97=B4=E8=B7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/DestinationGroupCount.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/views/DestinationGroupCount.jsx b/src/views/DestinationGroupCount.jsx index 69669af..decc96b 100644 --- a/src/views/DestinationGroupCount.jsx +++ b/src/views/DestinationGroupCount.jsx @@ -30,14 +30,14 @@ const DestinationGroupCount = () => { return ( <> - - + + customerServicesStore.selectTeam(value)} style={{ width: '95%' }} show_all={true} /> - + - + - + - + { }} /> - + + + - + customerServicesStore.selectTeam(value)} style={{ width: '95%' }} show_all={true} /> - + - + - + { }} /> - +