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