{data1} vs {data2}
diff --git a/src/components/DateFieldRadio.jsx b/src/components/DataFieldRadio.jsx
similarity index 87%
rename from src/components/DateFieldRadio.jsx
rename to src/components/DataFieldRadio.jsx
index b14047f..773ec5d 100644
--- a/src/components/DateFieldRadio.jsx
+++ b/src/components/DataFieldRadio.jsx
@@ -1,11 +1,11 @@
import { observer } from 'mobx-react';
import { Radio, Select } from 'antd';
-import { dataFieldOptions } from './../libs/ht';
+import { dataFieldOptions } from '../libs/ht';
export default observer((props) => {
const { visible, dataRaw, dataMapper, fieldMapper, onChange, ...extProps } = props;
const handleChange = (value) => {
- console.log('handleChange', value);
+ // console.log('handleChange', value);
if (typeof onChange === 'function') {
onChange(value);
}
diff --git a/src/components/DateGroupRadio/date.js b/src/components/DateGroupRadio/date.js
index 904f5d5..6d08642 100644
--- a/src/components/DateGroupRadio/date.js
+++ b/src/components/DateGroupRadio/date.js
@@ -4,7 +4,7 @@ export const datePartOptions = [
{ label: '日', value: 'day' },
{ label: '周', value: 'week' },
{ label: '月', value: 'month' },
- { label: '季', value: 'quarter' },
+ { label: '季', value: 'season' },
{ label: '年', value: 'year' },
];
export const datePartMethod = {
@@ -20,7 +20,7 @@ export const datePartMethod = {
const dateKey = `${year}-W${String(week).padStart(2, '0')}`;
return { dateKey, 'groupKey': dateKey, date };
},
- 'quarter': (date) => {
+ 'season': (date) => {
const dateO = moment(date);
// const key = dateO.format('YYYY-Q');
const key = `${dateO.year()}-${String(dateO.quarter()).padStart(2, 'Q')}`;
@@ -117,16 +117,19 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper,
}));
const parse2 = parseDateType(_data2, dateGroup, fieldMapper);
const parseData2 = parse2.data.map((ele) => ({
- [fieldMapper.dateKey]: ele.groupKey,
+ [fieldMapper.dateKey]: ele[fieldMapper.dateKey],
+ // [fieldMapper.dateKey]: ele.groupKey,
[fieldMapper.valueKey]: ele.value,
+ [fieldMapper.seriesKey]: ele[fieldMapper.seriesKey],
groups: _data2[0].groups,
dateKey: ele.dateKey,
dateRange: ele.dateRange,
dateGroup: ele[fieldMapper.dateKey],
}));
const useKeys = parseData1.map((ele) => ele[fieldMapper.dateKey]);
- const reindecData2 = parseData2.map((ele, index) => ({ ...ele, [fieldMapper.dateKey]: useKeys[index] || `X.${ele[fieldMapper.dateKey]}`, dateKey: ele.dateKey }));
- const retData = [].concat(parseData1, reindecData2);
+ const reindexData2 = parseData2.map((ele, index) => ({ ...ele, [fieldMapper.dateKey]: useKeys[index] || `_${ele[fieldMapper.dateKey]}`, dateKey: ele.dateKey }));
+ const retData = [].concat(parseData1, reindexData2 );
const avg1 = parse1.avgVal;
+ // console.log('callback', dateGroup, retData);
cb(dateGroup, retData, avg1);
};
diff --git a/src/components/DateGroupRadio/index.jsx b/src/components/DateGroupRadio/index.jsx
index e8b1fd2..16a325f 100644
--- a/src/components/DateGroupRadio/index.jsx
+++ b/src/components/DateGroupRadio/index.jsx
@@ -2,6 +2,10 @@ import { Radio } from 'antd';
import { observer } from 'mobx-react';
import { datePartOptions, resultDataCb } from './date';
+/**
+ * 仅前端转换数据
+ * 把按天的数据转换成 按周,季,月,年
+ */
export default observer((props) => {
const { visible, dataRaw, dataMapper, fieldMapper, onChange, ...extProps } = props;
const _dataMapper = dataMapper || { 'data1': null, data2: null };
diff --git a/src/components/StatisticCard.jsx b/src/components/StatisticCard.jsx
index 9a771f8..e6fe898 100644
--- a/src/components/StatisticCard.jsx
+++ b/src/components/StatisticCard.jsx
@@ -1,10 +1,11 @@
-import { observer } from "mobx-react";
+import { observer } from 'mobx-react';
import { Card, Statistic, Progress } from 'antd';
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
export default observer((props) => {
- const valueStyle = { color: props.VSrate < 0 ? '#3f8600' : '#cf1322' };
- const VSIcon = () => (props.VSrate < 0 ?
:
);
+ const ValueIcon = props.icon;
+ const valueStyle = { color: (props?.VSrate || -1) < 0 ? '#3f8600' : '#cf1322' };
+ const VSIcon = () => ((props?.VSrate || -1) < 0 ?
:
);
return (
{
>
)
}
+ prefix={}
+ // title={{props.title}}
{...props}
+ value={props.valueSuffix ? `${props.value} ${props.valueSuffix}` : props.value}
/>
{props.showProgress !== false &&
diff --git a/src/components/Waterfall.jsx b/src/components/Waterfall.jsx
index 9fc15f0..2ec6bd6 100644
--- a/src/components/Waterfall.jsx
+++ b/src/components/Waterfall.jsx
@@ -5,13 +5,13 @@ import { merge } from '../utils/commons';
export default observer((props) => {
const { dataSource, line, title, ...extProps } = props;
- const yMax = Math.max(line?.value || 0, ...dataSource.map((ele) => ele[extProps.yField]));
+ const yMax = (Math.max(line?.value || 0, ...dataSource.map((ele) => ele[extProps.yField])))*1;
const annotationsLine = line
? [
{
type: 'text',
position: ['start', line.value],
- content: `${line.label} ${line.value / 1000} K`,
+ content: `${line.label} ${line.value / 10000} 万`,
// offsetX: -15,
style: {
fill: '#F4664A',
@@ -36,6 +36,7 @@ export default observer((props) => {
/** 展示总计 */
total: {
+ // label: `${title}总`,
label: `${title}总`,
style: {
fill: '#96a6a6',
@@ -57,6 +58,16 @@ export default observer((props) => {
formatter: (v) => dataFieldAlias[extProps.yField]?.formatter(v) || v,
},
},
+ xAxis: {
+ type: 'cat',
+ },
+ tooltip: {
+ customItems: (originalItems) => {
+ // process originalItems,
+ const items = originalItems.map((ele) => ({ ...ele, title: `${ele.title} ${ele.data.groupsLabel}`, name: dataFieldAlias[ele.name]?.alias || ele.name }));
+ return items;
+ },
+ },
}, extProps);
return (
<>
diff --git a/src/components/kpi/KPISettings.jsx b/src/components/kpi/KPISettings.jsx
new file mode 100644
index 0000000..ecec5d4
--- /dev/null
+++ b/src/components/kpi/KPISettings.jsx
@@ -0,0 +1,79 @@
+import { useContext } from 'react';
+import { observer } from 'mobx-react';
+import { stores_Context } from './../../config';
+import { Typography, Row, Col, Tabs, } from 'antd';
+import SearchForm from './../search/SearchForm';
+import { bu, KPIObjects, KPISubjects } from './../../libs/ht';
+import { isEmpty, fixTo2Decimals, fixTo4Decimals, cloneDeep, numberFormatter, fixToInt, merge } from './../../utils/commons';
+import ProfitTable from './SubjectTable/Profit';
+
+const Todo = (props) => {
+ return
TODO
;
+};
+
+const subjectComponents = {
+ 'sum_profit': ProfitTable,
+ 'in_order_count': Todo,
+ 'confirm_order_count': Todo,
+ 'depart_order_count': Todo,
+ 'confirm_rates': Todo,
+ 'praise_rates': Todo,
+ 'sum_person_num': Todo,
+};
+
+export const KPIObjectsMapped = KPIObjects.reduce((a, c) => ({ ...a, [String(c.key)]: c }), {});
+const { Text } = Typography;
+
+export default observer((props) => {
+ const { KPIStore, DictDataStore, date_picker_store: searchFormStore } = useContext(stores_Context);
+ const { sort, initialValue, hides, shows, fieldProps: _fieldProps } = {
+ sort: '',
+ initialValue: searchFormStore.formValues,
+ fieldProps: {},
+ hides: [],
+ shows: ['DateType', 'years'],
+ ...props.searchProps,
+ };
+ const fieldProps = merge(_fieldProps, { years: { hide_vs: true } });
+ const { curObject, objects, KPISubjects, onSearchSubmit } = props;
+
+ return (
+ <>
+
+
+ {
+ console.log('invoke kpi setting search');
+ if (typeof onSearchSubmit === 'function') {
+ onSearchSubmit(obj);
+ }
+ }}
+ />
+
+
+
+
+ {
+ KPIStore.setSettingSubject(sub);
+ }}
+ items={KPISubjects.map((ele, i) => {
+ const SubjectTableComponent = subjectComponents[ele.key];
+ return {
+ ...ele,
+ children:
+ };
+ })}
+ />
+
+
+ >
+ );
+});
diff --git a/src/components/kpi/ObjectPanel.jsx b/src/components/kpi/ObjectPanel.jsx
new file mode 100644
index 0000000..a78c231
--- /dev/null
+++ b/src/components/kpi/ObjectPanel.jsx
@@ -0,0 +1,23 @@
+import { useContext } from 'react';
+import { observer } from 'mobx-react';
+// import { stores_Context } from '../config';
+import { Table } from 'antd';
+import KPISettings from './KPISettings';
+import { bu, KPISubjects } from '../../libs/ht';
+
+const searchFormItemSet = {
+ 'bu': { shows: ['DateType', 'years', 'HTBusinessUnits'] },
+ 'dept': { shows: ['DateType', 'years', 'DepartmentList'], fieldProps: { DepartmentList: { allowClear: true } } },
+ 'operator': { shows: ['DateType', 'years', 'DepartmentList'] }, // , 'operator'
+ 'destination': { shows: ['DateType', 'years', 'destination'] },
+ 'country': { shows: ['DateType', 'years', 'country'] },
+};
+
+export default observer((props) => {
+ const searchProps = searchFormItemSet?.[props.curObject] || {};
+ return (
+ <>
+
+ >
+ );
+});
diff --git a/src/components/kpi/OverviewPanel.jsx b/src/components/kpi/OverviewPanel.jsx
new file mode 100644
index 0000000..49f8760
--- /dev/null
+++ b/src/components/kpi/OverviewPanel.jsx
@@ -0,0 +1,263 @@
+import { useContext, useState, useEffect, useMemo } from 'react';
+import { observer } from 'mobx-react';
+import { toJS } from 'mobx';
+import moment from 'moment';
+import { stores_Context } from './../../config';
+import { Button, Table, Switch, Input, Space, Typography, Row, Col, Spin, Radio, Tabs, message } from 'antd';
+import { EditableProTable, ProCard, ProFormField } from '@ant-design/pro-components';
+import SearchForm from './../search/SearchForm';
+import { bu } from './../../libs/ht';
+import { isEmpty, objectMapper, fixToInt, fixTo2Decimals, fixTo4Decimals, cloneDeep, numberFormatter } from './../../utils/commons';
+
+const { Text } = Typography;
+const initialPercentKey = new Array(12).fill(1).reduce((r, v, i) => ({ ...r, [`M${i + 1}Percent`]: [8, 9].includes(i) ? 10 : 8 }), {});
+const numberConvert10K = (number, scale = 10) => {
+ return fixTo2Decimals((number/(1000*scale))) + '万';
+};
+
+export default observer((props) => {
+ const { KPIStore, date_picker_store: searchFormStore } = useContext(stores_Context);
+ const { curObject } = props;
+ const [dataSource, setDataSource] = useState([]);
+ useEffect(() => {
+ onSearchSubmit({
+ object: curObject,
+ date_type: 'applyDate',
+ start_date: searchFormStore.start_date.startOf('year').format('YYYY-MM-DD'),
+ end_date: searchFormStore.end_date.endOf('year').format('YYYY-MM-DD 23:59'),
+ });
+ return () => {};
+ }, []);
+
+ const onSearchSubmit = (obj, formVal={}) => {
+ const getkpiParam = objectMapper(obj, { DateType: { key: 'date_type' }, Date1: { key: 'start_date' }, Date2: { key: 'end_date' } });
+ Object.assign(getkpiParam, { object: curObject });
+ KPIStore.setSettingYear(formVal?.year?.year() || KPIStore.settingYear);
+ KPIStore.getList(getkpiParam).then((data) => {
+ setDataSource(data);
+ });
+ };
+ const [editOpen, setEditOpen] = useState(false);
+ const [editableRowsKeys, setEditableRowKeys] = useState([]);
+
+ const PercentInput = useMemo(
+ () =>
+ // eslint-disable-next-line react/display-name
+ ({ value, onChange, record, ...extProps }) => {
+ // // eslint-disable-next-line react-hooks/rules-of-hooks
+ const [inputValue, setInputValue] = useState(value);
+ const handleInputChange = (e) => {
+ setInputValue(e.target.value);
+ onChange?.(e.target.value);
+ };
+ const calcV = inputValue ? numberConvert10K(fixTo4Decimals((Number(record?.yearValue) * inputValue) / 100)) : 0;
+ return (
+
+
+ {calcV}
+
+ );
+ },
+ []
+ );
+ const RenderMonthCell = (row, mon) => {
+ return (
+
+
+ {fixTo2Decimals(row?.[`M${mon}Percent`])}
+ %
+
+ {numberConvert10K(fixTo4Decimals((Number(row?.yearValue) * row?.[`M${mon}Percent`]) / 100))}
+
+ );
+ };
+ const monthCol = new Array(12).fill(1).map((_, index) => {
+ return {
+ title: `${index + 1}月`,
+ dataIndex: `M${index + 1}Percent`,
+ valueType: 'digit',
+ width: '6.5em',
+ // fieldProps: { min: 0, max: 100, style: { width: '4em' } },
+ renderFormItem: ({ dataIndex, ...item }, { record, isEditable, ...e }, form) => {
+ return
;
+ },
+ render: (_, row) => RenderMonthCell(row, index + 1),
+ };
+ });
+ const columns = [
+ {
+ title: '年度目标',
+ dataIndex: 'yearValue',
+ valueType: 'digit',
+ fieldProps: { style: { width: '100%' }, step: 10000 * 100 },
+ formItemProps: {
+ style: { width: '100%' },
+ },
+ render: (_, row, ...a) => numberConvert10K(row.yearValue),
+ },
+ ...monthCol,
+ {
+ title: '操作',
+ valueType: 'option',
+ // width: 250,
+ render: () => {
+ return null;
+ },
+ },
+ ];
+ const onTableChange = (...argrs) => {
+ setEditableRowKeys(argrs[0].map((ele) => ele.key));
+ setDataSource(argrs[0]);
+ };
+ const onTableSubmit = () => {
+ const tableData = dataSource.reduce((r, curObj) => {
+ const allMonth = new Array(12).fill(1).map((_, index) => {
+ const mIndex = index + 1;
+ const mVal = (Number(curObj.yearValue) * Number(curObj[`M${mIndex}Percent`])) / 100;
+ const startM = moment([KPIStore.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'),
+ value: mVal,
+ kpi_id: curObj.kpiDataMapped?.[`M${mIndex}`]?.kpi_id || undefined,
+ key: undefined,
+ };
+ });
+ return r.concat(allMonth);
+ }, []);
+ const yearRow = (({ object, object_name, object_id, subject, date_type, yearValue, kpiYear }) => ({
+ object,
+ object_name,
+ object_id,
+ subject,
+ date_type,
+ value: yearValue,
+ start_date: moment([KPIStore.settingYear, 0, 1]).format('YYYY-MM-DD'),
+ end_date: moment([KPIStore.settingYear, 11, 1]).endOf('M').format('YYYY-MM-DD HH:mm'),
+ kpi_id: kpiYear?.kpi_id || undefined,
+ }))(dataSource?.[0] || {});
+ tableData.unshift(yearRow);
+ console.log('sub', tableData, delKpiIds);
+ // return false; // debug:
+ KPIStore.onSubmit(tableData, {delQueue: delKpiIds}).then((res) => {
+ if (res) {
+ message.success('保存成功');
+ setEditOpen(false);
+ setEditableRowKeys([]);
+ setDelKpiIds([]);
+ onSearchSubmit(searchFormStore.formValuesToSub);
+ return false;
+ }
+ message.error('失败, 请重试');
+ });
+ };
+ const initialRow = monthCol.reduce(
+ (r, v) => ({
+ ...r,
+ [v.dataIndex]: 0,
+ yearValue: 10000*100,
+ object: curObject,
+ object_name: '',
+ object_id: -1,
+ subject: 'sum_profit',
+ date_type: searchFormStore.formValuesToSub.DateType,
+ kpiDataMapped: {},
+ key: Date.now().toString(32)
+ }),
+ {}
+ ); // v.formItemProps.initialValue
+ const makeInitialTable = (e) => {
+ setEditOpen(e);
+ if (e && isEmpty(dataSource)) {
+ const _initialRow = Object.assign({}, initialRow, initialPercentKey);
+ setDataSource([_initialRow]);
+ setEditableRowKeys([_initialRow.key]);
+ return false;
+ }
+ setEditableRowKeys(e ? dataSource.map((ele) => ele.key) : []);
+ };
+ const [delKpiIds, setDelKpiIds] = useState([]);
+ return (
+ <>
+
+
+ {
+ // TradeStore.setStateSearch(form);
+ // pageRefresh(obj);
+ onSearchSubmit(obj, form);
+ setEditOpen(false);
+ setEditableRowKeys([]);
+ }}
+ />
+
+
+
{
+ return [
+ {
+ makeInitialTable(e);
+ }}
+ />,
+ ,
+ ];
+ }}
+ editable={{
+ type: 'multiple',
+ editableKeys: editableRowsKeys,
+ actionRender: (row, config, defaultDoms) => {
+ return [defaultDoms.delete];
+ },
+ onDelete: (_key, _row) => {
+ // console.log('del', _key, _row);
+ const rowKpiIds = (_row?.kpiData || []).map(ele => ele.kpi_id);
+ rowKpiIds.push(_row?.kpiYear?.kpi_id);
+ setDelKpiIds(rowKpiIds);
+ },
+ onValuesChange: (record, recordList) => {
+ // console.log('on edit, onValuesChange',record, recordList);
+ onTableChange(recordList);
+ },
+ onChange: (editableKeys, editableRows) => {
+ setEditableRowKeys(editableKeys);
+ },
+ }}
+ />
+ >
+ );
+});
diff --git a/src/components/kpi/SubjectTable/Profit.jsx b/src/components/kpi/SubjectTable/Profit.jsx
new file mode 100644
index 0000000..777adb4
--- /dev/null
+++ b/src/components/kpi/SubjectTable/Profit.jsx
@@ -0,0 +1,252 @@
+import { useContext, useState, useEffect, useMemo } from 'react';
+import { observer } from 'mobx-react';
+import moment from 'moment';
+import { stores_Context } from './../../../config';
+import { Button, Switch, Input, Space, Typography, Row, Col, message } from 'antd';
+import { EditableProTable } from '@ant-design/pro-components';
+import { KPIObjects } from './../../../libs/ht';
+import { isEmpty, fixTo2Decimals, fixTo4Decimals, cloneDeep, numberFormatter, fixToInt } from './../../../utils/commons';
+
+export const KPIObjectsMapped = KPIObjects.reduce((a, c) => ({ ...a, [String(c.key)]: c }), {});
+const { Text } = Typography;
+const initialPercentKey = new Array(12).fill(1).reduce((r, v, i) => ({ ...r, [`M${i + 1}Percent`]: [8, 9].includes(i) ? 10 : 8 }), {});
+const numberConvert10K = (number, scale = 10) => {
+ return fixTo2Decimals(number / (1000 * scale)) + '万';
+};
+
+export default observer((props) => {
+ const { KPIStore, date_picker_store: searchFormStore } = useContext(stores_Context);
+ const { curObject, objects, onSearchSubmit } = props;
+ const curObjectItem = KPIObjectsMapped[curObject];
+
+ const [dataSource, setDataSource] = useState(KPIStore.pageData);
+ const [editOpen, setEditOpen] = useState(false);
+ const [editableRowsKeys, setEditableRowKeys] = useState([]);
+ useEffect(() => {
+ setDataSource(KPIStore.pageData);
+ setEditOpen(false);
+ return () => {};
+ }, [KPIStore.pageData]);
+
+
+ const PercentInput = useMemo(
+ () =>
+ // eslint-disable-next-line react/display-name
+ ({ value, onChange, record, ...extProps }) => {
+ // // eslint-disable-next-line react-hooks/rules-of-hooks
+ const [inputValue, setInputValue] = useState(value);
+ const handleInputChange = (e) => {
+ setInputValue(e.target.value);
+ onChange?.(e.target.value);
+ };
+ const calcV = inputValue ? numberConvert10K(fixToInt((Number(record?.yearValue) * inputValue) / 100)) : 0;
+ return (
+
+
+ {calcV}
+
+ );
+ },
+ []
+ );
+ const RenderMonthCell = (row, mon) => {
+ return (
+
+
+ {fixTo2Decimals(row?.[`M${mon}Percent`])}
+ %
+
+ {numberConvert10K(fixTo4Decimals((Number(row?.yearValue) * row?.[`M${mon}Percent`]) / 100))}
+
+ );
+ };
+ const monthCol = new Array(12).fill(1).map((_, index) => {
+ return {
+ title: `${index + 1}月`,
+ dataIndex: `M${index + 1}Percent`,
+ valueType: 'digit',
+ width: '6.5em',
+ // fieldProps: { min: 0, max: 100, style: { width: '4em' } },
+ renderFormItem: ({ dataIndex, ...item }, { record, isEditable, ...e }, form) => {
+ return ;
+ },
+ render: (_, row) => RenderMonthCell(row, index + 1),
+ };
+ });
+ const columns = [
+ {
+ title: curObjectItem.label,
+ dataIndex: 'object_id',
+ editable: false,
+ render: (_, r) => r.object_name,
+ },
+ {
+ title: '年度目标',
+ dataIndex: 'yearValue',
+ valueType: 'digit',
+ fieldProps: { style: { width: '100%' }, step: 10000*100 },
+ formItemProps: {
+ style: { width: '100%' },
+ },
+ },
+ ...monthCol,
+ {
+ title: (
+
+ 操作
+ {
+ makeInitialTable(e);
+ }}
+ />
+
+ ),
+ valueType: 'option',
+ // width: 250,
+ render: () => {
+ return null;
+ },
+ },
+ ];
+
+ const onTableChange = (...argrs) => {
+ setEditableRowKeys(argrs[0].map((ele) => ele.key));
+ setDataSource(argrs[0]);
+ };
+ const onTableSubmit = () => {
+ const tableData = dataSource.reduce((r, curObj) => {
+ const allMonth = new Array(12).fill(1).map((_, index) => {
+ const mIndex = index + 1;
+ const mVal = (Number(curObj.yearValue) * Number(curObj[`M${mIndex}Percent`])) / 100;
+ const startM = moment([KPIStore.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'),
+ value: mVal,
+ kpi_id: curObj.kpiDataMapped?.[`M${mIndex}`]?.kpi_id || undefined,
+ key: undefined,
+ };
+ });
+ return r.concat(allMonth);
+ }, []);
+ const yearRow = (({ object, object_name, object_id, subject, date_type, yearValue, kpiYear }) => ({
+ object,
+ object_name,
+ object_id,
+ subject,
+ date_type,
+ value: yearValue,
+ start_date: moment([KPIStore.settingYear, 0, 1]).format('YYYY-MM-DD'),
+ end_date: moment([KPIStore.settingYear, 11, 1]).endOf('M').format('YYYY-MM-DD HH:mm'),
+ kpi_id: kpiYear?.kpi_id || undefined,
+ }))(dataSource?.[0] || {});
+ tableData.unshift(yearRow);
+ console.log('sub', tableData, 'del:', delKpiIds);
+ // return false; // debug:
+ KPIStore.onSubmit(tableData, { delQueue: delKpiIds }).then((res) => {
+ if (res) {
+ message.success('保存成功');
+ setEditOpen(false);
+ setEditableRowKeys([]);
+ setDelKpiIds([]);
+ onSearchSubmit(searchFormStore.formValuesToSub);
+ return false;
+ }
+ message.error('失败, 请重试');
+ });
+ };
+ const initialRow = monthCol.reduce(
+ (r, v) => ({
+ ...r,
+ [v.dataIndex]: 0,
+ yearValue: 10000 * 100,
+ object: curObject,
+ object_name: '',
+ object_id: -1,
+ subject: 'sum_profit',
+ date_type: searchFormStore.formValuesToSub.DateType,
+ kpiDataMapped: {},
+ key: Date.now().toString(32),
+ }),
+ {}
+ ); // v.formItemProps.initialValue
+ const makeInitialTable = (e) => {
+ setEditOpen(e);
+ // todo: 单独设置之后, 清空筛选会导致无法批量设置新的
+ if (e && isEmpty(dataSource)) {
+ const _initialRow = Object.assign({}, initialRow, initialPercentKey);
+ const _objects = isEmpty(objects) ? (curObjectItem?.data || []) : objects;
+ console.log('ooo', objects, isEmpty(objects), curObjectItem?.data || []);
+ const _initialTable = _objects.map((obj) => ({
+ ...cloneDeep(_initialRow),
+ object_name: obj.label,
+ object_id: obj.value,
+ key: Date.now().toString(32) + obj.value,
+ }));
+ console.log(_initialRow, 'iiiii');
+ setDataSource(_initialTable);
+ setEditableRowKeys(_initialTable.map((ele) => ele.key));
+ return false;
+ }
+ setEditableRowKeys(e ? dataSource.map((ele) => ele.key) : []);
+ };
+ const [delKpiIds, setDelKpiIds] = useState([]);
+ return (
+ <>
+
+
+ {
+ return [defaultDoms.delete];
+ },
+ onDelete: (_key, _row) => {
+ // console.log('del', _key, _row);
+ const rowKpiIds = (_row?.kpiData || []).map((ele) => ele.kpi_id);
+ rowKpiIds.push(_row?.kpiYear?.kpi_id);
+ setDelKpiIds(rowKpiIds);
+ },
+ onValuesChange: (record, recordList) => {
+ // console.log('on edit, onValuesChange',record, recordList);
+ onTableChange(recordList);
+ },
+ onChange: (editableKeys, editableRows) => {
+ setEditableRowKeys(editableKeys);
+ },
+ }}
+ />
+
+
+
+
+
+ >
+ );
+});
diff --git a/src/components/kpi/SumProfitPanel.jsx b/src/components/kpi/SumProfitPanel.jsx
new file mode 100644
index 0000000..0818a00
--- /dev/null
+++ b/src/components/kpi/SumProfitPanel.jsx
@@ -0,0 +1,57 @@
+import { useContext } from 'react';
+import { observer } from 'mobx-react';
+// import { stores_Context } from '../config';
+import { Button, Table, Switch, Input, Space, Typography, Row, Col, Spin, Radio, Tabs } from 'antd';
+import SearchForm from './../search/SearchForm';
+import { bu, KPIObjects } from './../../libs/ht';
+
+export default observer((props) => {
+ // const { } = useContext(stores_Context);
+ return (
+ <>
+
+
+ {
+ // TradeStore.setStateSearch(form);
+ // pageRefresh(obj);
+ }}
+ />
+
+
+
+
+ {
+ const id = String(i);
+ return {
+ ...ele,
+ children: `Content of tab ${id}`,
+ };
+ })}
+ />
+
+
+ >
+ );
+});
diff --git a/src/components/search/BusinessSelect.jsx b/src/components/search/BusinessSelect.jsx
index b97fcb3..cb94770 100644
--- a/src/components/search/BusinessSelect.jsx
+++ b/src/components/search/BusinessSelect.jsx
@@ -5,16 +5,23 @@ import { biz } from '../../libs/ht';
const Business_unit = (props) => {
- const {store} = props;
+ const { store, mode, value, onChange, show_all, ...extProps } = props;
return (
);
};
-
+/**
+ * 基于组织架构
+ */
export default observer(Business_unit);
diff --git a/src/components/search/BusinessUnitSelect.jsx b/src/components/search/BusinessUnitSelect.jsx
new file mode 100644
index 0000000..1b0738c
--- /dev/null
+++ b/src/components/search/BusinessUnitSelect.jsx
@@ -0,0 +1,36 @@
+import React, {Component} from 'react';
+import {Select} from 'antd';
+import {observer} from "mobx-react";
+import { biz, bu } from '../../libs/ht';
+
+
+const Business_unit = (props) => {
+ const { store, mode, value, onChange, show_all, ...extProps } = props;
+ const _show_all = ['tags', 'multiple'].includes(mode) ? false : show_all;
+ return (
+
+
+
+ );
+};
+/**
+ * HT的事业部
+ */
+export default observer(Business_unit);
diff --git a/src/components/search/DataTypeSelect.jsx b/src/components/search/DataTypeSelect.jsx
index e6f185d..731c81b 100644
--- a/src/components/search/DataTypeSelect.jsx
+++ b/src/components/search/DataTypeSelect.jsx
@@ -8,15 +8,30 @@ class DataTypeSelect extends Component {
super(props);
}
+ // debug:
+ // componentDidMount() {
+ // console.log(this.props, 'DataTypeSelect props');
+ // }
+
+ handleChange = (value) => {
+ if (this.props.store) {
+ this.props.store.onChange_datetype(value);
+ }
+ if (this.props.onChange) {
+ this.props.onChange(value);
+ }
+ };
+
render() {
const store = this.props.store;
return (
-
-
-
);
}
}
diff --git a/src/components/search/DatePickerCharts.jsx b/src/components/search/DatePickerCharts.jsx
index 3712ff8..d6dc4f0 100644
--- a/src/components/search/DatePickerCharts.jsx
+++ b/src/components/search/DatePickerCharts.jsx
@@ -1,5 +1,5 @@
import React, { Component } from "react";
-import { Col, DatePicker, Row } from "antd";
+import { Col, DatePicker, Row, Form } from "antd";
import { observer } from "mobx-react";
import * as config from "../../config";
import moment from "moment";
@@ -7,6 +7,16 @@ import "moment/locale/zh-cn";
import locale from "antd/es/date-picker/locale/zh_CN";
import { stores_Context } from "../../config";
+// 1.0的搜索组件 不需要Form包裹
+const SectionWrapper = ({ isform, id, title, children, right, ...extProps }) =>
+ !isform ? (
+ <>{children}>
+ ) : (
+
+ {children}
+
+ );
+
// 用于日期选择,计算上一时间段、同比时间等
class DatePickerCharts extends Component {
static contextType = stores_Context;
@@ -17,16 +27,20 @@ class DatePickerCharts extends Component {
render() {
const { date_picker_store } = this.context;
+ const { isform } = this.props;
+ const defaultV = [date_picker_store.start_date, date_picker_store.end_date];
+ const defaultVdiff = [date_picker_store.start_date_cp, date_picker_store.end_date_cp];
return (
+
{
date_picker_store.onChange_dataPicker(e);
if (typeof this.props.onChange === 'function') {
@@ -46,19 +60,27 @@ class DatePickerCharts extends Component {
去年: [moment().subtract(1, "year").startOf("year"), moment().subtract(1, "year").endOf("year")],
}}
/>
+
{this.props.hide_vs ? (
""
) : (
+
{
+ if (typeof this.props.onChange === 'function') {
+ this.props.onChange(value);
+ }
+ date_picker_store?.onChange_dataPicker_cp(value);
+ }}
ranges={{
上一时间段: date_picker_store.previous_date(),
去年同期: date_picker_store.previous_year(),
@@ -68,7 +90,7 @@ class DatePickerCharts extends Component {
前三个月: [moment().subtract(5, "month").startOf("month"), moment().subtract(3, "month").endOf("month")],
去年: [moment().subtract(1, "year").startOf("year"), moment().subtract(1, "year").endOf("year")],
}}
- />
+ />
)}
diff --git a/src/components/search/GroupSelect.jsx b/src/components/search/GroupSelect.jsx
index 95a0e6e..24daa00 100644
--- a/src/components/search/GroupSelect.jsx
+++ b/src/components/search/GroupSelect.jsx
@@ -10,23 +10,29 @@ class GroupSelect extends Component {
render() {
const { store, mode, value, onChange, show_all, ...extProps } = this.props;
+ const _mode = mode || store?.group_select_mode || null;
+ const _show_all = ['tags', 'multiple'].includes(_mode) ? false : show_all;
return (