Browse Source

feat: 折线数据增加系数运算

main
betaqi 2 months ago
parent
commit
8895c1cc04
  1. 28
      package-lock.json
  2. 2
      package.json
  3. 197
      src/views/stationData/component/line-dlg.vue
  4. 69
      src/views/stationData/component/newDataChart.vue
  5. 26
      src/views/stationData/topology/components/detailDrawer.vue
  6. 61
      src/views/stationData/transfer/components/deviceDrawer.vue

28
package-lock.json generated

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
"@types/qs": "^6.9.18",
"@unocss/reset": "^66.0.0",
"axios": "^1.8.4",
"big.js": "^7.0.1",
"dayjs": "^1.11.13",
"dexie": "^4.0.11",
"echarts": "^5.6.0",
@ -32,6 +33,7 @@ @@ -32,6 +33,7 @@
"devDependencies": {
"@iconify/json": "^2.2.310",
"@tsconfig/node22": "^22.0.0",
"@types/big.js": "^6.2.2",
"@types/node": "^24.2.1",
"@unocss/preset-icons": "^66.0.0",
"@unocss/preset-rem-to-px": "^66.0.0",
@ -2211,6 +2213,13 @@ @@ -2211,6 +2213,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/big.js": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.2.2.tgz",
"integrity": "sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-array": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
@ -3680,12 +3689,16 @@ @@ -3680,12 +3689,16 @@
"license": "MIT"
},
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-7.0.1.tgz",
"integrity": "sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==",
"license": "MIT",
"engines": {
"node": "*"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bigjs"
}
},
"node_modules/binary-extensions": {
@ -5724,6 +5737,15 @@ @@ -5724,6 +5737,15 @@
"node": ">=8.9.0"
}
},
"node_modules/loader-utils/node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/local-pkg": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz",

