lambo-design-bi 0.0.187 → 0.0.189
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bi/widget/page/child-page-tm.vue +14 -2
- package/bi/widget/table/paging-table.vue +72 -79
- package/package.json +1 -1
- package/pub/charts/factory/options.js +282 -3
- package/util/math-util.js +230 -56
|
@@ -29,6 +29,7 @@ import { getPageConfig } from '../api/config'
|
|
|
29
29
|
import { deepCopy } from "@lambo-design/shared/utils/assist"
|
|
30
30
|
import { getWidgetName } from '../util/widget-map'
|
|
31
31
|
import { setRouteCfg2Search, getInitSearchRes, getSearchFormRes } from './util/common'
|
|
32
|
+
import { EventBus, EVENT_TYPES } from '../util/event-bus'
|
|
32
33
|
|
|
33
34
|
export default {
|
|
34
35
|
name: 'BiChildPageTm',
|
|
@@ -95,11 +96,11 @@ export default {
|
|
|
95
96
|
}
|
|
96
97
|
if (parentRouteName) {
|
|
97
98
|
console.log("child-page-tm goBack parentRouteName:", parentRouteName)
|
|
98
|
-
this.$router.push({
|
|
99
|
+
this.$router.push({
|
|
99
100
|
name: parentRouteName,
|
|
100
101
|
query: { pageId: this.parentPageId }
|
|
101
102
|
})
|
|
102
|
-
} else {
|
|
103
|
+
} else {
|
|
103
104
|
console.log("child-page-tm goBack history.back()")
|
|
104
105
|
this.$router.go(-1)
|
|
105
106
|
}
|
|
@@ -127,12 +128,19 @@ export default {
|
|
|
127
128
|
}
|
|
128
129
|
this.params = deepCopy(formParams)
|
|
129
130
|
console.log("child-page-tm doSearch 2 this.params:", this.params)
|
|
131
|
+
},
|
|
132
|
+
handleNumIdxActivated(eventData) {
|
|
133
|
+
console.log('BiPage handleNumIdxActivated eventData:', eventData)
|
|
134
|
+
// 处理数值指标激活事件的逻辑
|
|
135
|
+
this.$set(this.params, 'idxBizCode', eventData["idxBizCode"]);
|
|
130
136
|
}
|
|
131
137
|
},
|
|
132
138
|
created() {
|
|
133
139
|
this.getConfig()
|
|
134
140
|
},
|
|
135
141
|
mounted() {
|
|
142
|
+
// 监听卡片激活事件
|
|
143
|
+
EventBus.$on(EVENT_TYPES.NUM_IDX_ACTIVATED, this.handleNumIdxActivated)
|
|
136
144
|
|
|
137
145
|
},
|
|
138
146
|
watch: {
|
|
@@ -158,6 +166,10 @@ export default {
|
|
|
158
166
|
)
|
|
159
167
|
return filteredWidgets.length > 0
|
|
160
168
|
}
|
|
169
|
+
},
|
|
170
|
+
beforeDestroy() {
|
|
171
|
+
// 组件销毁前移除事件监听
|
|
172
|
+
EventBus.$off(EVENT_TYPES.NUM_IDX_ACTIVATED, this.handleOtherCardActivated)
|
|
161
173
|
}
|
|
162
174
|
}
|
|
163
175
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<LamboPagingTableBi ref="table" :auto-search="false" :columns="columns" :dataUrl="widget.options.url"
|
|
4
4
|
:export-batch-size="20000" :show-table-option="false" :exportName="widget.name"
|
|
5
5
|
:page-disable="widget.options.isPaging === '0'" :page-size="widget.options.pageSize" :export-request-limit="200"
|
|
6
|
-
:isSingleSelectModel="true" :showSummary="widget.options.
|
|
6
|
+
:isSingleSelectModel="true" :showSummary="widget.options.isAllSum === '1'" :summary-method="handleSummary"
|
|
7
7
|
@on-data-load="onDataLoad" :searchParams="tableSearchParams">
|
|
8
8
|
<div slot="search"></div>
|
|
9
9
|
</LamboPagingTableBi>
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
<script>
|
|
13
13
|
import biConfig from '../config/config'
|
|
14
|
-
import { getListMapData } from '../api/data'
|
|
15
14
|
import LamboPagingTableBi from '../../../pub/table/paging-table/index.vue'
|
|
15
|
+
import { accAdd } from '../../../util/math-util'
|
|
16
16
|
|
|
17
17
|
export default {
|
|
18
18
|
name: 'BiPagingTable',
|
|
@@ -31,7 +31,8 @@ export default {
|
|
|
31
31
|
return {
|
|
32
32
|
tableSearchParams: {
|
|
33
33
|
inJson: ''
|
|
34
|
-
}
|
|
34
|
+
},
|
|
35
|
+
allSumData: [],
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
methods: {
|
|
@@ -51,84 +52,78 @@ export default {
|
|
|
51
52
|
query: newQuery
|
|
52
53
|
})
|
|
53
54
|
},
|
|
54
|
-
onDataLoad() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (this.columns.length > 0) {
|
|
63
|
-
console.log(JSON.stringify(this.columns))
|
|
64
|
-
if (this.columns[0].key === 'index' || this.columns[0].key === 'checkbox') {
|
|
65
|
-
sumRows[this.columns[1].key] = '总计';
|
|
66
|
-
} else {
|
|
67
|
-
sumRows[this.columns[0].key] = '总计';
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
sumRows.is_append_page_all_sum = true;
|
|
71
|
-
this.$refs.table.tableData.push(sumRows)
|
|
72
|
-
console.log("列表增加总计成功")
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}).catch(err => {
|
|
76
|
-
console.error("调用总计服务[" + this.widget.options.sumApiId + "]异常:", err)
|
|
77
|
-
})
|
|
55
|
+
onDataLoad(dataRes) {
|
|
56
|
+
console.log("onDataLoad dataRes:", dataRes)
|
|
57
|
+
if (this.widget.options.isPaging === '1' && this.widget.options.isAllSum === '1') {
|
|
58
|
+
// 接收数据,并赋值
|
|
59
|
+
if (dataRes && dataRes.code === 1) {
|
|
60
|
+
this.allSumData = dataRes.data.sums || []
|
|
61
|
+
console.log("onDataLoad this.allSumData:", this.allSumData)
|
|
62
|
+
}
|
|
78
63
|
}
|
|
79
64
|
},
|
|
80
|
-
/*合计 根据columns中的hasSum是否合计来进行计算*/
|
|
81
65
|
handleSummary({ columns, data }) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
const value = Number(curr);
|
|
95
|
-
if (!isNaN(value)) {
|
|
96
|
-
return prev + curr;
|
|
97
|
-
} else {
|
|
98
|
-
return prev;
|
|
99
|
-
}
|
|
100
|
-
}, 0);
|
|
101
|
-
sums[key] = {
|
|
102
|
-
key,
|
|
103
|
-
value: v
|
|
104
|
-
};
|
|
105
|
-
} else {
|
|
106
|
-
sums[key] = {
|
|
107
|
-
key,
|
|
108
|
-
value: ''
|
|
109
|
-
};
|
|
66
|
+
console.log("handleSummary { columns, data }:", { columns, data })
|
|
67
|
+
const sums = {}
|
|
68
|
+
if (columns && columns.length > 0) {
|
|
69
|
+
sums[columns[0].key] = {
|
|
70
|
+
key: columns[0].key,
|
|
71
|
+
value: '总计'
|
|
72
|
+
}
|
|
73
|
+
// 如果是分页表格
|
|
74
|
+
if (this.widget.options.isPaging === '1') {
|
|
75
|
+
let allSumObj = {}
|
|
76
|
+
if (this.allSumData && this.allSumData.length > 0) {
|
|
77
|
+
allSumObj = this.allSumData[0] || {}
|
|
110
78
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
};
|
|
79
|
+
console.log("handleSummary allSumObj:", allSumObj)
|
|
80
|
+
for (let i = 1; i < columns.length; i++) {
|
|
81
|
+
let col = columns[i]
|
|
82
|
+
let colKey = col.key
|
|
83
|
+
if (Object.prototype.hasOwnProperty.call(allSumObj, colKey)) {
|
|
84
|
+
sums[colKey] = {
|
|
85
|
+
key: colKey,
|
|
86
|
+
value: allSumObj[colKey] || ''
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
sums[colKey] = {
|
|
90
|
+
key: colKey,
|
|
91
|
+
value: ''
|
|
92
|
+
}
|
|
93
|
+
}
|
|
127
94
|
}
|
|
128
95
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
96
|
+
// 如果不是分页表格
|
|
97
|
+
else {
|
|
98
|
+
columns.forEach((column, index) => {
|
|
99
|
+
const key = column.key
|
|
100
|
+
if (index > 0) {
|
|
101
|
+
const values = data.map(item => Number(item[key]))
|
|
102
|
+
if (values && values.length > 0 && !values.every(value => isNaN(value))) {
|
|
103
|
+
const v = values.reduce((prev, curr) => {
|
|
104
|
+
const value = Number(curr)
|
|
105
|
+
if (!isNaN(value)) {
|
|
106
|
+
return accAdd(prev, curr)
|
|
107
|
+
} else {
|
|
108
|
+
return prev
|
|
109
|
+
}
|
|
110
|
+
}, 0);
|
|
111
|
+
sums[key] = {
|
|
112
|
+
key,
|
|
113
|
+
value: v
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
sums[key] = {
|
|
117
|
+
key,
|
|
118
|
+
value: ''
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return sums
|
|
126
|
+
}
|
|
132
127
|
},
|
|
133
128
|
created() {
|
|
134
129
|
// eslint-disable-next-line
|
|
@@ -141,9 +136,7 @@ export default {
|
|
|
141
136
|
computed: {
|
|
142
137
|
columns() {
|
|
143
138
|
let columns = []
|
|
144
|
-
if (this.widget &&
|
|
145
|
-
Object.prototype.hasOwnProperty.call(this.widget, "options") &&
|
|
146
|
-
Object.prototype.hasOwnProperty.call(this.widget.options, "columns")) {
|
|
139
|
+
if (this.widget && Object.prototype.hasOwnProperty.call(this.widget, "options") && Object.prototype.hasOwnProperty.call(this.widget.options, "columns")) {
|
|
147
140
|
if (this.widget.options.columns) {
|
|
148
141
|
try {
|
|
149
142
|
columns = JSON.parse(this.widget.options.columns)
|
|
@@ -183,7 +176,7 @@ export default {
|
|
|
183
176
|
this.doSearch()
|
|
184
177
|
},
|
|
185
178
|
deep: true
|
|
186
|
-
}
|
|
179
|
+
}
|
|
187
180
|
}
|
|
188
181
|
}
|
|
189
182
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
1
3
|
import * as echarts from 'echarts'
|
|
2
4
|
import { accDiv, accMul } from '../../../util/math-util'
|
|
3
|
-
|
|
4
5
|
function generateTestData(dataX, dataY) {
|
|
5
6
|
const colors = ['#2D8CF0', '#45D5D0', '#FFBF37', '#FD7336', '#655EF3', '#47D791', '#F85968', '#33BFF3', '#C74EF4', '#F84CEE', '#F5D000', '#B7E518'];
|
|
6
7
|
const total = dataY.reduce((a, b) => a + b, 0);
|
|
@@ -97,6 +98,8 @@ function getLevelOption() {
|
|
|
97
98
|
* 43 仪表盘进度条)
|
|
98
99
|
* 2A:单个柱状图以及多条折线,
|
|
99
100
|
* 2B:单个柱状图以及左右 <br/>
|
|
101
|
+
* 44:雷达图
|
|
102
|
+
* 45:圆形进度图
|
|
100
103
|
* dataX:x轴数据 <br/>
|
|
101
104
|
* dataY:y轴数据 <br/>
|
|
102
105
|
* dataDim:组数据 (例如柱状图、折线图多组数据) <br/>
|
|
@@ -471,8 +474,8 @@ export function getECharts(type, dataX, dataY, dataDim) {
|
|
|
471
474
|
shadowBlur: 4
|
|
472
475
|
},
|
|
473
476
|
data: [
|
|
474
|
-
{type: 'max', name: '
|
|
475
|
-
{type: 'min', name: '
|
|
477
|
+
{type: 'max', name: 'Max'},
|
|
478
|
+
{type: 'min', name: 'Min',}
|
|
476
479
|
]
|
|
477
480
|
},
|
|
478
481
|
markLine: {
|
|
@@ -2590,6 +2593,282 @@ export function getECharts(type, dataX, dataY, dataDim) {
|
|
|
2590
2593
|
series: series
|
|
2591
2594
|
};
|
|
2592
2595
|
}
|
|
2596
|
+
else if (type === '44') {
|
|
2597
|
+
const transData = transpose(dataY);
|
|
2598
|
+
const indicators = dataX.map((name, index) => {
|
|
2599
|
+
let maxValue = 0;
|
|
2600
|
+
for (let i = 0; i < dataY[index].length; i++) {
|
|
2601
|
+
if (dataY[index] && dataY[index][i] > maxValue) {
|
|
2602
|
+
maxValue = dataY[index][i];
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
return {
|
|
2606
|
+
name: name,
|
|
2607
|
+
max: Math.ceil(maxValue )
|
|
2608
|
+
};
|
|
2609
|
+
});
|
|
2610
|
+
const seriesData = [];
|
|
2611
|
+
transData.forEach((data, index) => {
|
|
2612
|
+
seriesData.push({
|
|
2613
|
+
name: dataDim[index],
|
|
2614
|
+
value: data,
|
|
2615
|
+
lineStyle: {
|
|
2616
|
+
width: 3,
|
|
2617
|
+
color: colors[index % colors.length]
|
|
2618
|
+
},
|
|
2619
|
+
itemStyle: {
|
|
2620
|
+
color: colors[index % colors.length]
|
|
2621
|
+
},
|
|
2622
|
+
areaStyle: {
|
|
2623
|
+
color: areaColors[index % areaColors.length]
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
});
|
|
2627
|
+
opt = {
|
|
2628
|
+
legend: {
|
|
2629
|
+
data: seriesData.map(item => item.name),
|
|
2630
|
+
bottom:0,
|
|
2631
|
+
textStyle: {
|
|
2632
|
+
fontSize: 12
|
|
2633
|
+
}
|
|
2634
|
+
},
|
|
2635
|
+
tooltip: {},
|
|
2636
|
+
radar: {
|
|
2637
|
+
center: ['50%', '45%'],
|
|
2638
|
+
radius: '70%',
|
|
2639
|
+
indicator: indicators,
|
|
2640
|
+
name: {
|
|
2641
|
+
textStyle: {
|
|
2642
|
+
color: '#666',
|
|
2643
|
+
fontSize: 14,
|
|
2644
|
+
fontWeight: 'bold'
|
|
2645
|
+
}
|
|
2646
|
+
},
|
|
2647
|
+
axisLine: {
|
|
2648
|
+
lineStyle: {
|
|
2649
|
+
color: '#ddd'
|
|
2650
|
+
}
|
|
2651
|
+
},
|
|
2652
|
+
splitLine: {
|
|
2653
|
+
lineStyle: {
|
|
2654
|
+
color: '#eee'
|
|
2655
|
+
}
|
|
2656
|
+
},
|
|
2657
|
+
splitArea: {
|
|
2658
|
+
show: true,
|
|
2659
|
+
areaStyle: {
|
|
2660
|
+
color: ['rgba(250,250,250,0.8)', 'rgba(240,240,240,0.8)']
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
},
|
|
2664
|
+
series: [{
|
|
2665
|
+
type: 'radar',
|
|
2666
|
+
data: seriesData,
|
|
2667
|
+
symbol: 'circle',
|
|
2668
|
+
symbolSize: 6,
|
|
2669
|
+
lineStyle: {
|
|
2670
|
+
type: 'solid'
|
|
2671
|
+
}
|
|
2672
|
+
}],
|
|
2673
|
+
animation: true,
|
|
2674
|
+
animationDuration: 1000
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
else if (type === '45') {
|
|
2678
|
+
const progressValue = dataY[0] && dataY[0][0] ? dataY[0][0] : 0;
|
|
2679
|
+
const maxValue = 100;
|
|
2680
|
+
|
|
2681
|
+
const colorIndex = dataY[0] && dataY[0][1] ? dataY[0][1] % colors.length : 0;
|
|
2682
|
+
const baseColor = colors[colorIndex];
|
|
2683
|
+
const lightColor = hexToRgba(baseColor, 0.6);
|
|
2684
|
+
|
|
2685
|
+
const progressGradient = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
2686
|
+
{ offset: 0, color: baseColor },
|
|
2687
|
+
{ offset: 0.5, color: lightColor },
|
|
2688
|
+
{ offset: 1, color: hexToRgba(baseColor, 0.3) }
|
|
2689
|
+
]);
|
|
2690
|
+
|
|
2691
|
+
const bgColorIndex = (colorIndex + 1) % colors.length;
|
|
2692
|
+
const bgColor = colors[bgColorIndex];
|
|
2693
|
+
const bgColorTransparent = hexToRgba(bgColor, 0);
|
|
2694
|
+
const bgColorSolid = hexToRgba(bgColor, 0.4);
|
|
2695
|
+
|
|
2696
|
+
opt = {
|
|
2697
|
+
title: [
|
|
2698
|
+
{
|
|
2699
|
+
text: dataDim[0] || '',
|
|
2700
|
+
x: 'center',
|
|
2701
|
+
top: '32%',
|
|
2702
|
+
textStyle: {
|
|
2703
|
+
fontSize: 26,
|
|
2704
|
+
fontFamily: 'Microsoft YaHei',
|
|
2705
|
+
fontWeight: '400',
|
|
2706
|
+
color: '#777',
|
|
2707
|
+
textShadow: '0 1px 2px rgba(0,0,0,0.05)'
|
|
2708
|
+
},
|
|
2709
|
+
},
|
|
2710
|
+
{
|
|
2711
|
+
text: `${progressValue}%`,
|
|
2712
|
+
x: 'center',
|
|
2713
|
+
top: '50%',
|
|
2714
|
+
textStyle: {
|
|
2715
|
+
fontSize: 52,
|
|
2716
|
+
color: baseColor,
|
|
2717
|
+
fontWeight: '500',
|
|
2718
|
+
fontFamily: 'Microsoft YaHei',
|
|
2719
|
+
textShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
|
2720
|
+
},
|
|
2721
|
+
},
|
|
2722
|
+
],
|
|
2723
|
+
polar: {
|
|
2724
|
+
radius: ['44%', '50%'],
|
|
2725
|
+
center: ['50%', '50%'],
|
|
2726
|
+
},
|
|
2727
|
+
angleAxis: {
|
|
2728
|
+
max: maxValue,
|
|
2729
|
+
show: false,
|
|
2730
|
+
},
|
|
2731
|
+
radiusAxis: {
|
|
2732
|
+
type: 'category',
|
|
2733
|
+
show: true,
|
|
2734
|
+
axisLabel: {
|
|
2735
|
+
show: false,
|
|
2736
|
+
},
|
|
2737
|
+
axisLine: {
|
|
2738
|
+
show: false,
|
|
2739
|
+
},
|
|
2740
|
+
axisTick: {
|
|
2741
|
+
show: false,
|
|
2742
|
+
},
|
|
2743
|
+
},
|
|
2744
|
+
series: [
|
|
2745
|
+
{
|
|
2746
|
+
type: 'pie',
|
|
2747
|
+
startAngle: 90,
|
|
2748
|
+
radius: ['83%', '90%'],
|
|
2749
|
+
center: ['50%', '50%'],
|
|
2750
|
+
hoverAnimation: true,
|
|
2751
|
+
animationType: 'scale',
|
|
2752
|
+
animationEasing: 'cubicOut',
|
|
2753
|
+
itemStyle: {
|
|
2754
|
+
borderRadius: 10,
|
|
2755
|
+
borderWidth: 0,
|
|
2756
|
+
shadowColor: hexToRgba(baseColor, 0.3),
|
|
2757
|
+
shadowBlur: 10,
|
|
2758
|
+
shadowOffsetY: 2
|
|
2759
|
+
},
|
|
2760
|
+
data: [
|
|
2761
|
+
{
|
|
2762
|
+
hoverOffset: 5,
|
|
2763
|
+
value: progressValue,
|
|
2764
|
+
name: '',
|
|
2765
|
+
itemStyle: {
|
|
2766
|
+
color: progressGradient,
|
|
2767
|
+
borderWidth: 0,
|
|
2768
|
+
borderColor: hexToRgba(baseColor, 0.8),
|
|
2769
|
+
},
|
|
2770
|
+
label: {
|
|
2771
|
+
show: false,
|
|
2772
|
+
},
|
|
2773
|
+
labelLine: {
|
|
2774
|
+
lineStyle: {
|
|
2775
|
+
width: 0,
|
|
2776
|
+
},
|
|
2777
|
+
},
|
|
2778
|
+
emphasis: {
|
|
2779
|
+
itemStyle: {
|
|
2780
|
+
shadowColor: hexToRgba(baseColor, 0.5),
|
|
2781
|
+
shadowBlur: 15,
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2785
|
+
{
|
|
2786
|
+
label: {
|
|
2787
|
+
show: false,
|
|
2788
|
+
},
|
|
2789
|
+
labelLine: {
|
|
2790
|
+
lineStyle: {
|
|
2791
|
+
width: 0,
|
|
2792
|
+
},
|
|
2793
|
+
},
|
|
2794
|
+
value: maxValue - progressValue,
|
|
2795
|
+
itemStyle: {
|
|
2796
|
+
color: 'rgba(200, 200, 200, 0.1)',
|
|
2797
|
+
borderWidth: 0,
|
|
2798
|
+
},
|
|
2799
|
+
},
|
|
2800
|
+
],
|
|
2801
|
+
},
|
|
2802
|
+
{
|
|
2803
|
+
name: '',
|
|
2804
|
+
type: 'pie',
|
|
2805
|
+
startAngle: 90,
|
|
2806
|
+
radius: ['78%', '82%'],
|
|
2807
|
+
hoverAnimation: false,
|
|
2808
|
+
center: ['50%', '50%'],
|
|
2809
|
+
itemStyle: {
|
|
2810
|
+
color: new echarts.graphic.RadialGradient(0.5, 0.5, 0.7, [
|
|
2811
|
+
{
|
|
2812
|
+
offset: 0,
|
|
2813
|
+
color: bgColorSolid,
|
|
2814
|
+
},
|
|
2815
|
+
{
|
|
2816
|
+
offset: 0.8,
|
|
2817
|
+
color: hexToRgba(bgColor, 0.2),
|
|
2818
|
+
},
|
|
2819
|
+
{
|
|
2820
|
+
offset: 1,
|
|
2821
|
+
color: bgColorTransparent,
|
|
2822
|
+
},
|
|
2823
|
+
]),
|
|
2824
|
+
borderWidth: 0,
|
|
2825
|
+
shadowBlur: 8,
|
|
2826
|
+
shadowColor: hexToRgba(bgColor, 0.15),
|
|
2827
|
+
},
|
|
2828
|
+
data: [
|
|
2829
|
+
{
|
|
2830
|
+
value: maxValue,
|
|
2831
|
+
itemStyle: {
|
|
2832
|
+
borderWidth: 0,
|
|
2833
|
+
}
|
|
2834
|
+
},
|
|
2835
|
+
],
|
|
2836
|
+
label: {
|
|
2837
|
+
show: false
|
|
2838
|
+
},
|
|
2839
|
+
},
|
|
2840
|
+
{
|
|
2841
|
+
name: '',
|
|
2842
|
+
type: 'pie',
|
|
2843
|
+
radius: '70%',
|
|
2844
|
+
center: ['50%', '50%'],
|
|
2845
|
+
startAngle: 90,
|
|
2846
|
+
hoverAnimation: false,
|
|
2847
|
+
silent: true,
|
|
2848
|
+
itemStyle: {
|
|
2849
|
+
color: new echarts.graphic.RadialGradient(0.5, 0.5, 0.5, [
|
|
2850
|
+
{ offset: 0, color: hexToRgba(baseColor, 0.08) },
|
|
2851
|
+
{ offset: 0.7, color: hexToRgba(baseColor, 0.03) },
|
|
2852
|
+
{ offset: 1, color: hexToRgba(baseColor, 0) }
|
|
2853
|
+
]),
|
|
2854
|
+
borderWidth: 0,
|
|
2855
|
+
},
|
|
2856
|
+
label: {
|
|
2857
|
+
show: false
|
|
2858
|
+
},
|
|
2859
|
+
data: [{
|
|
2860
|
+
value: 100,
|
|
2861
|
+
itemStyle: {
|
|
2862
|
+
borderWidth: 0
|
|
2863
|
+
}
|
|
2864
|
+
}]
|
|
2865
|
+
}
|
|
2866
|
+
],
|
|
2867
|
+
animation: true,
|
|
2868
|
+
animationDuration: 1000,
|
|
2869
|
+
animationEasing: 'cubicOut'
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2593
2872
|
return opt
|
|
2594
2873
|
}
|
|
2595
2874
|
|
package/util/math-util.js
CHANGED
|
@@ -1,78 +1,252 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 高精度加法计算(修复JS浮点数精度问题)
|
|
3
|
+
* @param {number|string} arg1 - 第一个加数
|
|
4
|
+
* @param {number|string} arg2 - 第二个加数
|
|
5
|
+
* @returns {number} 计算结果
|
|
6
|
+
*/
|
|
7
|
+
export function accAdd(arg1, arg2) {
|
|
8
|
+
// 参数校验
|
|
9
|
+
if (arg1 == null || arg2 == null) {
|
|
10
|
+
console.warn('accAdd: 参数不能为null或undefined');
|
|
11
|
+
return NaN;
|
|
5
12
|
}
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
14
|
+
// 转换为数字
|
|
15
|
+
const num1 = Number(arg1);
|
|
16
|
+
const num2 = Number(arg2);
|
|
10
17
|
|
|
11
|
-
//
|
|
12
|
-
if (
|
|
13
|
-
|
|
18
|
+
// 检查是否为有效数字
|
|
19
|
+
if (isNaN(num1) || isNaN(num2)) {
|
|
20
|
+
console.warn(`accAdd: 参数无效,arg1=${arg1}, arg2=${arg2}`);
|
|
21
|
+
return NaN;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
|
-
//
|
|
17
|
-
if (
|
|
18
|
-
|
|
24
|
+
// 如果是整数,直接相加(不会有精度问题)
|
|
25
|
+
if (Number.isInteger(num1) && Number.isInteger(num2)) {
|
|
26
|
+
return num1 + num2;
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
const
|
|
29
|
+
// 处理科学计数法
|
|
30
|
+
const str1 = num1.toString();
|
|
31
|
+
const str2 = num2.toString();
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
// 获取小数位数
|
|
34
|
+
const getDecimalLength = (numStr) => {
|
|
35
|
+
// 处理科学计数法
|
|
36
|
+
if (numStr.includes('e') || numStr.includes('E')) {
|
|
37
|
+
// 将科学计数法转换为普通小数
|
|
38
|
+
const [base, exponent] = numStr.toLowerCase().split('e');
|
|
39
|
+
const baseDecimalLength = base.includes('.') ? base.split('.')[1].length : 0;
|
|
40
|
+
const exp = parseInt(exponent);
|
|
41
|
+
return Math.max(0, baseDecimalLength - exp);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 普通小数
|
|
45
|
+
const decimalPart = numStr.split('.')[1];
|
|
46
|
+
return decimalPart ? decimalPart.length : 0;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const decimalLen1 = getDecimalLength(str1);
|
|
51
|
+
const decimalLen2 = getDecimalLength(str2);
|
|
52
|
+
const maxDecimalLen = Math.max(decimalLen1, decimalLen2);
|
|
53
|
+
|
|
54
|
+
// 使用放大倍数法计算
|
|
55
|
+
const multiplier = Math.pow(10, maxDecimalLen);
|
|
56
|
+
|
|
57
|
+
// 使用精确的乘法避免中间步骤的精度丢失
|
|
58
|
+
const multiply = (num, multiplier) => {
|
|
59
|
+
// 分离整数和小数部分
|
|
60
|
+
const [integerPart, decimalPart = ''] = num.toString().split('.');
|
|
61
|
+
const decimalNum = parseInt(decimalPart.padEnd(maxDecimalLen, '0'));
|
|
62
|
+
const integerNum = parseInt(integerPart || '0');
|
|
63
|
+
return integerNum * multiplier + decimalNum;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const result = (multiply(num1, multiplier) + multiply(num2, multiplier)) / multiplier;
|
|
67
|
+
|
|
68
|
+
// 处理可能的精度误差
|
|
69
|
+
return parseFloat(result.toFixed(maxDecimalLen));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('accAdd 计算错误:', error);
|
|
72
|
+
// 降级处理:使用toFixed
|
|
73
|
+
const maxDecimal = Math.max(
|
|
74
|
+
(str1.split('.')[1] || '').length,
|
|
75
|
+
(str2.split('.')[1] || '').length
|
|
76
|
+
);
|
|
77
|
+
return parseFloat((num1 + num2).toFixed(maxDecimal));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 高精度减法
|
|
83
|
+
* @param {number|string} arg1 - 被减数
|
|
84
|
+
* @param {number|string} arg2 - 减数
|
|
85
|
+
* @returns {number} 计算结果
|
|
86
|
+
*/
|
|
87
|
+
export function accSub(arg1, arg2) {
|
|
88
|
+
return accAdd(arg1, -arg2);
|
|
25
89
|
}
|
|
26
90
|
|
|
27
|
-
|
|
91
|
+
/**
|
|
92
|
+
* 高精度乘法
|
|
93
|
+
* @param {number|string} arg1 - 第一个乘数
|
|
94
|
+
* @param {number|string} arg2 - 第二个乘数
|
|
95
|
+
* @returns {number} 计算结果
|
|
96
|
+
*/
|
|
28
97
|
export function accMul(arg1, arg2) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
m += s1.split(".")[1].length;
|
|
34
|
-
}
|
|
35
|
-
if (s2.includes('.')) {
|
|
36
|
-
m += s2.split(".")[1].length;
|
|
98
|
+
// 参数校验
|
|
99
|
+
if (arg1 == null || arg2 == null) {
|
|
100
|
+
console.warn('accMul: 参数不能为null或undefined');
|
|
101
|
+
return NaN;
|
|
37
102
|
}
|
|
38
103
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
r1 = arg1.toString().split(".")[1].length
|
|
47
|
-
} catch (e) {
|
|
48
|
-
r1 = 0
|
|
49
|
-
console.error('accAdd:', e)
|
|
104
|
+
const num1 = Number(arg1);
|
|
105
|
+
const num2 = Number(arg2);
|
|
106
|
+
|
|
107
|
+
if (isNaN(num1) || isNaN(num2)) {
|
|
108
|
+
console.warn(`accMul: 参数无效,arg1=${arg1}, arg2=${arg2}`);
|
|
109
|
+
return NaN;
|
|
50
110
|
}
|
|
111
|
+
|
|
112
|
+
// 处理科学计数法
|
|
113
|
+
const str1 = num1.toString();
|
|
114
|
+
const str2 = num2.toString();
|
|
115
|
+
|
|
116
|
+
const getDecimalLength = (numStr) => {
|
|
117
|
+
if (numStr.includes('e') || numStr.includes('E')) {
|
|
118
|
+
const [base, exponent] = numStr.toLowerCase().split('e');
|
|
119
|
+
const baseDecimalLength = base.includes('.') ? base.split('.')[1].length : 0;
|
|
120
|
+
const exp = parseInt(exponent);
|
|
121
|
+
return Math.max(0, baseDecimalLength - exp);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const decimalPart = numStr.split('.')[1];
|
|
125
|
+
return decimalPart ? decimalPart.length : 0;
|
|
126
|
+
};
|
|
127
|
+
|
|
51
128
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
129
|
+
const decimalLen1 = getDecimalLength(str1);
|
|
130
|
+
const decimalLen2 = getDecimalLength(str2);
|
|
131
|
+
const totalDecimalLen = decimalLen1 + decimalLen2;
|
|
132
|
+
|
|
133
|
+
// 转换为整数相乘
|
|
134
|
+
const int1 = parseInt(str1.replace('.', '').replace(/e[+-]?\d+/i, ''));
|
|
135
|
+
const int2 = parseInt(str2.replace('.', '').replace(/e[+-]?\d+/i, ''));
|
|
136
|
+
|
|
137
|
+
// 处理指数
|
|
138
|
+
const getExponent = (numStr) => {
|
|
139
|
+
if (numStr.includes('e')) {
|
|
140
|
+
return parseInt(numStr.toLowerCase().split('e')[1]);
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const exponent = getExponent(str1) + getExponent(str2);
|
|
146
|
+
|
|
147
|
+
// 计算结果
|
|
148
|
+
let result = int1 * int2;
|
|
149
|
+
|
|
150
|
+
// 应用小数位数
|
|
151
|
+
if (totalDecimalLen > 0) {
|
|
152
|
+
result /= Math.pow(10, totalDecimalLen);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 应用指数
|
|
156
|
+
if (exponent !== 0) {
|
|
157
|
+
result *= Math.pow(10, exponent);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 处理可能的精度误差
|
|
161
|
+
return parseFloat(result.toFixed(Math.min(15, totalDecimalLen)));
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error('accMul 计算错误:', error);
|
|
164
|
+
// 降级处理
|
|
165
|
+
return parseFloat((num1 * num2).toFixed(12));
|
|
56
166
|
}
|
|
57
|
-
m = Math.pow(10, Math.max(r1, r2));
|
|
58
|
-
return accDiv((accMul(arg1, m) + accMul(arg2, m)), m);
|
|
59
167
|
}
|
|
60
168
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
169
|
+
/**
|
|
170
|
+
* 高精度除法
|
|
171
|
+
* @param {number|string} arg1 - 被除数
|
|
172
|
+
* @param {number|string} arg2 - 除数
|
|
173
|
+
* @returns {number} 计算结果
|
|
174
|
+
* @throws {Error} 除数为0时抛出错误
|
|
175
|
+
*/
|
|
176
|
+
export function accDiv(arg1, arg2) {
|
|
177
|
+
// 参数校验
|
|
178
|
+
if (arg1 == null || arg2 == null) {
|
|
179
|
+
console.warn('accDiv: 参数不能为null或undefined');
|
|
180
|
+
return NaN;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const num1 = Number(arg1);
|
|
184
|
+
const num2 = Number(arg2);
|
|
185
|
+
|
|
186
|
+
if (isNaN(num1) || isNaN(num2)) {
|
|
187
|
+
console.warn(`accDiv: 参数无效,arg1=${arg1}, arg2=${arg2}`);
|
|
188
|
+
return NaN;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 检查除数是否为0
|
|
192
|
+
if (num2 === 0) {
|
|
193
|
+
console.error('accDiv: 除数不能为0');
|
|
194
|
+
return Infinity * Math.sign(num1);
|
|
69
195
|
}
|
|
196
|
+
|
|
197
|
+
// 处理科学计数法
|
|
198
|
+
const str1 = num1.toString();
|
|
199
|
+
const str2 = num2.toString();
|
|
200
|
+
|
|
201
|
+
const getDecimalLength = (numStr) => {
|
|
202
|
+
if (numStr.includes('e') || numStr.includes('E')) {
|
|
203
|
+
const [base, exponent] = numStr.toLowerCase().split('e');
|
|
204
|
+
const baseDecimalLength = base.includes('.') ? base.split('.')[1].length : 0;
|
|
205
|
+
const exp = parseInt(exponent);
|
|
206
|
+
return Math.max(0, baseDecimalLength - exp);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const decimalPart = numStr.split('.')[1];
|
|
210
|
+
return decimalPart ? decimalPart.length : 0;
|
|
211
|
+
};
|
|
212
|
+
|
|
70
213
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
214
|
+
const decimalLen1 = getDecimalLength(str1);
|
|
215
|
+
const decimalLen2 = getDecimalLength(str2);
|
|
216
|
+
const maxDecimalLen = Math.max(decimalLen1, decimalLen2);
|
|
217
|
+
|
|
218
|
+
// 转换为整数相除
|
|
219
|
+
const int1 = parseInt(str1.replace('.', '').replace(/e[+-]?\d+/i, ''));
|
|
220
|
+
const int2 = parseInt(str2.replace('.', '').replace(/e[+-]?\d+/i, ''));
|
|
221
|
+
|
|
222
|
+
// 调整小数位数差异
|
|
223
|
+
const adjustFactor = Math.pow(10, Math.abs(decimalLen1 - decimalLen2));
|
|
224
|
+
|
|
225
|
+
let result;
|
|
226
|
+
if (decimalLen1 >= decimalLen2) {
|
|
227
|
+
result = int1 / (int2 * adjustFactor);
|
|
228
|
+
} else {
|
|
229
|
+
result = (int1 * adjustFactor) / int2;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// 处理指数
|
|
233
|
+
const getExponent = (numStr) => {
|
|
234
|
+
if (numStr.includes('e')) {
|
|
235
|
+
return parseInt(numStr.toLowerCase().split('e')[1]);
|
|
236
|
+
}
|
|
237
|
+
return 0;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const exponent = getExponent(str1) - getExponent(str2);
|
|
241
|
+
if (exponent !== 0) {
|
|
242
|
+
result *= Math.pow(10, exponent);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 处理可能的精度误差
|
|
246
|
+
return parseFloat(result.toFixed(Math.min(15, maxDecimalLen + 4)));
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error('accDiv 计算错误:', error);
|
|
249
|
+
// 降级处理
|
|
250
|
+
return parseFloat((num1 / num2).toFixed(12));
|
|
75
251
|
}
|
|
76
|
-
m = Math.pow(10, Math.max(r1, r2));
|
|
77
|
-
return accDiv((accMul(arg1, m) - accMul(arg2, m)), m);
|
|
78
252
|
}
|