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

264 lines
9.3 KiB
JavaScript

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 (
<Space direction={'vertical'}>
<Input key={'input'} suffix="%" type={'number'} value={inputValue} onChange={handleInputChange} step={0.1} />
<Text type={'secondary'}>{calcV}</Text>
</Space>
);
},
[]
);
const RenderMonthCell = (row, mon) => {
return (
<Space direction={'vertical'}>
<div>
{fixTo2Decimals(row?.[`M${mon}Percent`])}
<span>%</span>
</div>
<div>{numberConvert10K(fixTo4Decimals((Number(row?.yearValue) * row?.[`M${mon}Percent`]) / 100))}</div>
</Space>
);
};
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 <PercentInput {...{ record }} month={index + 1} key={`M${index + 1}`} />;
},
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 (
<>
<Row gutter={16} className="mb-1" style1={{ margin: '0 0 1em' }}>
<Col className="gutter-row m-n1 p-none" span={24} style1={{ margin: '0 0 -16px 0', padding: 0 }}>
<SearchForm
defaultValue={{
'initialValue': {},
shows: ['DateType', 'years'],
'fieldProps': {
DepartmentList: { show_all: false },
WebCode: { show_all: false },
years: { hide_vs: true },
},
}}
confirmText="查询"
onSubmit={(_err, obj, form, str) => {
// TradeStore.setStateSearch(form);
// pageRefresh(obj);
onSearchSubmit(obj, form);
setEditOpen(false);
setEditableRowKeys([]);
}}
/>
</Col>
</Row>
<EditableProTable
key={KPIStore.settingYear}
headerTitle={`毛利`}
columns={columns}
rowKey="key"
scroll={{
x: 1000,
}}
value={dataSource}
onChange={onTableChange}
recordCreatorProps={false}
toolBarRender={() => {
return [
<Switch
unCheckedChildren="查看"
checkedChildren="编辑"
key={'openEdit'}
checked={editOpen}
onChange={(e) => {
makeInitialTable(e);
}}
/>,
<Button disabled={!editOpen} type="primary" key="save" onClick={onTableSubmit}>
保存数据
</Button>,
];
}}
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);
},
}}
/>
</>
);
});