From 33751b3eca896704a60822e4decf2a7ba8781f7f Mon Sep 17 00:00:00 2001 From: Lei OT Date: Wed, 20 Sep 2023 17:07:10 +0800 Subject: [PATCH] kpi --- src/App.css | 15 +- src/components/kpi/BUPanel.jsx | 17 +- src/components/kpi/KPISettings.jsx | 256 ++++++++++++++++++ src/components/kpi/OverviewPanel.jsx | 258 ++++++++++++++++-- src/components/kpi/SumProfitPanel.jsx | 57 ++++ src/components/search/BusinessUnitSelect.jsx | 36 +++ src/components/search/SearchForm.jsx | 8 +- src/stores/DatePickerStore.js | 15 +- src/stores/KPI.js | 76 ++---- src/utils/request.js | 15 ++ src/views/KPI.jsx | 259 ++----------------- src/views/kpi.css | 14 + 12 files changed, 707 insertions(+), 319 deletions(-) create mode 100644 src/components/kpi/KPISettings.jsx create mode 100644 src/components/kpi/SumProfitPanel.jsx create mode 100644 src/components/search/BusinessUnitSelect.jsx diff --git a/src/App.css b/src/App.css index 2460a39..678262a 100644 --- a/src/App.css +++ b/src/App.css @@ -6,4 +6,17 @@ .align_left{ text-align: left; -} \ No newline at end of file +} + +.mb-1{ + margin-bottom: 1em; +} +.mb-n1{ + margin-bottom: -1em; +} +.p-none{ + padding: 0; +} +.p-s1{ + padding: .5em; +} diff --git a/src/components/kpi/BUPanel.jsx b/src/components/kpi/BUPanel.jsx index e159abe..0ebdd84 100644 --- a/src/components/kpi/BUPanel.jsx +++ b/src/components/kpi/BUPanel.jsx @@ -1,13 +1,18 @@ import { useContext } from 'react'; -import { observer } from "mobx-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'; export default observer((props) => { // const { } = useContext(stores_Context); - return ( - <> - {props.title} - - ); + const searchProps = { + // shows: ['DateType', 'years', 'HTBusinessUnits'], + }; + return ( + <> + + + ); }); diff --git a/src/components/kpi/KPISettings.jsx b/src/components/kpi/KPISettings.jsx new file mode 100644 index 0000000..f4c9e65 --- /dev/null +++ b/src/components/kpi/KPISettings.jsx @@ -0,0 +1,256 @@ +import { useContext, useState, useEffect } 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 { EditableProTable, ProCard, ProFormField } from '@ant-design/pro-components'; +import SearchForm from './../search/SearchForm'; +import { bu, KPIObjects, KPISubjects } from './../../libs/ht'; +import { isEmpty, fixTo2Decimals, fixTo4Decimals, cloneDeep, numberFormatter } from './../../utils/commons'; + +export const KPIObjectsMapped = KPIObjects.reduce((a, c) => ({ ...a, [String(c.key)]: c }), {}); +const { Text } = Typography; +const numberConvert10K = (number, scale = 10) => { + return fixTo2Decimals(number / (1000 * scale)) + '万'; +}; + +export default observer((props) => { + const { KPIStore, DictDataStore } = useContext(stores_Context); + const { sort, initialValue, hides, shows, fieldProps } = { + sort: '', + initialValue: {}, + fieldProps: { + years: { hide_vs: true }, + }, + hides: [], + shows: ['DateType', 'years'], + ...props.searchProps, + }; + const { curObject, objects, KPISubjects, onSearchSubmit } = props; + + const curObjectItem = KPIObjectsMapped[curObject]; +console.log(curObjectItem, KPIObjectsMapped, curObject, 'cocococo'); + const [dataSource, setDataSource] = useState([]); + const { settingYear } = KPIStore; + + const [editOpen, setEditOpen] = useState(false); // test: + const [editableRowsKeys, setEditableRowKeys] = useState([]); + // console.log(toJS(KPIStore.pageData ), dataSource, '00000'); + + const PercentInput = ({ value, onChange, record, ...extProps }) => { + // console.log(extProps, '22222222'); + const initialPercent = record.kpiDataMapped?.[`M${extProps.month}`]?.percentVal; + const [inputVal, setInputVal] = useState(value); + const calcV = inputVal ? numberConvert10K(fixTo4Decimals((Number(record?.yearValue) * inputVal) / 100)) : 0; + + const handleInputChange = ({ target: { value } }) => { + setInputVal(value); + }; + const handleInputConfirm = () => { + // onChange?.(inputVal); + // setInputVal(''); + }; + return ( + + + {/* onBlur={handleInputConfirm} onPressEnter={handleInputConfirm} */} + {/* 1 */} + {calcV} + + ); + }; + const RenderInput = (row, mon) => { + // console.log(toJS(row), mon); + return ( + +
+ {row.kpiDataMapped?.[`M${mon}`]?.percentVal} + % +
+
{row.kpiDataMapped?.[`M${mon}`]?.value}
+
+ ); + }; + 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) => RenderInput(row, index + 1), + }; + }); + const initialRow = monthCol.reduce((r, v) => ({ ...r, [v.dataIndex]: 0 }), {}); // v.formItemProps.initialValue + const columns = [ + { + title: curObjectItem.label, + dataIndex: 'object_id', + valueType: 'select', + // ...valueEnum + // fieldProps: { labelInValue: true }, + render: (_, r) => r.object_name, + }, + // { + // title: 'Name', + // dataIndex: 'title', + // //...form rules + // formItemProps: { + // rules: [ + // { + // required: true, + // whitespace: true, + // message: '此项是必填项', + // }, + // ], + // }, + // }, + { + title: '年度目标', + dataIndex: 'yearValue', + valueType: 'digit', + fieldProps: { style: { width: '100%' } }, + formItemProps: { + style: { width: '100%' }, + }, + }, + ...monthCol, + // { + // title: '完成进度', + // dataIndex: 'place', + // valueType: 'percent', + // editable: false, + // width: '6em', + // }, + { + title: ( + + 操作 + { + setEditOpen(e); + setEditableRowKeys(e ? dataSource.map((ele) => ele.key) : []); + // KPIStore.setEditableRowsKeys(e ? dataSource.map((ele) => ele.key) : []); + }} + /> + + ), + valueType: 'option', + // width: 250, + render: () => { + return null; + }, + }, + ]; + const onTableChange = (...argrs) => { + console.log(argrs[0], 'who who who'); + setEditableRowKeys(argrs[0].map((ele) => ele.key)); + // KPIStore.setEditableRowsKeys(argrs[0].map((ele) => ele.key)); + setDataSource(argrs[0]); + // KPIStore.handleTableEdit(argrs[0]); + }; + return ( + <> + + + { + // TradeStore.setStateSearch(form); + // pageRefresh(obj); + }} + /> + + + + + { + const id = String(i); + return { + ...ele, + children: ( + { + // return [ + // { + // setEditOpen(e); + // setEditableRowKeys(e ? dataSource.map((ele) => ele.key) : []); + // // KPIStore.setEditableRowsKeys(e ? dataSource.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, onValuesChange'); + onTableChange(recordList); + }, + onChange: (editableKeys, editableRows) => { + console.log('editable onValuesChange'); + onTableChange(editableRows); + // KPIStore.setEditableRowsKeys() + }, + }} + /> + ), + }; + })} + /> + + + + ); +}); diff --git a/src/components/kpi/OverviewPanel.jsx b/src/components/kpi/OverviewPanel.jsx index f25e336..49f8760 100644 --- a/src/components/kpi/OverviewPanel.jsx +++ b/src/components/kpi/OverviewPanel.jsx @@ -1,37 +1,263 @@ -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 { 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 { } = useContext(stores_Context); + 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/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/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/SearchForm.jsx b/src/components/search/SearchForm.jsx index 725b5ab..cf63c57 100644 --- a/src/components/search/SearchForm.jsx +++ b/src/components/search/SearchForm.jsx @@ -1,7 +1,7 @@ -import { createContext } from 'react'; +import { createContext, useContext } from 'react'; import { toJS } from "mobx"; import { observer } from 'mobx-react'; -import { DATE_FORMAT } from './../../config'; +import { DATE_FORMAT, stores_Context } from './../../config'; import { SearchOutlined, } from "@ant-design/icons"; import { Form, Row, Col, Select, Button, Space, DatePicker } from 'antd'; import moment from 'moment'; @@ -32,6 +32,7 @@ const Option = Select.Option; * @property onSubmit */ export default observer((props) => { + const { date_picker_store: searchFormStore } = useContext(stores_Context); const [form] = Form.useForm(); const { sort, initialValue, hides, shows, fieldProps } = { sort: '', @@ -143,6 +144,8 @@ export default observer((props) => { Object.keys(dest).forEach((key) => (dest[key] == null || dest[key] === '' || dest[key].length === 0) && delete dest[key]); console.log('form value send to onSubmit:', dest); const str = new URLSearchParams(dest).toString(); + searchFormStore.setFormValues(values); + searchFormStore.setFormValuesToSub(dest); if (typeof onSubmit === 'function') { onSubmit(null, dest, values, str); } @@ -156,6 +159,7 @@ export default observer((props) => { const onValuesChange = (...args) => { const [changedValues, allValues] = args; console.log('form onValuesChange', args); + searchFormStore.setFormValues(allValues); }; return ( diff --git a/src/stores/DatePickerStore.js b/src/stores/DatePickerStore.js index ff7ac74..9735607 100644 --- a/src/stores/DatePickerStore.js +++ b/src/stores/DatePickerStore.js @@ -1,6 +1,8 @@ import {makeAutoObservable} from "mobx"; import moment from "moment"; - +/** + * 管理搜索组件的状态 + */ class DatePickerStore { constructor(rootStore) { @@ -8,6 +10,9 @@ class DatePickerStore { makeAutoObservable(this); } + formValues = {}; + formValuesToSub = {}; + start_date = moment().startOf('week').subtract(7, 'days'); end_date = moment().endOf('week').subtract(7, 'days'); start_date_cp = false; @@ -38,8 +43,14 @@ class DatePickerStore { return [moment(this.start_date).subtract(1, 'year'), moment(this.end_date).subtract(1, 'year')]; } -} + setFormValues(data){ + this.formValues = data; + } + setFormValuesToSub(data){ + this.formValuesToSub = data; + } +} export default DatePickerStore; diff --git a/src/stores/KPI.js b/src/stores/KPI.js index a1e6296..d31f81b 100644 --- a/src/stores/KPI.js +++ b/src/stores/KPI.js @@ -1,61 +1,41 @@ import { makeAutoObservable, runInAction, toJS } from 'mobx'; import * as req from '../utils/request'; -import { isEmpty, sortBy, groupBy, cloneDeep } from '../utils/commons'; +import { isEmpty, sortBy, groupBy, cloneDeep, fixTo4Decimals, flush } from '../utils/commons'; import moment from 'moment'; -const currentYear = moment().year(); - class KPI { constructor(appStore) { this.appStore = appStore; makeAutoObservable(this); } - saveOrUpdate(x) { - console.log('ssssssssssss', x); - console.log(toJS(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); + async delByID(ids) { + const data = { 'kpi_ids': ids }; + const json = await req.delJSON('/service-Analyse2/delkpi_multi', data); + return json.errcode === 0; + } + + async saveOrUpdate(tableData) { const data = { 'kpis': tableData }; - 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'); - }); - } - }); + const json = await req.postJSON('/service-Analyse2/setkpi_multi', data); + return json.errcode === 0; + } + + async onSubmit(tableData, { delQueue }) { + const flushData = tableData.filter(row => !isEmpty(row.value) || !isEmpty(row?.kpi_id)); + const postRes = isEmpty(flushData) ? true : await this.saveOrUpdate(flushData); + const delRes = isEmpty(flush(delQueue)) ? true : await this.delByID(delQueue); + return postRes && delRes; } - getList() { - const param = { + getList(param = {}) { + const _param = { date_type: 'applyDate', start_date: '2020-01-01', end_date: '2024-12-31 23:59:59', + ...param, }; - // return req.fetchJSON('/service-Analyse2/getkpi/test', param).then((json) => { - return req.fetchJSON('/service-Analyse2/getkpi', param).then((json) => { + return req.fetchJSON('/service-Analyse2/getkpi', _param).then((json) => { if (json.errcode === 0) { runInAction(() => { this.originData = json.result; @@ -68,12 +48,11 @@ class KPI { }); } - handleTableEdit(data) { - console.log('handle change ', data); - // this.pageData = data; + settingYear = moment().year(); + setSettingYear(v) { + this.settingYear = v; } - settingYear = 2023; settingSubject = 'sum_profit'; originData =[]; @@ -115,14 +94,15 @@ export const parseKPI = (kpis, keyArr = []) => { // r.push({ monthIndex: v.monthIndex, yearIndex: v.yearIndex, value: v.value, kpi_id: v.kpi_id }); return { monthIndex: v.monthIndex, yearIndex: v.yearIndex, value: v.value, kpi_id: v.kpi_id }; }, {}); - const kpiData = _ByFull.false.reduce((r, v) => { - r.push({ monthIndex: v.monthIndex, yearIndex: v.yearIndex, value: v.value, kpi_id: v.kpi_id, percentVal: (v.value/kpiYear.value*100) }); + const kpiData = (_ByFull?.false || []).reduce((r, v) => { + r.push({ monthIndex: v.monthIndex, yearIndex: v.yearIndex, value: v.value, kpi_id: v.kpi_id, percentVal: (fixTo4Decimals(v.value/kpiYear.value)*100) }); return r; }, []); const kpiDataMapped = kpiData.reduce((r, v) => ({...r, [`M${v.monthIndex}`]: v }), {}); const kpiDataFlat = kpiData.reduce((r, v) => ({...r, [`M${v.monthIndex}Val`]: v.value, [`M${v.monthIndex}Percent`]: v.percentVal}), {}); const { start_date, end_date, kpi_id, value, unit, monthIndex, monthRange, ...objectEle } = subjectObject[oID][0]; - return { ...cloneDeep(initialPercentKey), ...objectEle, ...kpiDataFlat, kpiData, kpiDataMapped, kpiYear, yearValue: kpiYear?.value || 0 }; + const allKey = !isEmpty(kpiData) ? kpiData.map(ek => ek.kpi_id).join('_') : `${Object.values(kpiYear).join('_')}`; + return { ...cloneDeep(initialPercentKey), ...objectEle, ...kpiDataFlat, kpiData, kpiDataMapped, kpiYear, yearValue: kpiYear?.value || 0, key: allKey }; }); ret[_subject] = afterGroup; return 1; diff --git a/src/utils/request.js b/src/utils/request.js index e9289eb..d954743 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -78,3 +78,18 @@ export function postStream(url, obj) { throw error; }); } + +export function delJSON(url, obj) { + const host = /^https?:\/\//i.test(url) ? '': HT_HOST; + return fetch(`${host}${url}`, { + method: 'DELETE', + body: JSON.stringify(obj), + headers: { + 'Content-type': 'application/json; charset=UTF-8' + } + }).then(checkStatus) + .then(response => response.json()) + .catch(error => { + throw error; + }); +} diff --git a/src/views/KPI.jsx b/src/views/KPI.jsx index 38e4dab..4ecc327 100644 --- a/src/views/KPI.jsx +++ b/src/views/KPI.jsx @@ -1,19 +1,12 @@ -import { useContext, useEffect, useState, useRef } from 'react'; -import { observer, useLocalStore } from 'mobx-react'; -import { toJS } from 'mobx'; -// import type { ProColumns } from '@ant-design/pro-components'; -import { EditableProTable, ProCard, ProFormField } from '@ant-design/pro-components'; -import { Button, Table, Switch, Input, Space, Typography, Row, Col, Spin, Radio, Tabs } from 'antd'; -import { stores_Context } from '../config'; -import { isEmpty, fixTo4Decimals, cloneDeep } from './../utils/commons'; -import SearchForm from './../components/search/SearchForm'; +import { useEffect, useState } from 'react'; +import { observer } from 'mobx-react'; +import { Row, Col, Tabs } from 'antd'; +import { KPIObjects } from './../libs/ht'; import BUPanel from './../components/kpi/BUPanel'; import OverviewPanel from './../components/kpi/OverviewPanel'; -import { KPIObjects } from './../libs/ht'; import './kpi.css'; -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 itemComponents = { + +const objectComponents = { 'overview': OverviewPanel, 'bu': BUPanel, 'dept': BUPanel, @@ -22,253 +15,31 @@ const itemComponents = { 'destination': BUPanel, 'country': BUPanel, }; -const tabsItems = KPIObjects.map((ele) => ({ - ...ele, - label: ele.label, - key: ele.value, - children: BUPanel, -})); -console.log(tabsItems); export default observer((props) => { - const [dataSource, setDataSource] = useState([]); - const { KPIStore, DictDataStore } = useContext(stores_Context); - const { settingYear } = KPIStore; - const { operator } = DictDataStore; - useEffect(() => { - // KPIStore.saveOrUpdate(); - KPIStore.getList().then((data) => { - setDataSource(data); - }); - DictDataStore.fetchDictData('operator', { is_assign: 1 }); - DictDataStore.fetchDictData('country'); - return () => {}; - }, []); - const [editOpen, setEditOpen] = useState(false); // test: - const [editableRowsKeys, setEditableRowKeys] = useState([]); - // console.log(toJS(KPIStore.pageData ), dataSource, '00000'); - const PercentInput = ({ value, onChange, record, ...extProps }) => { - // console.log(extProps, '22222222'); - const initialPercent = record.kpiDataMapped?.[`M${extProps.month}`]?.percentVal; - const [inputVal, setInputVal] = useState(value); - const calcV = inputVal ? fixTo4Decimals((Number(record?.yearValue) * inputVal) / 100) : 0; - - const handleInputChange = ({ target: { value } }) => { - setInputVal(value); - }; - const handleInputConfirm = () => { - // onChange?.(inputVal); - // setInputVal(''); - }; - return ( - - - {/* onBlur={handleInputConfirm} onPressEnter={handleInputConfirm} */} - {/* 1 */} - {calcV} - - ); - }; - const RenderInput = (row, mon) => { - // console.log(toJS(row), mon); - return ( - -
- {row.kpiDataMapped?.[`M${mon}`]?.percentVal} - % -
-
{row.kpiDataMapped?.[`M${mon}`]?.value}
-
- ); - }; - const monthCol = new Array(12).fill(1).map((_, index) => { - return { - title: `${index + 1}月`, - dataIndex: `M${index + 1}Percent`, - valueType: 'percent', - width: '6.5em', - fieldProps: { min: 0, max: 100, style: { width: '4em' } }, - renderFormItem: ({ dataIndex, ...item }, { record, isEditable, ...e }, form) => { - return ; - }, - render: (_, row) => RenderInput(row, index + 1), - }; - }); - const initialRow = monthCol.reduce((r, v) => ({ ...r, [v.dataIndex]: 0 }), {}); // v.formItemProps.initialValue - const columns = [ - { - title: '对象', - dataIndex: 'object_id', - valueType: 'select', - // ...valueEnum - // fieldProps: { labelInValue: true }, - render: (_, r) => r.object_name, - }, - // { - // title: 'Name', - // dataIndex: 'title', - // //...form rules - // formItemProps: { - // rules: [ - // { - // required: true, - // whitespace: true, - // message: '此项是必填项', - // }, - // ], - // }, - // }, - { - title: '年度目标', - dataIndex: 'yearValue', - 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 onTableChange = (...argrs) => { - console.log(argrs[0], 'who who who'); - setEditableRowKeys(argrs[0].map((ele) => ele.key)); - // KPIStore.setEditableRowsKeys(argrs[0].map((ele) => ele.key)); - setDataSource(argrs[0]); - // KPIStore.handleTableEdit(argrs[0]); - }; - const handleRadioChange = (val) => { - console.log(val, 'sss'); + // useEffect(() => { + // return () => {}; + // }, []); + const [curObject, setCurObject] = useState('overview'); + const onObjectChange = (object) => { + setCurObject(object); }; return ( <> - {/* handleRadioChange(e.target.value)} /> */} { - const ItemComponent = itemComponents[ele.key]; + const ItemComponent = objectComponents[ele.key]; return { ...ele, - children: , + children: , }; })} /> - - - { - // TradeStore.setStateSearch(form); - // pageRefresh(obj); - }} - /> - - - ({ - key: Date.now().toString(32), // dataSource.length + 1, // Number(Date.now().toString()), - ...initialRow, - object_name: '', - value: 0, - yearValue: 0, - ...cloneDeep(initialPercentKey), - }), - } - : false - } - toolBarRender={() => { - return [ - { - setEditOpen(e); - setEditableRowKeys(e ? dataSource.map((ele) => ele.key) : []); - // KPIStore.setEditableRowsKeys(e ? dataSource.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, onValuesChange'); - onTableChange(recordList); - }, - onChange: (editableKeys, editableRows) => { - console.log('editable onValuesChange'); - onTableChange(editableRows); - // KPIStore.setEditableRowsKeys() - }, - }} - /> - {(operator?.dataSource || []).map((ele) => ( -
- {ele.label} {ele.mobile} -
- ))} ); }); diff --git a/src/views/kpi.css b/src/views/kpi.css index c652f22..ac1d799 100644 --- a/src/views/kpi.css +++ b/src/views/kpi.css @@ -1,3 +1,17 @@ .ant-tabs.ant-tabs-card > .ant-tabs-nav { margin-bottom: 0; } +.ant-tabs.ant-tabs-left .ant-tabs-content-holder{ + padding: 0; +} +.ant-tabs-content.ant-tabs-content-left .ant-tabs-tabpane.ant-tabs-tabpane-active{ + padding-left: 0; +} +.ant-tabs-content.ant-tabs-content-left .ant-tabs-tabpane .ant-pro-table .ant-pro-card-body{ + padding: 0; +} + +.ant-form-item-control-input .ant-input-affix-wrapper{ + padding-left: 4px; + padding-right: 4px; +}