lambo-design-bi 0.0.187 → 0.0.188
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 +98 -76
- package/package.json +1 -1
- package/pub/charts/factory/options.js +283 -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,9 +3,13 @@
|
|
|
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"
|
|
7
|
-
@on-data-load="onDataLoad" :searchParams="tableSearchParams">
|
|
6
|
+
:isSingleSelectModel="true" @on-data-load="onDataLoad" :searchParams="tableSearchParams">
|
|
8
7
|
<div slot="search"></div>
|
|
8
|
+
<div slot="footer">
|
|
9
|
+
<Table class="ivu-table-summary" v-if="widget.options.isAllSum && allSumData && allSumData.length > 0"
|
|
10
|
+
cellspacing="0" cellpadding="0" :columns="sumColumns" :data="allSumData" :border="true" :show-header="false">
|
|
11
|
+
</Table>
|
|
12
|
+
</div>
|
|
9
13
|
</LamboPagingTableBi>
|
|
10
14
|
</div>
|
|
11
15
|
</template>
|
|
@@ -13,6 +17,7 @@
|
|
|
13
17
|
import biConfig from '../config/config'
|
|
14
18
|
import { getListMapData } from '../api/data'
|
|
15
19
|
import LamboPagingTableBi from '../../../pub/table/paging-table/index.vue'
|
|
20
|
+
import { accAdd } from '../../../util/math-util'
|
|
16
21
|
|
|
17
22
|
export default {
|
|
18
23
|
name: 'BiPagingTable',
|
|
@@ -31,7 +36,8 @@ export default {
|
|
|
31
36
|
return {
|
|
32
37
|
tableSearchParams: {
|
|
33
38
|
inJson: ''
|
|
34
|
-
}
|
|
39
|
+
},
|
|
40
|
+
allSumData: [],
|
|
35
41
|
}
|
|
36
42
|
},
|
|
37
43
|
methods: {
|
|
@@ -51,84 +57,82 @@ export default {
|
|
|
51
57
|
query: newQuery
|
|
52
58
|
})
|
|
53
59
|
},
|
|
54
|
-
onDataLoad() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
sumRows[
|
|
60
|
+
onDataLoad(res) {
|
|
61
|
+
console.log("onDataLoad res:", res)
|
|
62
|
+
console.log("onDataLoad this.$refs.table.tableData:", this.$refs.table.tableData)
|
|
63
|
+
if (this.widget.options.isAllSum === '1') {
|
|
64
|
+
if (this.widget.options.isPaging === '1' && this.widget.options.sumApiId) {
|
|
65
|
+
// 请求后端做合计
|
|
66
|
+
getListMapData(this.widget.options.sumApiId, this.params).then(res => {
|
|
67
|
+
if (res && res.data.code === 1) {
|
|
68
|
+
if (res.data.data.rows.length > 0) {
|
|
69
|
+
let sumRows = res.data.data.rows[0]
|
|
70
|
+
let bakSumColumns = this.sumColumns
|
|
71
|
+
console.log("onDataLoad this.sumColumns:", this.sumColumns)
|
|
72
|
+
if (bakSumColumns && bakSumColumns.length > 0) {
|
|
73
|
+
sumRows[bakSumColumns[0].key] = '总计'
|
|
68
74
|
}
|
|
75
|
+
this.allSumData = [sumRows]
|
|
76
|
+
console.log("onDataLoad this.allSumData:", this.allSumData)
|
|
69
77
|
}
|
|
70
|
-
|
|
71
|
-
this
|
|
72
|
-
|
|
78
|
+
} else {
|
|
79
|
+
console.error("调用总计服务[" + this.widget.options.sumApiId + "]失败:" + res.data.message)
|
|
80
|
+
}
|
|
81
|
+
}).catch(err => {
|
|
82
|
+
console.error("调用总计服务[" + this.widget.options.sumApiId + "]异常:", err)
|
|
83
|
+
})
|
|
84
|
+
} else {
|
|
85
|
+
if (this.$refs.table.tableData && this.$refs.table.tableData.length > 0) {
|
|
86
|
+
// 前端遍历求和
|
|
87
|
+
let sumObj = {}
|
|
88
|
+
let bakSumColumns = this.getLeafNodes(this.sumColumns)
|
|
89
|
+
let tableData = this.$refs.table.tableData
|
|
90
|
+
console.log("onDataLoad bakSumColumns:", bakSumColumns)
|
|
91
|
+
if (bakSumColumns && bakSumColumns.length > 0 && tableData && tableData.length > 0) {
|
|
92
|
+
bakSumColumns.forEach((column, index) => {
|
|
93
|
+
const key = column.key
|
|
94
|
+
if (index === 0) {
|
|
95
|
+
sumObj[key] = "总计"
|
|
96
|
+
} else {
|
|
97
|
+
const values = tableData.map(item => Number(item[key]))
|
|
98
|
+
console.log("onDataLoad values:", values)
|
|
99
|
+
if (!values.every(value => isNaN(value))) {
|
|
100
|
+
const v = values.reduce((prev, curr) => {
|
|
101
|
+
const value = Number(curr)
|
|
102
|
+
if (!isNaN(value)) {
|
|
103
|
+
return accAdd(prev, curr)
|
|
104
|
+
} else {
|
|
105
|
+
return prev
|
|
106
|
+
}
|
|
107
|
+
}, 0)
|
|
108
|
+
sumObj[key] = v
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
if (sumObj) {
|
|
114
|
+
this.allSumData = [sumObj]
|
|
73
115
|
}
|
|
116
|
+
console.log("onDataLoad this.allSumData:", this.allSumData)
|
|
74
117
|
}
|
|
75
|
-
}
|
|
76
|
-
console.error("调用总计服务[" + this.widget.options.sumApiId + "]异常:", err)
|
|
77
|
-
})
|
|
118
|
+
}
|
|
78
119
|
}
|
|
79
120
|
},
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
columns.forEach((column, index) => {
|
|
88
|
-
const key = column.key;
|
|
89
|
-
const hasSum = column.hasSum;
|
|
90
|
-
if (hasSum === 'true') {
|
|
91
|
-
const values = tempData.map(item => Number(item[key]));
|
|
92
|
-
if (!values.every(value => isNaN(value))) {
|
|
93
|
-
const v = values.reduce((prev, curr) => {
|
|
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
|
-
};
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
if (key === 'index' || key === 'checkbox') {
|
|
113
|
-
sums[key] = {
|
|
114
|
-
key,
|
|
115
|
-
value: '合计'
|
|
116
|
-
};
|
|
117
|
-
} else if (index === 0) {
|
|
118
|
-
sums[key] = {
|
|
119
|
-
key,
|
|
120
|
-
value: '合计'
|
|
121
|
-
};
|
|
121
|
+
getLeafNodes(columns) {
|
|
122
|
+
const leafNodes = [];
|
|
123
|
+
function traverse(nodes) {
|
|
124
|
+
if (!Array.isArray(nodes)) return;
|
|
125
|
+
for (const node of nodes) {
|
|
126
|
+
if (!node.children || !Array.isArray(node.children) || node.children.length === 0) {
|
|
127
|
+
leafNodes.push(node);
|
|
122
128
|
} else {
|
|
123
|
-
|
|
124
|
-
key,
|
|
125
|
-
value: ''
|
|
126
|
-
};
|
|
129
|
+
traverse(node.children);
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
}
|
|
133
|
+
traverse(columns);
|
|
134
|
+
return leafNodes;
|
|
135
|
+
}
|
|
132
136
|
},
|
|
133
137
|
created() {
|
|
134
138
|
// eslint-disable-next-line
|
|
@@ -141,9 +145,7 @@ export default {
|
|
|
141
145
|
computed: {
|
|
142
146
|
columns() {
|
|
143
147
|
let columns = []
|
|
144
|
-
if (this.widget &&
|
|
145
|
-
Object.prototype.hasOwnProperty.call(this.widget, "options") &&
|
|
146
|
-
Object.prototype.hasOwnProperty.call(this.widget.options, "columns")) {
|
|
148
|
+
if (this.widget && Object.prototype.hasOwnProperty.call(this.widget, "options") && Object.prototype.hasOwnProperty.call(this.widget.options, "columns")) {
|
|
147
149
|
if (this.widget.options.columns) {
|
|
148
150
|
try {
|
|
149
151
|
columns = JSON.parse(this.widget.options.columns)
|
|
@@ -174,6 +176,26 @@ export default {
|
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
return columns
|
|
179
|
+
},
|
|
180
|
+
sumColumns() {
|
|
181
|
+
let sumColumnsStr = this.widget.options.columns
|
|
182
|
+
let sumColumns = []
|
|
183
|
+
if (this.widget && Object.prototype.hasOwnProperty.call(this.widget, "options") && Object.prototype.hasOwnProperty.call(this.widget.options, "columns")) {
|
|
184
|
+
if (this.widget.options.columns) {
|
|
185
|
+
try {
|
|
186
|
+
sumColumns = JSON.parse(sumColumnsStr)
|
|
187
|
+
if (sumColumns && sumColumns.length > 0) {
|
|
188
|
+
sumColumns[0].type = '-'
|
|
189
|
+
}
|
|
190
|
+
} catch (e) {
|
|
191
|
+
console.log("BiPagingTable -- sumColumns() -- this.widget.options.columns:", this.widget.options.columns)
|
|
192
|
+
console.error("BiPagingTable -- sumColumns() JSON解析异常:", e)
|
|
193
|
+
this.$Message.info("合计的表格头配置数据解析异常")
|
|
194
|
+
sumColumns = []
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return sumColumns
|
|
177
199
|
}
|
|
178
200
|
},
|
|
179
201
|
watch: {
|
|
@@ -183,7 +205,7 @@ export default {
|
|
|
183
205
|
this.doSearch()
|
|
184
206
|
},
|
|
185
207
|
deep: true
|
|
186
|
-
}
|
|
208
|
+
}
|
|
187
209
|
}
|
|
188
210
|
}
|
|
189
211
|
</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,283 @@ export function getECharts(type, dataX, dataY, dataDim) {
|
|
|
2590
2593
|
series: series
|
|
2591
2594
|
};
|
|
2592
2595
|
}
|
|
2596
|
+
else if (type === '44') {
|
|
2597
|
+
const indicators = dataX.map((name, index) => {
|
|
2598
|
+
let maxValue = 0;
|
|
2599
|
+
for (let i = 0; i < dataY.length; i++) {
|
|
2600
|
+
if (dataY[i] && dataY[i][index] > maxValue) {
|
|
2601
|
+
maxValue = dataY[i][index];
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
return {
|
|
2605
|
+
name: name,
|
|
2606
|
+
max: Math.ceil(maxValue * 1.2)
|
|
2607
|
+
};
|
|
2608
|
+
});
|
|
2609
|
+
|
|
2610
|
+
const seriesData = [];
|
|
2611
|
+
|
|
2612
|
+
dataY.forEach((data, index) => {
|
|
2613
|
+
seriesData.push({
|
|
2614
|
+
name: dataDim[index],
|
|
2615
|
+
value: data,
|
|
2616
|
+
lineStyle: {
|
|
2617
|
+
width: 3,
|
|
2618
|
+
color: colors[index % colors.length]
|
|
2619
|
+
},
|
|
2620
|
+
itemStyle: {
|
|
2621
|
+
color: colors[index % colors.length]
|
|
2622
|
+
},
|
|
2623
|
+
areaStyle: {
|
|
2624
|
+
color: areaColors[index % areaColors.length]
|
|
2625
|
+
}
|
|
2626
|
+
});
|
|
2627
|
+
});
|
|
2628
|
+
opt = {
|
|
2629
|
+
legend: {
|
|
2630
|
+
data: seriesData.map(item => item.name),
|
|
2631
|
+
bottom:0,
|
|
2632
|
+
textStyle: {
|
|
2633
|
+
fontSize: 12
|
|
2634
|
+
}
|
|
2635
|
+
},
|
|
2636
|
+
tooltip: {},
|
|
2637
|
+
radar: {
|
|
2638
|
+
center: ['50%', '45%'],
|
|
2639
|
+
radius: '70%',
|
|
2640
|
+
indicator: indicators,
|
|
2641
|
+
name: {
|
|
2642
|
+
textStyle: {
|
|
2643
|
+
color: '#666',
|
|
2644
|
+
fontSize: 14,
|
|
2645
|
+
fontWeight: 'bold'
|
|
2646
|
+
}
|
|
2647
|
+
},
|
|
2648
|
+
axisLine: {
|
|
2649
|
+
lineStyle: {
|
|
2650
|
+
color: '#ddd'
|
|
2651
|
+
}
|
|
2652
|
+
},
|
|
2653
|
+
splitLine: {
|
|
2654
|
+
lineStyle: {
|
|
2655
|
+
color: '#eee'
|
|
2656
|
+
}
|
|
2657
|
+
},
|
|
2658
|
+
splitArea: {
|
|
2659
|
+
show: true,
|
|
2660
|
+
areaStyle: {
|
|
2661
|
+
color: ['rgba(250,250,250,0.8)', 'rgba(240,240,240,0.8)']
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
},
|
|
2665
|
+
series: [{
|
|
2666
|
+
type: 'radar',
|
|
2667
|
+
data: seriesData,
|
|
2668
|
+
symbol: 'circle',
|
|
2669
|
+
symbolSize: 6,
|
|
2670
|
+
lineStyle: {
|
|
2671
|
+
type: 'solid'
|
|
2672
|
+
}
|
|
2673
|
+
}],
|
|
2674
|
+
animation: true,
|
|
2675
|
+
animationDuration: 1000
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
else if (type === '45') {
|
|
2679
|
+
const progressValue = dataY[0] && dataY[0][0] ? dataY[0][0] : 0;
|
|
2680
|
+
const maxValue = 100;
|
|
2681
|
+
|
|
2682
|
+
const colorIndex = dataY[0] && dataY[0][1] ? dataY[0][1] % colors.length : 0;
|
|
2683
|
+
const baseColor = colors[colorIndex];
|
|
2684
|
+
const lightColor = hexToRgba(baseColor, 0.6);
|
|
2685
|
+
|
|
2686
|
+
const progressGradient = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
2687
|
+
{ offset: 0, color: baseColor },
|
|
2688
|
+
{ offset: 0.5, color: lightColor },
|
|
2689
|
+
{ offset: 1, color: hexToRgba(baseColor, 0.3) }
|
|
2690
|
+
]);
|
|
2691
|
+
|
|
2692
|
+
const bgColorIndex = (colorIndex + 1) % colors.length;
|
|
2693
|
+
const bgColor = colors[bgColorIndex];
|
|
2694
|
+
const bgColorTransparent = hexToRgba(bgColor, 0);
|
|
2695
|
+
const bgColorSolid = hexToRgba(bgColor, 0.4);
|
|
2696
|
+
|
|
2697
|
+
opt = {
|
|
2698
|
+
title: [
|
|
2699
|
+
{
|
|
2700
|
+
text: dataDim[0] || '',
|
|
2701
|
+
x: 'center',
|
|
2702
|
+
top: '32%',
|
|
2703
|
+
textStyle: {
|
|
2704
|
+
fontSize: 26,
|
|
2705
|
+
fontFamily: 'Microsoft YaHei',
|
|
2706
|
+
fontWeight: '400',
|
|
2707
|
+
color: '#777',
|
|
2708
|
+
textShadow: '0 1px 2px rgba(0,0,0,0.05)'
|
|
2709
|
+
},
|
|
2710
|
+
},
|
|
2711
|
+
{
|
|
2712
|
+
text: `${progressValue}%`,
|
|
2713
|
+
x: 'center',
|
|
2714
|
+
top: '50%',
|
|
2715
|
+
textStyle: {
|
|
2716
|
+
fontSize: 52,
|
|
2717
|
+
color: baseColor,
|
|
2718
|
+
fontWeight: '500',
|
|
2719
|
+
fontFamily: 'Microsoft YaHei',
|
|
2720
|
+
textShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
|
2721
|
+
},
|
|
2722
|
+
},
|
|
2723
|
+
],
|
|
2724
|
+
polar: {
|
|
2725
|
+
radius: ['44%', '50%'],
|
|
2726
|
+
center: ['50%', '50%'],
|
|
2727
|
+
},
|
|
2728
|
+
angleAxis: {
|
|
2729
|
+
max: maxValue,
|
|
2730
|
+
show: false,
|
|
2731
|
+
},
|
|
2732
|
+
radiusAxis: {
|
|
2733
|
+
type: 'category',
|
|
2734
|
+
show: true,
|
|
2735
|
+
axisLabel: {
|
|
2736
|
+
show: false,
|
|
2737
|
+
},
|
|
2738
|
+
axisLine: {
|
|
2739
|
+
show: false,
|
|
2740
|
+
},
|
|
2741
|
+
axisTick: {
|
|
2742
|
+
show: false,
|
|
2743
|
+
},
|
|
2744
|
+
},
|
|
2745
|
+
series: [
|
|
2746
|
+
{
|
|
2747
|
+
type: 'pie',
|
|
2748
|
+
startAngle: 90,
|
|
2749
|
+
radius: ['83%', '90%'],
|
|
2750
|
+
center: ['50%', '50%'],
|
|
2751
|
+
hoverAnimation: true,
|
|
2752
|
+
animationType: 'scale',
|
|
2753
|
+
animationEasing: 'cubicOut',
|
|
2754
|
+
itemStyle: {
|
|
2755
|
+
borderRadius: 10,
|
|
2756
|
+
borderWidth: 0,
|
|
2757
|
+
shadowColor: hexToRgba(baseColor, 0.3),
|
|
2758
|
+
shadowBlur: 10,
|
|
2759
|
+
shadowOffsetY: 2
|
|
2760
|
+
},
|
|
2761
|
+
data: [
|
|
2762
|
+
{
|
|
2763
|
+
hoverOffset: 5,
|
|
2764
|
+
value: progressValue,
|
|
2765
|
+
name: '',
|
|
2766
|
+
itemStyle: {
|
|
2767
|
+
color: progressGradient,
|
|
2768
|
+
borderWidth: 0,
|
|
2769
|
+
borderColor: hexToRgba(baseColor, 0.8),
|
|
2770
|
+
},
|
|
2771
|
+
label: {
|
|
2772
|
+
show: false,
|
|
2773
|
+
},
|
|
2774
|
+
labelLine: {
|
|
2775
|
+
lineStyle: {
|
|
2776
|
+
width: 0,
|
|
2777
|
+
},
|
|
2778
|
+
},
|
|
2779
|
+
emphasis: {
|
|
2780
|
+
itemStyle: {
|
|
2781
|
+
shadowColor: hexToRgba(baseColor, 0.5),
|
|
2782
|
+
shadowBlur: 15,
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
label: {
|
|
2788
|
+
show: false,
|
|
2789
|
+
},
|
|
2790
|
+
labelLine: {
|
|
2791
|
+
lineStyle: {
|
|
2792
|
+
width: 0,
|
|
2793
|
+
},
|
|
2794
|
+
},
|
|
2795
|
+
value: maxValue - progressValue,
|
|
2796
|
+
itemStyle: {
|
|
2797
|
+
color: 'rgba(200, 200, 200, 0.1)',
|
|
2798
|
+
borderWidth: 0,
|
|
2799
|
+
},
|
|
2800
|
+
},
|
|
2801
|
+
],
|
|
2802
|
+
},
|
|
2803
|
+
{
|
|
2804
|
+
name: '',
|
|
2805
|
+
type: 'pie',
|
|
2806
|
+
startAngle: 90,
|
|
2807
|
+
radius: ['78%', '82%'],
|
|
2808
|
+
hoverAnimation: false,
|
|
2809
|
+
center: ['50%', '50%'],
|
|
2810
|
+
itemStyle: {
|
|
2811
|
+
color: new echarts.graphic.RadialGradient(0.5, 0.5, 0.7, [
|
|
2812
|
+
{
|
|
2813
|
+
offset: 0,
|
|
2814
|
+
color: bgColorSolid,
|
|
2815
|
+
},
|
|
2816
|
+
{
|
|
2817
|
+
offset: 0.8,
|
|
2818
|
+
color: hexToRgba(bgColor, 0.2),
|
|
2819
|
+
},
|
|
2820
|
+
{
|
|
2821
|
+
offset: 1,
|
|
2822
|
+
color: bgColorTransparent,
|
|
2823
|
+
},
|
|
2824
|
+
]),
|
|
2825
|
+
borderWidth: 0,
|
|
2826
|
+
shadowBlur: 8,
|
|
2827
|
+
shadowColor: hexToRgba(bgColor, 0.15),
|
|
2828
|
+
},
|
|
2829
|
+
data: [
|
|
2830
|
+
{
|
|
2831
|
+
value: maxValue,
|
|
2832
|
+
itemStyle: {
|
|
2833
|
+
borderWidth: 0,
|
|
2834
|
+
}
|
|
2835
|
+
},
|
|
2836
|
+
],
|
|
2837
|
+
label: {
|
|
2838
|
+
show: false
|
|
2839
|
+
},
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
name: '',
|
|
2843
|
+
type: 'pie',
|
|
2844
|
+
radius: '70%',
|
|
2845
|
+
center: ['50%', '50%'],
|
|
2846
|
+
startAngle: 90,
|
|
2847
|
+
hoverAnimation: false,
|
|
2848
|
+
silent: true,
|
|
2849
|
+
itemStyle: {
|
|
2850
|
+
color: new echarts.graphic.RadialGradient(0.5, 0.5, 0.5, [
|
|
2851
|
+
{ offset: 0, color: hexToRgba(baseColor, 0.08) },
|
|
2852
|
+
{ offset: 0.7, color: hexToRgba(baseColor, 0.03) },
|
|
2853
|
+
{ offset: 1, color: hexToRgba(baseColor, 0) }
|
|
2854
|
+
]),
|
|
2855
|
+
borderWidth: 0,
|
|
2856
|
+
},
|
|
2857
|
+
label: {
|
|
2858
|
+
show: false
|
|
2859
|
+
},
|
|
2860
|
+
data: [{
|
|
2861
|
+
value: 100,
|
|
2862
|
+
itemStyle: {
|
|
2863
|
+
borderWidth: 0
|
|
2864
|
+
}
|
|
2865
|
+
}]
|
|
2866
|
+
}
|
|
2867
|
+
],
|
|
2868
|
+
animation: true,
|
|
2869
|
+
animationDuration: 1000,
|
|
2870
|
+
animationEasing: 'cubicOut'
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2593
2873
|
return opt
|
|
2594
2874
|
}
|
|
2595
2875
|
|
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
|
}
|