diff --git a/src/components/Data.jsx b/src/components/Data.jsx index f907dd2..d503f07 100644 --- a/src/components/Data.jsx +++ b/src/components/Data.jsx @@ -1,10 +1,13 @@ import { Tag } from 'antd'; import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'; -export const VSTag = (diffPercent, diffData, data1, data2) => { +export const VSTag = (props) => { + const { diffPercent, diffData, data1, data2 } = props; const CaretIcon = parseInt(diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined; - const tagColor = parseInt(diffPercent) < 0 ? "gold" : "lime"; - return parseInt(diffPercent) === 0 ? "-" : ( + const tagColor = parseInt(diffPercent) < 0 ? 'gold' : 'lime'; + return parseInt(diffPercent) === 0 ? ( + '-' + ) : (
{data1} vs {data2} diff --git a/src/components/DateGroupRadio/date.js b/src/components/DateGroupRadio/date.js index 904f5d5..4e367f9 100644 --- a/src/components/DateGroupRadio/date.js +++ b/src/components/DateGroupRadio/date.js @@ -119,6 +119,7 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper, const parseData2 = parse2.data.map((ele) => ({ [fieldMapper.dateKey]: ele.groupKey, [fieldMapper.valueKey]: ele.value, + [fieldMapper.seriesKey]: ele[fieldMapper.seriesKey], groups: _data2[0].groups, dateKey: ele.dateKey, dateRange: ele.dateRange, @@ -128,5 +129,6 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper, const reindecData2 = parseData2.map((ele, index) => ({ ...ele, [fieldMapper.dateKey]: useKeys[index] || `X.${ele[fieldMapper.dateKey]}`, dateKey: ele.dateKey })); const retData = [].concat(parseData1, reindecData2); const avg1 = parse1.avgVal; + // console.log('callback', dateGroup, retData); cb(dateGroup, retData, avg1); }; diff --git a/src/components/search/BusinessSelect.jsx b/src/components/search/BusinessSelect.jsx index b97fcb3..5cd1f25 100644 --- a/src/components/search/BusinessSelect.jsx +++ b/src/components/search/BusinessSelect.jsx @@ -5,16 +5,23 @@ import { biz } from '../../libs/ht'; const Business_unit = (props) => { - const {store} = props; + const { store, mode, value, onChange, show_all, ...extProps } = props; return (
store.onChange_datetype(value)} + // onChange={(value) => store.onChange_datetype(value)} + onChange={this.handleChange} > {dateTypes.map((ele) => ( @@ -24,7 +39,6 @@ class DataTypeSelect extends Component { ))} -
); } } diff --git a/src/components/search/DatePickerCharts.jsx b/src/components/search/DatePickerCharts.jsx index 3712ff8..bb73445 100644 --- a/src/components/search/DatePickerCharts.jsx +++ b/src/components/search/DatePickerCharts.jsx @@ -1,5 +1,5 @@ import React, { Component } from "react"; -import { Col, DatePicker, Row } from "antd"; +import { Col, DatePicker, Row, Form } from "antd"; import { observer } from "mobx-react"; import * as config from "../../config"; import moment from "moment"; @@ -21,12 +21,13 @@ class DatePickerCharts extends Component {
+ { date_picker_store.onChange_dataPicker(e); if (typeof this.props.onChange === 'function') { @@ -45,20 +46,27 @@ class DatePickerCharts extends Component { 今年: [moment().startOf("year"), moment().endOf("year")], 去年: [moment().subtract(1, "year").startOf("year"), moment().subtract(1, "year").endOf("year")], }} - /> + /> {this.props.hide_vs ? ( "" ) : ( + { + if (typeof this.props.onChange === 'function') { + this.props.onChange(value); + } + date_picker_store?.onChange_dataPicker_cp(value); + }} ranges={{ 上一时间段: date_picker_store.previous_date(), 去年同期: date_picker_store.previous_year(), @@ -68,7 +76,7 @@ class DatePickerCharts extends Component { 前三个月: [moment().subtract(5, "month").startOf("month"), moment().subtract(3, "month").endOf("month")], 去年: [moment().subtract(1, "year").startOf("year"), moment().subtract(1, "year").endOf("year")], }} - /> + /> )} diff --git a/src/components/search/GroupSelect.jsx b/src/components/search/GroupSelect.jsx index 95a0e6e..0dc2fc6 100644 --- a/src/components/search/GroupSelect.jsx +++ b/src/components/search/GroupSelect.jsx @@ -10,22 +10,28 @@ class GroupSelect extends Component { render() { const { store, mode, value, onChange, show_all, ...extProps } = this.props; + const _mode = mode || store?.group_select_mode || null; + const _show_all = ['tags', 'multiple'].includes(_mode) ? false : show_all; return (
+ + + + , + 2 + ), + // + item( + 'DateType', + 99, + + + , + 2 + ), + // item( + // 'applyDate', + // 99, + // + // + // , + // midCol + // ), + // item( + // 'applyDate2', + // 99, + // + // + // + // + // + // + // + // , + // 12 + // ), + item( + 'dates', + 99, + + + , + midCol + ), + item( + 'year', + 99, + + {/* */} + + ,2 + ), + ]; + baseChildren = baseChildren + .map((x) => { + x.hide = false; + if (props.sort === undefined) { + return x; + } + const tmpSort = props.sort; + for (const key in tmpSort) { + if (Object.prototype.hasOwnProperty.call(tmpSort, key)) { + if (x.name === key) { + x.sort = tmpSort[key]; + } + } + } + return x; + }) + .map((x) => { + if (props.hides.length === 0 && props.shows.length === 0) { + return x; + } + if (props.hides.length === 0) { + x.hide = !props.shows.includes(x.name); + } else if (props.shows.length === 0) { + x.hide = props.hides.includes(x.name); + } + return x; + }) + .filter((x) => !x.hide) + .sort((a, b) => { + return a.sort < b.sort ? -1 : 1; + }); + const children = []; + const leftStyle = {}; // { borderRight: '1px solid #dedede' }; + for (let i = 0; i < baseChildren.length; i++) { + let style = { padding: '0px 2px' }; + style = i % 2 === 0 && baseChildren[i].col === 12 ? { ...style, ...leftStyle } : style; + style = !baseChildren[i].hide ? { ...style, display: 'block' } : { ...style, display: 'none' }; + const Item = ( + + {baseChildren[i].render} + + ); + children.push(Item); + } + return children; +} diff --git a/src/components/search/SiteSelect.jsx b/src/components/search/SiteSelect.jsx index abb138b..3d22f93 100644 --- a/src/components/search/SiteSelect.jsx +++ b/src/components/search/SiteSelect.jsx @@ -11,22 +11,28 @@ class SiteSelect extends Component { render() { const { store, mode, value, onChange, show_all, ...extProps } = this.props; - return ( + const _mode = mode || store?.group_select_mode || null; + const _show_all = ['tags', 'multiple'].includes(_mode) ? false : show_all; + return (
diff --git a/src/components/search/YearPickerCharts.jsx b/src/components/search/YearPickerCharts.jsx new file mode 100644 index 0000000..1a5a6f7 --- /dev/null +++ b/src/components/search/YearPickerCharts.jsx @@ -0,0 +1,70 @@ +import React, { Component } from 'react'; +import { Col, DatePicker, Row, Form } from 'antd'; +import { observer } from 'mobx-react'; +import * as config from '../../config'; +import moment from 'moment'; +import 'moment/locale/zh-cn'; +import locale from 'antd/es/date-picker/locale/zh_CN'; +import { stores_Context } from '../../config'; + +// 用于日期选择,计算上一时间段、同比时间等 +class DatePickerCharts extends Component { + static contextType = stores_Context; + + constructor(props) { + super(props); + } + + render() { + const { date_picker_store } = this.context; + return ( +
+ + + + { + const fullYear = [e.clone().set('month', 0).set('date', 1), e.clone().set('month', 11).set('date', 31)]; + date_picker_store.onChange_dataPicker(fullYear); + if (typeof this.props.onChange === 'function') { + this.props.onChange(fullYear); + } + }} + /> + + + {this.props.hide_vs ? ( + '' + ) : ( + + + { + const fullYear = [value.clone().set('month', 0).set('date', 1), value.clone().set('month', 11).set('date', 31)]; + if (typeof this.props.onChange === 'function') { + this.props.onChange(fullYear); + } + date_picker_store?.onChange_dataPicker_cp(fullYear); + }} + /> + + + )} + +
+ ); + } +} + +export default observer(DatePickerCharts); diff --git a/src/components/search/search.css b/src/components/search/search.css new file mode 100644 index 0000000..9f8f546 --- /dev/null +++ b/src/components/search/search.css @@ -0,0 +1,4 @@ +.ant-form-item{ + margin: 0; + margin-bottom: 8px; +} diff --git a/src/mock/2.0/1.json b/src/mock/2.0/1.json deleted file mode 100644 index 9b25a55..0000000 --- a/src/mock/2.0/1.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "get|/service-web/QueryData/GetOrderCount/test": { - "errcode": "", - "errmsg": "", - "data": null, - "ordercount1|10": [ - { - "id|10-99": 1, - "key|10-99": 1, - "orderCount|1-100": 5, - "WebCode|1": ["ah", "cht"], - "groups": "groups1", - "ApplyDate": "@date(\"2023-08-dd\")" - } - ], - "ordercount2|10": [ - { - "id|100-200": 1, - "key|100-200": 1, - "orderCount|1-100": 5, - "WebCode|1": ["ah", "cht"], - "groups": "groups2", - "ApplyDate": "@date(\"2023-08-dd\")" - } - ] - } -} diff --git a/src/mock/2.0/baseinfo.json b/src/mock/2.0/baseinfo.json new file mode 100644 index 0000000..e02e285 --- /dev/null +++ b/src/mock/2.0/baseinfo.json @@ -0,0 +1,19 @@ +{ + "get|/service-web/baseinfo/operator/test": { + "errcode": 0, + "errmsg": "", + "data": null, + "loading": null, + "result|10": [ + { + "mobile": "13@integer(99999999,999999999)", + "op_id": "@integer(10,99)", + "cn_name": "@cname", + "email": "@email", + "en_name": "@first", + "code": "@word(2,3)", + "key": "@increment" + } + ] + } +} diff --git a/src/stores/DictData.js b/src/stores/DictData.js new file mode 100644 index 0000000..a9306f2 --- /dev/null +++ b/src/stores/DictData.js @@ -0,0 +1,54 @@ +import { makeAutoObservable, runInAction, toJS } from 'mobx'; +import * as req from '../utils/request'; +import { isEmpty, sortBy, objectMapper } from '../utils/commons'; + +const modelMapper = { + 'operator': { + url: '/service-web/baseinfo/operator/test', + mapper: { + op_id: [{ key: 'key' }, { key: 'value' }], + cn_name: { key: 'label' }, + en_name: { key: 'label_alias' }, + }, + }, + 'vendor': { + url: '/service-web/QueryData/GetVEIName', + mapper: { + CAV_VEI_SN: [{ key: 'key' }, { key: 'value' }], + VEI2_CompanyBN: { key: 'label' }, + }, + }, + 'creditcardbilltype': { + url: '/service-web/QueryData/GetCreditCardBillType', + mapper: { + cb_billtype: [{ key: 'key' }, { key: 'value' }, { key: 'label' }], + }, + }, +}; + +class DictData { + constructor(appStore) { + this.appStore = appStore; + makeAutoObservable(this); + } + + async fetchDictData(model = '') { + const mkey = model.toLowerCase(); + this[mkey] = { loading: true, dataSource: [] }; + const json = await req.fetchJSON(modelMapper[mkey].url); + if (json.errcode === 0) { + runInAction(() => { + this[mkey].loading = false; + this[mkey].dataSource = objectMapper(json.result, modelMapper[mkey].mapper); + console.log({ loading: false, ...json }, model, 'DictData', toJS(this[mkey])); + }); + } + return this[mkey]; + } + + data = {}; + operator = { loading: false, dataSource: [] }; + vendor = { loading: false, dataSource: [] }; + creditcardbilltype = { loading: false, dataSource: [] }; +} +export default DictData; diff --git a/src/stores/Index.js b/src/stores/Index.js index 45aed26..0d38106 100644 --- a/src/stores/Index.js +++ b/src/stores/Index.js @@ -12,6 +12,7 @@ import WhatsAppStore from "./WhatsApp"; import CustomerServicesStore from "./CustomerServices"; import TradeStore from "./Trade"; import KPI from "./KPI"; +import DictData from "./DictData"; class Index { constructor() { this.dashboard_store = new DashboardStore(this); @@ -27,6 +28,7 @@ class Index { this.customerServicesStore = new CustomerServicesStore(this); this.TradeStore = new TradeStore(this); this.KPIStore = new KPI(this); + this.DictDataStore = new DictData(this); makeAutoObservable(this); } diff --git a/src/stores/Trade.js b/src/stores/Trade.js index 113d473..cfe3aed 100644 --- a/src/stores/Trade.js +++ b/src/stores/Trade.js @@ -76,10 +76,15 @@ class Trade { }); } + setStateSearch(body) { + this.searchPayloadHome = body; + } + summaryData = { loading: false, dataSource: [] }; sideData = { loading: false, dataSource: {}, kpi: {}, monthData: [] }; topData = {}; defaultDataSubject = 'CJCount'; + searchPayloadHome = {}; } export default Trade; diff --git a/src/utils/commons.js b/src/utils/commons.js index 8b5087f..5050b07 100644 --- a/src/utils/commons.js +++ b/src/utils/commons.js @@ -441,3 +441,60 @@ export function objectMapper(input, keyMap) { return input; } + +/** + * 创建一个对应于对象路径的值数组 + */ +export function at(obj, path) { + let result; + if (Array.isArray(obj)) { + // array case + const indexes = path.split('.').map((i) => parseInt(i)); + result = []; + for (let i = 0; i < indexes.length; i++) { + result.push(obj[indexes[i]]); + } + } else { + // object case + const indexes = path.split('.').map((i) => i); + result = [obj]; + for (let i = 0; i < indexes.length; i++) { + result = [result[0][indexes[i]]]; + } + } + return result; +} +/** + * 删除 null/undefined + */ +export function flush(collection) { + let result, len, i; + if (!collection) { + return undefined; + } + if (Array.isArray(collection)) { + result = []; + len = collection.length; + for (i = 0; i < len; i++) { + const elem = collection[i]; + if (elem != null) { + result.push(elem); + } + } + return result; + } + if (typeof collection === 'object') { + result = {}; + const keys = Object.keys(collection); + len = keys.length; + for (i = 0; i < len; i++) { + const key = keys[i]; + const value = collection[key]; + if (value != null) { + result[key] = value; + } + } + return result; + } + return undefined; +} diff --git a/src/views/Home.jsx b/src/views/Home.jsx index 75b7d6b..7649fc0 100644 --- a/src/views/Home.jsx +++ b/src/views/Home.jsx @@ -9,7 +9,7 @@ import Bullet from '../components/Bullet'; import Waterfall from '../components/Waterfall'; import Column from '../components/Column'; import DataFieldRadio from './../components/DateFieldRadio'; -import DatePickerCharts from './../components/search/DatePickerCharts'; +import SearchForm from './../components/search/SearchForm'; import { empty } from './../utils/commons'; import './home.css'; @@ -17,7 +17,7 @@ import './home.css'; export default observer(() => { const navigate = useNavigate(); const { TradeStore } = useContext(stores_Context); - const { sideData, summaryData, topData } = TradeStore; + const { searchPayloadHome, sideData, summaryData, topData } = TradeStore; const topSeries = [ { key: 'Country', label: '国籍' }, @@ -28,15 +28,19 @@ export default observer(() => { useEffect(() => { if (empty(summaryData.dataSource)) { - TradeStore.fetchSummaryData(); - TradeStore.fetchTradeDataByMonth(); - for (const iterator of topSeries) { - TradeStore.fetchTradeDataByType(iterator.key); - } + // pageRefresh(); } return () => {}; }, []); + const pageRefresh = (queryData) => { + TradeStore.fetchSummaryData(); + TradeStore.fetchTradeDataByMonth(queryData); + for (const iterator of topSeries) { + TradeStore.fetchTradeDataByType(iterator.key, queryData); + } + }; + const layoutProps = { gutter: { xs: 8, sm: 8, lg: 16 }, lg: { span: 6 }, @@ -106,10 +110,30 @@ export default observer(() => { return ( <> + + + { + TradeStore.setStateSearch(form); + pageRefresh(obj); + }} + /> + +

年度业绩

-
@@ -146,7 +170,7 @@ export default observer(() => { {topSeries.map((item) => ( - +

{item.label}