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()
+ }
+ }}
+ />
+ >
+ );
+});