UNPKG

fastlion-amis

Version:

一种MIS页面生成工具

290 lines (276 loc) 10.6 kB
import { IAbcDataParams } from "."; import { IColumn } from "../../../store/table"; import { getDecimalPlaces } from "../../../utils/utils"; export const activityBasedClassification = (data: number[], areaLimit: { aType: number, bType: number }): ABC => { data = data.sort((a, b) => (b - a)); const total = data?.length ? data.reduce((prev, curr) => { return +prev + +curr; }) : 0; let A: number[] = [], B: number[] = [], C: number[] = []; let totalA = 0, totalB = 0, totalC = 0; // 修复A类分配逻辑:先检查添加后是否满足条件,再决定是否添加 while (data.length > 0) { const nextItem = data[0]; // 只有当前totalA加上下一项后仍不超过阈值时,才添加到A类 if (totalA + nextItem <= total * areaLimit.aType / 100) { A.push(...data.splice(0, 1)); totalA += nextItem; } else { break; } } // B类分配逻辑:B类的阈值应该是从A类阈值到B类阈值的总和 const bLimit = total * areaLimit.bType / 100; while (data.length > 0) { const nextItem = data[0]; // 需要考虑A类已经占用的部分,所以使用totalA + totalB + nextItem来比较 if (totalA + totalB + nextItem <= bLimit) { B.push(...data.splice(0, 1)); totalB += nextItem; } else { break; } } // 剩余数据为C类 C = data; totalC = data.length > 0 ? C.reduce((prev, curr) => +prev + +curr) : 0; return { A, B, C } } export const getTable = (colsName: string[], abcData: ABC, params: IAbcDataParams, originColList: IColumn[], data: any[]) => { let colList = originColList.filter(col => col.name && colsName.includes(col.name)); const label = colList[0].label; const yAxisLabel = colList.find(col => col.name === params.statisticsSelects)?.label; let colsArr = [ { label: label + '类', name: 'type', type: 'plain' }, { label: label + '项数', name: 'sum', type: 'number', }, { label: label + '占比', name: 'per', type: 'number', suffix: '%', precision: 3, isPercentage: true }, { label: yAxisLabel + '占比', name: 'sumPer', type: 'number', suffix: '%', precision: 3, isPercentage: true }, ]; if (params.displayEachColumn) { colsArr.push({ label: label + '列', name: 'col', type: 'plain' }); } let tableColList = []; for (let i = 0; i < colsArr.length; i++) { const info = colsArr[i]; let col: any = { name: info.name, label: info.label, type: info.type!, suffix: info.suffix, precision: info.precision, isNumerical: true, sortable: true, isPercentage: info.isPercentage, } tableColList.push(col); } // { // caption: colList[1].attr.caption + '总价均值', // fieldName: 'sumValue' // } let col: IColumn = JSON.parse(JSON.stringify(colList[1])); col = { ...col.pristine, ...col } col.label = yAxisLabel + '均值'; col.name = 'sumValue'; // 江惠需求:希望每一类的那列 在最后一列 // tableColList.push(col) tableColList.splice(-1, 0, col); let colData = data .sort(compare(params.statisticsSelects)) .map(item => { let val = item[params.sortSelectes] // 不太明白什么是lookUpData // let col = colList.find(item => item.name === params.sortSelectes) // if (col?.elementType === 'lookup' && lookUpData) { // val = lookUpData?.[col.fieldName]?.find(lookup => lookup.value == item[col?.lookUpKeyField])?.[col.fieldName] // } return val }); function compare(property: string) { return function (obj1: obj<any>, obj2: obj<any>) { var value1 = obj1[property]; var value2 = obj2[property]; return value2 - value1; // 升序 } } const tableData = Object.keys(abcData).map((key: keyof ABC) => { const cols = colData.splice(0, abcData[key].length); const sumValue = cols.length ? (AbcAnalysisMath.sum(abcData[key]) / cols.length).toFixed(2) : 0; return { type: key + '类', sum: abcData[key].length, per: AbcAnalysisMath.per(key, abcData), sumPer: AbcAnalysisMath.percent(abcData[key], abcData), sumValue, col: cols.join(',') } }); return { tableColumns: tableColList, tableData } } export const formatAbcTableData = (params: IAbcDataParams, data1: obj<any>[]) => { const { settingType, aType, bType } = params let colName = params.statisticsSelects; let colData: number[] = []; data1.forEach(dataItem => { colData.push(+dataItem[colName]); }); let abType = { aType: 65, bType: 85 } if (settingType === 'manual') { abType = { aType, bType } } return { colData, abType } } export function statisticsData(sortName: string | number, compotedNames: string[] | number[], data: obj[], originColList: IColumn[]): obj[] { if (!sortName || !data.length) { return []; } let _data: obj<any>[] = []; if (compotedNames && compotedNames.length) { data.forEach(dataItem => { if (_data.length === 0) { return _data.push(dataItem); } let ifPush = true; _data.forEach(_dataItem => { if (_dataItem[sortName] === dataItem[sortName]) { ifPush = false; const compotedArr = Array.isArray(compotedNames) ? compotedNames : [compotedNames] compotedArr.forEach(name => { _dataItem[name] = +dataItem[name] + +_dataItem[name]; }); } }); ifPush && _data.push(dataItem); }); } else { // 列统计 let sortNameContents = []; data.forEach(item => { const field: any = originColList.find(item => item.name === sortName); const value = `${item[sortName]}`; if (value && sortNameContents.indexOf(value) === -1) { sortNameContents.push(value); item['_COUNT'] = item['_COUNT'] || 1; item['_PERCENT'] = item['_PERCENT'] || (item['_COUNT'] / data.length * 100).toFixed(2) + '%'; // _data.push(field.elementType === 'lookup' ? // { // ...item, // [sortName]: item[field.lookUpKeyField].split(field?.flLookup?.valueSep || ',') // .join(field?.flLookup?.valueSep || ',') // } // : // item // ); _data.push(item) } else { sortNameContents.forEach(content => { if (content === value) { _data.forEach((_item, i) => { const _value = _item[sortName] && `${_item[sortName]}`; if (_value === value) { _data[i]['_COUNT'] = _item['_COUNT'] + 1; _data[i]['_PERCENT'] = (_data[i]['_COUNT'] / data.length * 100).toFixed(2) + '%'; } }) } }) } }); } return _data; } export const getAbcTableData = (params: IAbcDataParams, data: obj<any>[], originColList: IColumn[]) => { const { sortSelectes, statisticsSelects } = params // 需要深拷贝data 因为statisticsData内部对引用地址的数据进行了操作 let dealData: obj<any>[] = JSON.parse(JSON.stringify(data)) // 需要处理的数据 let sortName = sortSelectes const _data = statisticsData(sortName, [statisticsSelects], dealData, originColList); const { colData, abType } = formatAbcTableData(params, _data) let abcData = activityBasedClassification(colData, abType); return getTable([sortSelectes, statisticsSelects], abcData, params, originColList, _data); } export type ABC = { A: number[]; B: number[]; C: number[]; } export const AbcAnalysisMath = { sum: (values: number[]): number => { let numberMaxLen = 2; return values.length ? values.reduce((total: number, curr: number) => { numberMaxLen = Math.max(getDecimalPlaces(curr), numberMaxLen) return +Number(+total) + Number(+curr) }, 0) : 0 }, colLen: (values: number[]): number => values.length, avg: (values: number[]): number => AbcAnalysisMath.sum(values) / AbcAnalysisMath.colLen(values), percent: (v: number[], values: ABC): number => { let totalA = values.A.length ? values.A.reduce((total, curr) => total + curr) : 0; let totalB = values.B.length ? values.B.reduce((total, curr) => total + curr) : 0; let totalC = values.C.length ? values.C.reduce((total, curr) => total + curr) : 0; let value = v.length ? v.reduce((total, curr) => total + curr) : 0; // 数据为数字型,才能进行继续统计 if (totalA + totalB + totalC === 0) return 0 return (value / (totalA + totalB + totalC)) * 100; }, per: (key: keyof ABC, values: ABC): number => { let len = values.A.length + values.B.length + values.C.length; // 数据为数字型,才能进行继续统计 if (len === 0) return 0 return (values[key].length / len) * 100; } } // 计算累计占有 export const getBasedCount = (data: obj[], sortName?: string, statisticsSelects?: string) => { if (!sortName || !data.length || !statisticsSelects) { return []; } let total = 0; data.forEach(item => { total += item[statisticsSelects] }) let sum = 0; const newArr = data.map(item => { sum+=item[statisticsSelects] return { ...item, countPer: (sum / total * 100).toFixed(3) } }) return newArr; }