2
package.json

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
"@types/qs": "^6.9.18",
"@unocss/reset": "^66.0.0",
"axios": "^1.8.4",
"big.js": "^7.0.1",
"dayjs": "^1.11.13",
"dexie": "^4.0.11",
"echarts": "^5.6.0",
@ -38,6 +39,7 @@ @@ -38,6 +39,7 @@
"devDependencies": {
"@iconify/json": "^2.2.310",
"@tsconfig/node22": "^22.0.0",
"@types/big.js": "^6.2.2",
"@types/node": "^24.2.1",
"@unocss/preset-icons": "^66.0.0",
"@unocss/preset-rem-to-px": "^66.0.0",

197
src/views/stationData/component/line-dlg.vue

@ -0,0 +1,197 @@ @@ -0,0 +1,197 @@
<template>
<EdfsDialog
class="plf-strategy-dlg"
:title="title"
:isShow="visibility"
width="20%"
@on-close="onClone"
@on-save="onSave"
>
<div class="dlg-body">
<el-row>
<div class="label">设置系数</div>
<div class="box">
<div
class="operator-btn"
:class="{ active: formData.operator === '/' }"
@click="formData.operator = '/'"
>
</div>
<div class="custom-stepper">
<div class="stepper-btn minus" @click="decrease">-</div>
<div class="stepper-input">{{ formData.coefficient }}</div>
<div class="stepper-btn plus" @click="increase">+</div>
</div>
<div
class="operator-btn"
:class="{ active: formData.operator === '*' }"
@click="formData.operator = '*'"
>
</div>
</div>
</el-row>
</div>
</EdfsDialog>
</template>
<script setup lang="ts">
import { cloneDeep } from 'lodash'
import EdfsDialog from '@/components/Edfs-dialog.vue'
const emits = defineEmits(['on-save', 'on-close'])
const title = ref()
const createObj = {
id: '',
coefficient: 1,
operator: '*',
}
const formData = ref(cloneDeep(createObj)) as any
function onClone() {
formData.value = cloneDeep(createObj)
visibility.value = false
emits('on-close')
}
async function onSave() {
emits('on-save', cloneDeep(formData.value))
onClone()
}
const visibility = ref(false)
function open(titleStr: string, id: string, coefficient: string, operator: string) {
title.value = titleStr
formData.value.id = id
if (coefficient) {
formData.value.coefficient = Number(coefficient)
}
if (operator) {
formData.value.operator = operator
}
visibility.value = true
}
const ALLOWED_VALUES = [1, 10, 100, 1000]
function decrease() {
const currentIndex = ALLOWED_VALUES.indexOf(formData.value.coefficient)
if (currentIndex > 0) {
formData.value.coefficient = ALLOWED_VALUES[currentIndex - 1]
}
}
function increase() {
const currentIndex = ALLOWED_VALUES.indexOf(formData.value.coefficient)
if (currentIndex < ALLOWED_VALUES.length - 1) {
formData.value.coefficient = ALLOWED_VALUES[currentIndex + 1]
} else if (currentIndex === -1) {
formData.value.coefficient = 1
}
}
defineExpose({
open,
})
</script>
<style scoped lang="scss">
.plf-strategy-dlg {
.dlg-body {
}
.el-row {
height: 32px;
margin-bottom: 20px;
:deep(.label) {
margin-right: 10px;
line-height: 32px;
width: 100px;
text-align: right;
}
span {
margin-right: 10px;
width: 110px;
height: 32px;
line-height: 32px;
text-align: right;
}
:deep(.el-radio-group) {
height: 100%;
}
:deep(.el-radio) {
height: 100%;
}
}
.box {
display: flex;
gap: 10px;
}
.operator-btn {
width: 40px;
height: 32px;
line-height: 32px;
text-align: center;
border: 1px solid var(--el-border-color);
cursor: pointer;
border-radius: var(--el-border-radius-base);
color: var(--el-text-color-regular);
background-color: var(--el-bg-color);
&.active {
background-color: var(--el-color-primary);
color: var(--el-color-white);
border-color: var(--el-color-primary);
}
&:hover:not(.active) {
color: var(--el-color-primary);
border-color: var(--el-color-primary-light-7);
background-color: var(--el-color-primary-light-9);
}
}
.mx-2 {
margin: 0 10px;
}
.custom-stepper {
display: flex;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
height: 32px;
overflow: hidden;
background-color: var(--el-bg-color);
.stepper-btn {
width: 32px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--el-fill-color-light);
cursor: pointer;
user-select: none;
color: var(--el-text-color-regular);
transition: all 0.3s;
&:hover {
color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9);
}
&.minus {
border-right: 1px solid var(--el-border-color);
}
&.plus {
border-left: 1px solid var(--el-border-color);
}
}
.stepper-input {
flex: 1;
min-width: 50px;
text-align: center;
line-height: 30px;
font-size: 14px;
color: var(--el-text-color-regular);
background-color: var(--el-bg-color);
}
}
}
</style>

69
src/views/stationData/component/newDataChart.vue

