Browse Source

feat: 一些调整

main
betaqi 1 week ago
parent
commit
aba07c78e9
  1. 127
      src/utils/useMessage.ts
  2. 7
      src/utils/zmq.ts
  3. 120
      src/views/stationData/component/newDataChart.vue
  4. 5
      src/views/stationData/index.vue
  5. 4
      src/views/stationData/topology/components/detailDrawer.vue
  6. 69
      src/views/stationData/transfer/components/deviceDrawer.vue
  7. 2
      src/views/stationData/transfer/index.vue

127
src/utils/useMessage.ts

@ -0,0 +1,127 @@ @@ -0,0 +1,127 @@
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
export const useMessage = () => {
return {
// 消息提示
info(content: string) {
ElMessage.info(content)
},
// 错误消息
error(content: string) {
ElMessage.error(content)
},
// 成功消息
success(content: string) {
ElMessage.success(content)
},
// 警告消息
warning(content: string) {
ElMessage.warning(content)
},
// 弹出提示
alert(content: string) {
ElMessageBox.alert(content, '系统提示')
},
// 错误提示
alertError(content: string) {
ElMessageBox.alert(content, '系统提示', { type: 'error' })
},
// 成功提示
alertSuccess(content: string) {
ElMessageBox.alert(content, '系统提示', { type: 'success' })
},
// 警告提示
alertWarning(content: string) {
ElMessageBox.alert(content, '系统提示', { type: 'warning' })
},
// 通知提示
notify(content: string) {
ElNotification.info(content)
},
// 错误通知
notifyError(content: string, tip?: string) {
ElNotification.error({
title: tip ? tip : '系统提示',
message: content,
})
},
// 成功通知
notifySuccess(content: string) {
ElNotification.success(content)
},
// 警告通知
notifyWarning(content: string) {
ElNotification.warning(content)
},
// 确认窗体
confirm(content: string, tip?: string) {
return ElMessageBox.confirm(content, tip ? tip : '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
},
forceConfirm(content: string, tip?: string, buttonText?: string) {
return ElMessageBox.confirm(content, tip ? tip : '系统提示', {
confirmButtonText: buttonText ?? '确定',
showCancelButton: false,
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
type: 'warning',
})
},
// 删除窗体
delConfirm(content?: string, tip?: string) {
return new Promise((resolve, reject) => {
ElMessageBox.confirm(
content ? content : '是否确认删除数据项?',
tip ? tip : '系统提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
resolve('')
})
.catch(() => {
reject('')
})
})
},
// 导出窗体
exportConfirm(content?: string, tip?: string) {
return ElMessageBox.confirm(
content ? content : '是否确认导出数据项?',
tip ? tip : '系统提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
},
// 提交内容
prompt(content: string, tip: string) {
return ElMessageBox.prompt(content, tip, {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
},
promptVerify(content: string, tip: string, pattern: string, inputErrorMessage = '') {
const PatternRegExp = new RegExp(
`^${pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}$`
)
return ElMessageBox.prompt(content, tip, {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: PatternRegExp,
inputErrorMessage: inputErrorMessage,
type: 'warning',
})
},
}
}

7
src/utils/zmq.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import { v4 as uuidv4 } from 'uuid';
export type ManualAction =
'init' | 'release' | 'write' | 'report' | 'lock' | 'unlock' |
'export' | 'cancel' | 'import' | 'upgrade'
@ -32,14 +33,15 @@ export interface TimeoutMsg { @@ -32,14 +33,15 @@ export interface TimeoutMsg {
timeoutId: string
timeoutTopic: string
}
export interface ZmqMessage {
cmd: ZmqCMD
msg: string
community: boolean
topic: string
}
type TopicType = 'event' | 'status'
type TopicType = 'event' | 'status'
// web端发布消息类型
@ -49,6 +51,7 @@ export interface PublishMsg<A> { @@ -49,6 +51,7 @@ export interface PublishMsg<A> {
reply: 'yes' | 'no' // 是否需要回复
params: any // 消息的参数
}
// web端发布消息服务端返回的数据类型
export interface PubMsgData {
code: number
@ -66,7 +69,6 @@ export interface SubMsgData { @@ -66,7 +69,6 @@ export interface SubMsgData {
}
/*
* @Description:
* type:
@ -130,6 +132,7 @@ export function getPubInitData<T extends ManualAction>(action: T, params: any, r @@ -130,6 +132,7 @@ export function getPubInitData<T extends ManualAction>(action: T, params: any, r
params
})
}
export function isHexadecimal(text: string) {
const hexRegex = /^[0-9A-Fa-f]+$/
return hexRegex.test(text)

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

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
:loading-options="loadingOpt"
:loading="loading"
@click="onChartClick"
@legendselectchanged="changeLegend"
/>
</div>
<LineChartDlg ref="LineChartDlgRef" @on-save="onChangeCoefficient" />
@ -41,6 +42,42 @@ const ZOOM_HEIGHT = 30 @@ -41,6 +42,42 @@ const ZOOM_HEIGHT = 30
const ZOOM_BOTTOM = 10
const emits = defineEmits(['on-change-coefficient'])
const EXTENDED_PALETTE = [
'#5470c6',
'#91cc75',
'#fac858',
'#ee6666',
'#73c0de',
'#3ba272',
'#fc8452',
'#9a60b4',
'#ea7ccc',
'#2f4554',
'#61a0a8',
'#d48265',
'#91c7ae',
'#749f83',
'#ca8622',
'#bda29a',
'#6e7074',
'#546570',
'#c4ccd3',
'#f05b72',
'#ef5b9c',
'#f47920',
'#905a3d',
'#fab27b',
'#2a5caa',
'#444693',
'#726930',
'#b2d235',
'#6d8346',
'#ac6767',
'#1d953f',
'#6950a1',
'#918597',
]
type Legend = {
addr: string
label: string
@ -109,8 +146,12 @@ const chartOption = computed<EChartsOption>(() => { @@ -109,8 +146,12 @@ const chartOption = computed<EChartsOption>(() => {
}
loading.value = false
const tmpSeries: SeriesOption[] = []
for (const legend of props.legends.filter(item => item.addr !== 'ts')) {
const legends = props.legends.filter(item => item.addr !== 'ts')
for (let i = 0; i < legends.length; i++) {
const legend = legends[i]
const entry = props.chartDatas.get(legend.addr) ?? []
const color = EXTENDED_PALETTE[i % EXTENDED_PALETTE.length]
const lineData: SeriesOption = {
name: `${legend.label}|${legend.addr}`,
type: 'line',
@ -118,7 +159,11 @@ const chartOption = computed<EChartsOption>(() => { @@ -118,7 +159,11 @@ const chartOption = computed<EChartsOption>(() => {
// symbol: "none",
connectNulls: true,
triggerLineEvent: true,
itemStyle: {
color: color,
},
data: entry.map(([ts, val]) => {
console.log(ts)
const coef = legend?.coefficient ? new Big(legend.coefficient) : new Big(1)
let valBig = new Big(val ?? 0)
valBig = valBig.div(coef)
@ -155,22 +200,71 @@ const chartOption = computed<EChartsOption>(() => { @@ -155,22 +200,71 @@ const chartOption = computed<EChartsOption>(() => {
appendToBody: true,
formatter: function (params: any) {
//
const date = new Date(params[0].value[0])
const timeStr = dayjs(params[0].value[0]).format('YYYY-MM-DD HH:mm:ss.SSS')
const targetTime = params[0].value[0]
const timeStr = dayjs(targetTime).format('YYYY-MM-DD HH:mm:ss.SSS')
let relVal = timeStr
const findNearest = (data: any[], target: number) => {
let left = 0
let right = data.length - 1
let nearest = data[0]
let minDiff = Math.abs(data[0][0] - target)
for (let i = 0; i < params.length; i++) {
const data = props.legends.find(item => item.addr === params[i].seriesId)
const coefficient = data?.coefficient ? Number(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.split('|')[0]}:</div>
<div>${params[i].value[1]}${
coefficient ? `【系数为${coefficient}` : ''
}${unit}</div>
</div>`
while (left <= right) {
const mid = Math.floor((left + right) / 2)
const current = data[mid]
const diff = Math.abs(current[0] - target)
if (diff < minDiff) {
minDiff = diff
nearest = current
}
if (current[0] < target) {
left = mid + 1
} else if (current[0] > target) {
right = mid - 1
} else {
return current
}
}
return nearest
}
chartOption.value.series
?.filter((series: any) => !unCheckArr.value.includes(series.name))
.forEach((series: any, index: number) => {
// params hover
const paramItem = params.find((p: any) => p.seriesId === series.id)
let value
let marker
if (paramItem) {
value = paramItem.value[1]
marker = paramItem.marker
} else {
// params
const nearestPoint = findNearest(series.data, targetTime)
value = nearestPoint ? nearestPoint[1] : '--'
// marker
const color = series.itemStyle?.color || '#000'
marker = `<span style="display:inline-block;margin-right:4px;color:${color};font-weight:bold;font-size: 20px;text-align:center;vertical-align:middle;line-height:10px;">*</span>`
}
const legendData = props.legends.find(item => item.addr === series.id)
const coefficient = legendData?.coefficient
? Number(legendData.coefficient)
: undefined
const unit = legendData?.unit || ''
const seriesName = series.name.split('|')[0]
relVal += `<div style="display: flex; justify-content: space-between; gap: 30px;">
<div style="display:flex;align-items:center;">${marker}${seriesName}:</div>
<div>${value}${coefficient ? `【系数为${coefficient}` : ''}${unit}</div>
</div>`
})
return relVal
},
},

5
src/views/stationData/index.vue

@ -106,6 +106,9 @@ import { type SiteInfo, useTransferDataStore } from '@/stores/transferData' @@ -106,6 +106,9 @@ import { type SiteInfo, useTransferDataStore } from '@/stores/transferData'
import { storeToRefs } from 'pinia'
import { getSiteList, type ISite } from '@/api/module/transfer'
import EdfsWrap from "@/components/Edfs-wrap.vue";
import { useMessage } from '@/utils/useMessage'
const message = useMessage()
const env = import.meta.env
@ -141,6 +144,8 @@ async function loadSiteList() { @@ -141,6 +144,8 @@ async function loadSiteList() {
const res = await getSiteList()
if (res.code === 200 || res.code === 0) {
siteList.value = res.data
} else {
message.error(res?.msg || '获取站点列表失败')
}
}

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

@ -147,7 +147,7 @@ const handleInput = debounce(async (val: number) => { @@ -147,7 +147,7 @@ const handleInput = debounce(async (val: number) => {
const isShowDrawer = defineModel<boolean>()
const title = computed(() =>
curDevice.value?.isonLine
? '数据详情'
? `${curDevice.value?.sn ?? ''}数据详情`
: env.VITE_APP_ENV === 'local'
? `已导出数据详情`
: '已导入数据详情'
@ -391,7 +391,7 @@ function setChartData(pointData: any[]) { @@ -391,7 +391,7 @@ function setChartData(pointData: any[]) {
pointData.forEach((data: any[]) => {
const [ts, val, addr] = data
if (checkPointList.value.some(i => i.addr === addr) && !!val) {
const time = dayjs(Number(ts)).format('YYYY-MM-DD HH:mm:ss.SSS')
const time = Number(ts)
if (addr && val) {
const colData = chartData.get(addr)
const value = Number(Number(val).toFixed(5))

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

@ -2,45 +2,45 @@ @@ -2,45 +2,45 @@
<div class="fault-rule-drawer">
<el-drawer
v-model="isShowDrawer"
:before-close="handleBeforeClose"
:title="title"
direction="rtl"
size="100%"
modal-class="model-dev-opn"
:before-close="handleBeforeClose"
size="100%"
@opened="onDrawerOpened"
>
<main class="wh-full flex">
<EdfsWrap
title="点位组"
isCollapse
:collapsed="collapsed"
@collapse="onCollapse"
:style="{ width: `${collapsed ? 0 : 600}px` }"
isCollapse
title="点位组"
@collapse="onCollapse"
>
<PointGroupTree
v-if="isShowDrawer"
ref="pointGroupTreeRef"
:data="pointGroup"
@device-select="onGroupChange"
:groupChangeLoading="groupChangeLoading"
@onchangePoints="onchangePoints"
:pointList="pointList"
:loadingPoints="loadingPoints"
:isTransfer="props.isTransfer"
:loadingPoints="loadingPoints"
:pointList="pointList"
:siteInfo="props.siteInfo"
ref="pointGroupTreeRef"
@onchangePoints="onchangePoints"
@device-select="onGroupChange"
/>
</EdfsWrap>
<div
class="flex-1 p-4 h-full overflow-hidden relative"
v-loading="loading"
class="flex-1 p-4 h-full overflow-hidden relative"
element-loading-text="数据加载中请耐心等待..."
>
<div
class="absolute inset-0 z-[99] flex items-center justify-center bg-white/80 backdrop-blur-sm transition-opacity duration-300"
v-if="isFetching"
class="absolute inset-0 z-[99] flex items-center justify-center bg-white/80 backdrop-blur-sm transition-opacity duration-300"
>
<div class="w-full max-w-[700px] mx-auto px-4 sm:px-6 lg:px-8">
<el-scrollbar height="70vh" max-height="600px" class="pr-2">
<el-scrollbar class="pr-2" height="70vh" max-height="600px">
<div class="space-y-4 md:space-y-6">
<div
v-for="deviceInfo in pointInfoData"
@ -52,9 +52,9 @@ @@ -52,9 +52,9 @@
</div>
<el-progress
:text-inside="true"
:stroke-width="20"
:percentage="deviceInfo.progress"
:stroke-width="20"
:text-inside="true"
/>
<div class="text-gray-600 text-base">
@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
>/<span class="text-blue-600 font-semibold">{{
deviceInfo.total
}}</span
>剩余<span class="text-red-500 font-semibold">{{
>剩余<span class="text-red-500 font-semibold">{{
deviceInfo.total - deviceInfo.fetchLimit
}}</span>
</div>
@ -78,13 +78,13 @@ @@ -78,13 +78,13 @@
<div class="w-400px">
<el-date-picker
v-model="time"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
range-separator="到"
:default-value="getBeforeMonth"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled-date="disabledDate"
end-placeholder="结束时间"
range-separator="到"
start-placeholder="开始时间"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</div>
<el-button type="primary" @click="loadChardData2">查询数据</el-button>
@ -92,18 +92,18 @@ @@ -92,18 +92,18 @@
<el-input-number
:key="refreshKey"
v-model="num"
:min="1"
:max="diffHours"
:min="1"
@input="handleInput"
/>
小时
</div>
<NewDataChart
v-if="isShowChart"
ref="chartRef"
:axis-data="Array.from(axisData)"
:chart-datas="chartData"
:legends="legends"
:axis-data="Array.from(axisData)"
ref="chartRef"
@onChangeCoefficient="onChangeCoefficient"
/>
</div>
@ -112,7 +112,7 @@ @@ -112,7 +112,7 @@
</div>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import NewDataChart from '../../component/newDataChart.vue'
import PointGroupTree from './PointGroupTree.vue'
import type { IMyPoint, IOfflineDevice, IOnlineDevice } from '../../type'
@ -174,11 +174,11 @@ const handleInput = debounce(async (val: number) => { @@ -174,11 +174,11 @@ const handleInput = debounce(async (val: number) => {
const isShowDrawer = defineModel<boolean>()
const title = computed(() =>
props.isTransfer
? '数据详情'
+props.isTransfer
? `${curDevice.value?.sn ?? ''}数据详情`
: env.VITE_APP_ENV === 'local'
? `已导出数据详情`
: '已导入数据详情'
? `${curDevice.value?.sn ?? ''}已导出数据详情`
: `${curDevice.value?.sn ?? ''}已导入数据详情`,
)
const message = useMessage()
@ -316,7 +316,7 @@ watch( @@ -316,7 +316,7 @@ watch(
pointInfoData.value = newValue
loading.value = false
},
{ deep: true }
{ deep: true },
)
async function loadChardData2() {
@ -356,7 +356,7 @@ function setChartData2(groupName: string, data: any[]) { @@ -356,7 +356,7 @@ function setChartData2(groupName: string, data: any[]) {
data.forEach((data: any[]) => {
const [ts, val, addr] = data
const time = dayjs(Number(ts)).format('YYYY-MM-DD HH:mm:ss.SSS')
const time = Number(ts)
if (addr && val) {
const colData = chartData.get(`${groupName}-${addr}`)
const value = Number(Number(val).toFixed(5))
@ -390,7 +390,8 @@ function handleBeforeClose(done: () => void) { @@ -390,7 +390,8 @@ function handleBeforeClose(done: () => void) {
chartGroupMap.clear()
done()
})
.catch(() => {})
.catch(() => {
})
}
function clearData() {
@ -472,7 +473,7 @@ function onchangePoints(checkPoints: IMyPoint[]) { @@ -472,7 +473,7 @@ function onchangePoints(checkPoints: IMyPoint[]) {
if (!curGroup?.value || !curGroupName?.value) return message.error('请选择设备')
const currentCheckPoints = checkPoints.filter(
(r: any) => r.parentName === curGroupName.value
(r: any) => r.parentName === curGroupName.value,
)
chartParamsMap.set(curGroupName.value, {
name: curGroupName.value,
@ -517,7 +518,7 @@ defineExpose({ @@ -517,7 +518,7 @@ defineExpose({
})
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
.fault-rule-drawer {
font-size: 16px;

2
src/views/stationData/transfer/index.vue

@ -182,7 +182,7 @@ const isonLineTransfer = computed(() => type.value === 'export') @@ -182,7 +182,7 @@ const isonLineTransfer = computed(() => type.value === 'export')
const message = useMessage()
const localTransferBtnText = computed(()=> isonLineTransfer.value ? '数据导出' : '数据导入')
const localTransferBtnText = computed(() => isonLineTransfer.value ? '数据导出' : '数据导入')
const transferDataStore = useTransferDataStore()
const { devicesMap } = storeToRefs(transferDataStore)

Loading…
Cancel
Save