todo: KPI 设置和查看

feature/2.0-sales-trade
Lei OT 2 years ago
parent 31481fd301
commit a816e9a9de

@ -10,7 +10,7 @@ import {
DollarOutlined, DollarOutlined,
AreaChartOutlined, AreaChartOutlined,
WechatOutlined, WechatOutlined,
UserOutlined, UserOutlined, FlagOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Layout, Menu, Image, Spin } from 'antd'; import { Layout, Menu, Image, Spin } from 'antd';
import { BrowserRouter, Route, Routes, NavLink } from 'react-router-dom'; import { BrowserRouter, Route, Routes, NavLink } from 'react-router-dom';
@ -35,6 +35,7 @@ import Logo from './logo.png';
import { stores_Context } from './config'; import { stores_Context } from './config';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import ExchangeRate from './charts/ExchangeRate'; import ExchangeRate from './charts/ExchangeRate';
import KPI from './views/KPI';
const App = () => { const App = () => {
const { Content, Footer, Sider } = Layout; const { Content, Footer, Sider } = Layout;
@ -119,6 +120,7 @@ const App = () => {
}, },
], ],
}, },
{ key: 'kpi', label: <NavLink to="/kpi">目标</NavLink>, icon: <FlagOutlined /> },
]; ];
return ( return (
@ -159,6 +161,7 @@ const App = () => {
> >
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/kpi" element={<KPI />} />
<Route element={<ProtectedRoute auth={['admin', 'director_bu', 'marketing']} />}> <Route element={<ProtectedRoute auth={['admin', 'director_bu', 'marketing']} />}>
<Route path="/orders" element={<Orders />} /> <Route path="/orders" element={<Orders />} />
<Route path="/orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<Orders_sub />} /> <Route path="/orders_sub/:ordertype/:ordertype_sub/:ordertype_title" element={<Orders_sub />} />

@ -104,19 +104,19 @@
{} {}
] ]
}, },
"get|/service-web/QueryData/Getkpi": { "get|/service-Analyse2/getkpi/test": {
"errcode": 0, "errcode": 0,
"errmsg": "", "errmsg": "",
"loading": false, "loading": false,
"data": null, "data": null,
"result1|10": [ "result|10": [
{ {
"object|1": "@pick([\"dept\",\"sales\", \"group\"])", "object|1": "@pick([\"dept\",\"sales\", \"group\"])",
"subject|1": "@pick([\"OrderCount\",\"SumML\", \"AvgML\", \"SuccessRate\"])", "subject|1": "@pick([\"OrderCount\",\"SumML\", \"AvgML\", \"SuccessRate\"])",
"object_id": "@integer(10,100)", "object_id": "@integer(10,100)",
"object_name": "@cname", "object_name": "@cname",
"date_type": "@pick([\"ConfirmDate\",\"startDate\", \"applyDate\"])", "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\")", "end_date": "@datetime(\"yyyy-MM-dd HH:mm:ss\")",
"value": "@integer(99,9999)", "value": "@integer(99,9999)",
"key": "@increment" "key": "@increment"
@ -124,5 +124,11 @@
"result2": [ "result2": [
{} {}
] ]
},
"post|/service-Analyse2/setkpi_multi/test": {
"errcode": 0,
"errmsg": "",
"loading": false,
"data": null
} }
} }

@ -11,7 +11,7 @@ import WechatStore from "./Wechat";
import WhatsAppStore from "./WhatsApp"; import WhatsAppStore from "./WhatsApp";
import CustomerServicesStore from "./CustomerServices"; import CustomerServicesStore from "./CustomerServices";
import TradeStore from "./Trade"; import TradeStore from "./Trade";
import KPI from "./KPI";
class Index { class Index {
constructor() { constructor() {
this.dashboard_store = new DashboardStore(this); this.dashboard_store = new DashboardStore(this);
@ -26,6 +26,7 @@ class Index {
this.whatsAppStore = new WhatsAppStore(this); this.whatsAppStore = new WhatsAppStore(this);
this.customerServicesStore = new CustomerServicesStore(this); this.customerServicesStore = new CustomerServicesStore(this);
this.TradeStore = new TradeStore(this); this.TradeStore = new TradeStore(this);
this.KPIStore = new KPI(this);
makeAutoObservable(this); makeAutoObservable(this);
} }

@ -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;

@ -315,3 +315,22 @@ export function merge(...objects) {
return result; 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;
}, {});
}

@ -51,7 +51,8 @@ export function postForm(url, data) {
} }
export function postJSON(url, obj) { export function postJSON(url, obj) {
return fetch(url, { const host = /^https?:\/\//i.test(url) ? '': HT_HOST;
return fetch(`${host}${url}`, {
method: 'POST', method: 'POST',
body: JSON.stringify(obj), body: JSON.stringify(obj),
headers: { headers: {

@ -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 (
<>
<EditableProTable
key={settingYear}
headerTitle={settingYear}
columns={columns}
rowKey="key"
scroll={{
x: 1000,
}}
value={pageData}
onChange={onChange}
recordCreatorProps={
editOpen
? {
newRecordType: 'dataSource',
record: () => ({
key: pageData.length+1, // Number(Date.now().toString()),
...initialRow,
object_name: '',
value:0
}),
}
: false
}
toolBarRender={() => {
return [
<Switch
unCheckedChildren="查看"
checkedChildren="编辑"
key={'openEdit'}
// defaultChecked={true}
checked={editOpen}
onChange={(e) => {
setEditOpen(e);
setEditableRowKeys(e ? pageData.map((ele) => ele.key) : []);
// KPIStore.setEditableRowsKeys(e ? pageData.map((ele) => ele.key) : []);
}}
/>,
<Button
disabled={!editOpen}
type="primary"
key="save"
onClick={() => {
// dataSource api
KPIStore.saveOrUpdate();
}}
>
保存数据
</Button>,
];
}}
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()
}
}}
/>
</>
);
});
Loading…
Cancel
Save