@ -7,22 +7,26 @@ @@ -7,22 +7,26 @@
:autoresize="autoresize"
:loading-options="loadingOpt"
:loading="loading"
/>
@click="onChartClick"
/>
</div>
<LineChartDlg ref="LineChartDlgRef" @on-save="onChangeCoefficient"/>
</template>
<script setup lang="ts">
import Big from 'big.js'
import dayjs from 'dayjs'
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import type { EChartsOption, SeriesOption } from 'echarts/types/dist/shared.js'
import { LineChart } from 'echarts/charts'
import LineChartDlg from './line-dlg.vue'
import {
TooltipComponent,
LegendComponent,
DataZoomComponent,
GridComponent,
LegendComponent,
TooltipComponent,
} from 'echarts/components'
use([
@ -35,17 +39,37 @@ use([ @@ -35,17 +39,37 @@ use([
])
const ZOOM_HEIGHT = 30
const ZOOM_BOTTOM = 10
const emits = defineEmits(['on-change-coefficient'])
type Legend = {
addr: string
label: string
unit?: string
coefficient?: string | number
operator?: string
}
const autoresize = {
throttle: 0,
}
const LineChartDlgRef = ref()
function onChangeCoefficient(data: { id: string; coefficient: string; operator: string }) {
emits('on-change-coefficient', data)
}
const onChartClick = (params: any) => {
// 线
const [seriesName, id] = params?.seriesName?.split('|')
if (params.componentType === 'series' && params.seriesType === 'line' && seriesName && id) {
const find = props.legends.find(item => item.addr === id) as any
if (find) {
LineChartDlgRef.value?.open(seriesName, id, find?.coefficient, find?.operator)
}
}
}
const props = defineProps({
title: String,
smooth: Boolean, //线
@ -82,14 +106,25 @@ const chartOption = computed<EChartsOption>(() => { @@ -82,14 +106,25 @@ const chartOption = computed<EChartsOption>(() => {
loading.value = false
const tmpSeries: SeriesOption[] = []
for (const legend of props.legends.filter(item => item.addr !== 'ts')) {
const entry = props.chartDatas.get(legend.addr) as Array<any>
const entry = props.chartDatas.get(legend.addr) ?? []
const lineData: SeriesOption = {
name: legend.label,
name: `${legend.label}|${legend.addr}`,
type: 'line',
id: legend.addr,
// symbol: "none",
connectNulls: true,
data: entry,
triggerLineEvent: true,
data: entry.map(([ts, val]) => {
const coef = legend?.coefficient ? new Big(legend.coefficient) : new Big(1)
const operator = legend?.operator || '*'
let valBig = new Big(val)
if (operator === '/') {
valBig = valBig.div(coef)
} else {
valBig = valBig.times(coef)
}
return [ts, valBig.toNumber()]
}),
sampling: 'lttb',
animation: false,
}
@ -126,10 +161,13 @@ const chartOption = computed<EChartsOption>(() => { @@ -126,10 +161,13 @@ const chartOption = computed<EChartsOption>(() => {
let relVal = timeStr
for (let i = 0; i < params.length; i++) {
const unit = props.legends.find(item => item.addr === params[i].seriesId)?.unit || ''
relVal += `<div style="display: flex; justify-content: space-between; gap: 30px;">
const data = props.legends.find(item => item.addr === params[i].seriesId)
const conefficients = data?.coefficient ?? undefined
const unit = data?.unit || ''
relVal += `<div style="display: flex; justify-content: space-between; gap: 30px;">
<div>${params[i].marker}${params[i].seriesName}:</div>
<div>${params[i].value[1]}${unit}</div>
<div>${params[i].value[1]}${conefficients ? `【系数为${conefficients}(${operatorMap[data?.operator] ?? ''
})` : ''}${unit}</div>
</div>`
}
return relVal
@ -139,17 +177,21 @@ const chartOption = computed<EChartsOption>(() => { @@ -139,17 +177,21 @@ const chartOption = computed<EChartsOption>(() => {
type: 'scroll',
orient: 'vertical',
formatter: name => {
return name.length > 15 ? name.substring(0, 15) + '...' : name
const nameStr = name.split('|')[0]
return nameStr.length > 15 ? nameStr.substring(0, 15) + '...' : nameStr
},
tooltip: {
show: true,
formatter: function (params) {
return params.name.split('|')[0]
},
},
right: 0,
top: 20,
itemWidth: 10,
itemHeight: 10,
pageIconSize: 12,
data: props.legends.map(item => item.label),
data: props.legends.map(item => `${item.label}|${item.addr}`),
// selected: unCheckArr.value.reduce((acc, cur) => {
// acc[cur] = false
// return acc
@ -220,6 +262,11 @@ const chartOption = computed<EChartsOption>(() => { @@ -220,6 +262,11 @@ const chartOption = computed<EChartsOption>(() => {
const unCheckArr = ref<string[]>([])
const operatorMap = {
'*': '×',
'/': '÷',
}
function changeLegend(data: { name: string; selected: Record<string, boolean> }) {
const { name, selected } = data
if (!selected[name]) {

26
src/views/stationData/topology/components/detailDrawer.vue

@ -79,7 +79,9 @@ @@ -79,7 +79,9 @@
:chart-datas="chartData"
:legends="legends"
:axis-data="Array.from(axisData)"
ref="chartRef"/>
ref="chartRef"
@onChangeCoefficient="onChangeCoefficient"
/>
</div>
</main>
</el-drawer>
@ -249,7 +251,27 @@ async function loadDeviceDetails() { @@ -249,7 +251,27 @@ async function loadDeviceDetails() {
const chartData = reactive(new Map<string, any[]>())
const axisData = new Set<string>()
const legends = ref<{ addr: string; label: string, unit: string }[]>([])
const legends = ref<{
addr: string; label: string, unit: string, coefficient?: string | number
operator?: string
}[]>([])
function onChangeCoefficient(
{
id,
coefficient,
operator,
}: {
id: string
coefficient: string
operator: string
}) {
const find = legends.value.findIndex(r => r.addr === id)
if (find !== -1) {
legends.value[find].coefficient = coefficient
legends.value[find].operator = operator
}
}
const loadingChart = ref(false)
const chartAllTotal = ref(0)

61
src/views/stationData/transfer/components/deviceDrawer.vue

@ -33,28 +33,28 @@ @@ -33,28 +33,28 @@
:key="deviceInfo.id"
class="space-y-3 text-center bg-white/95 backdrop-blur-sm p-6 rounded-xl shadow-lg border border-gray-100 hover:shadow-xl transition-shadow duration-200"
>
<div class="font-semibold text-gray-700 text-lg">
{{ chartGroupMap?.get(deviceInfo.id)?.cnName }} 数据加载中
</div>
<el-progress
:text-inside="true"
:stroke-width="20"
:percentage="deviceInfo.progress"
/>
<div class="text-gray-600 text-base">已查询
<span class="text-green-600 font-semibold">
<div class="font-semibold text-gray-700 text-lg">
{{ chartGroupMap?.get(deviceInfo.id)?.cnName }} 数据加载中
</div>
<el-progress
:text-inside="true"
:stroke-width="20"
:percentage="deviceInfo.progress"
/>
<div class="text-gray-600 text-base">已查询
<span class="text-green-600 font-semibold">
{{ deviceInfo.fetchLimit }}
</span>/<span class="text-blue-600 font-semibold">{{
deviceInfo.total
}}</span>剩余<span
class="text-red-500 font-semibold">{{
deviceInfo.total - deviceInfo.fetchLimit
}}</span>
deviceInfo.total
}}</span>剩余<span
class="text-red-500 font-semibold">{{
deviceInfo.total - deviceInfo.fetchLimit
}}</span>
</div>
</div>
</div>
</div>
</el-scrollbar>
</div>
</div>
@ -79,7 +79,8 @@ @@ -79,7 +79,8 @@
小时
</div>
<NewDataChart v-if="isShowChart" :chart-datas="chartData" :legends="legends"
:axis-data="Array.from(axisData)" ref="chartRef"/>
:axis-data="Array.from(axisData)" ref="chartRef"
@onChangeCoefficient="onChangeCoefficient"/>
</div>
</main>
</el-drawer>
@ -243,7 +244,10 @@ async function loadDeviceDetails() { @@ -243,7 +244,10 @@ async function loadDeviceDetails() {
const chartData = reactive(new Map<string, any[]>())
const axisData = new Set<string>()
const legends = ref<{ addr: string; label: string, unit: string }[]>([])
const legends = ref<{
addr: string; label: string, unit: string, coefficient?: string | number
operator?: string
}[]>([])
const loadingChart = ref(false)
const loading = ref(false)
@ -333,6 +337,23 @@ function setChartData2(groupName: string, data: any[]) { @@ -333,6 +337,23 @@ function setChartData2(groupName: string, data: any[]) {
})
}
function onChangeCoefficient(
{
id,
coefficient,
operator,
}: {
id: string
coefficient: string
operator: string
}) {
const find = legends.value.findIndex(r => r.addr === id)
if (find !== -1) {
legends.value[find].coefficient = coefficient
legends.value[find].operator = operator
}
}
function handleBeforeClose(done: () => void) {
ElMessageBox.confirm('你确定要关闭吗?')
.then(() => {

Loading…
Cancel
Save