This commit is contained in:
2026-03-26 11:12:48 +08:00
parent 09e0e0fb6e
commit 68cf01dd6f
15 changed files with 1743 additions and 37 deletions

View File

@ -0,0 +1,55 @@
import request from '@/utils/request'
export function listMeasurePoint(query) {
return request({
url: '/mes/md/measurepoint/list',
method: 'get',
params: query
})
}
export function getMeasurePoint(pointId) {
return request({
url: '/mes/md/measurepoint/' + pointId,
method: 'get'
})
}
export function addMeasurePoint(data) {
return request({
url: '/mes/md/measurepoint',
method: 'post',
data: data
})
}
export function updateMeasurePoint(data) {
return request({
url: '/mes/md/measurepoint',
method: 'put',
data: data
})
}
export function delMeasurePoint(pointId) {
return request({
url: '/mes/md/measurepoint/' + pointId,
method: 'delete'
})
}
export function getMeasurePointLatest(pointCode) {
return request({
url: '/mes/md/measurepoint/latest',
method: 'get',
params: { pointCode }
})
}
export function getMeasurePointHistory(query) {
return request({
url: '/mes/md/measurepoint/history',
method: 'get',
params: query
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 43 KiB

BIN
src/assets/logo/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -4,7 +4,7 @@
* 全局配置文件 * 全局配置文件
*/ */
export default { export default {
reportUrl: 'http://localhost:7899/ureport', reportUrl: 'http://110.40.171.179:7899/ureport',
print_transfer_url: "http://111.21.251.50:17522", print_transfer_url: "http://111.21.251.50:17522",
print_transfer_token: "123456", print_transfer_token: "123456",
} }

View File

@ -2,13 +2,23 @@
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/> <breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/> <top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<div class="right-menu-item board-entry">
<el-button
type="primary"
size="mini"
icon="el-icon-monitor"
@click="openWorkshopBoard"
>
大屏
</el-button>
</div>
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
@ -36,6 +46,7 @@
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
</div> </div>
</template> </template>
@ -47,8 +58,6 @@ import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
export default { export default {
components: { components: {
@ -57,9 +66,10 @@ export default {
Hamburger, Hamburger,
Screenfull, Screenfull,
SizeSelect, SizeSelect,
Search, Search
RuoYiGit, },
RuoYiDoc data() {
return {}
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
@ -88,6 +98,36 @@ export default {
toggleSideBar() { toggleSideBar() {
this.$store.dispatch('app/toggleSideBar') this.$store.dispatch('app/toggleSideBar')
}, },
openWorkshopBoard() {
const routeData = this.$router.resolve({
path: '/board/workshop',
query: {
_t: Date.now(),
displayMode: 'fullscreen'
}
})
const screenWidth = window.screen.availWidth || window.innerWidth || 1920
const screenHeight = window.screen.availHeight || window.innerHeight || 1080
const features = [
'popup=yes',
'noopener=yes',
'noreferrer=yes',
'toolbar=no',
'menubar=no',
'location=no',
'status=no',
'scrollbars=yes',
'resizable=yes',
`width=${screenWidth}`,
`height=${screenHeight}`,
'left=0',
'top=0'
].join(',')
const popup = window.open(routeData.href, 'WorkshopBoardDisplay', features)
if (popup) {
popup.focus()
}
},
async logout() { async logout() {
this.$confirm('确定注销并退出系统吗?', '提示', { this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
@ -95,9 +135,9 @@ export default {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.$store.dispatch('LogOut').then(() => { this.$store.dispatch('LogOut').then(() => {
location.href = '/index'; location.href = '/index'
}) })
}).catch(() => {}); }).catch(() => {})
} }
} }
} }
@ -165,6 +205,17 @@ export default {
} }
} }
.board-entry {
padding: 0 4px;
:deep(.el-button) {
height: 32px;
padding: 0 12px;
border-radius: 16px;
font-size: 13px;
}
}
.avatar-container { .avatar-container {
margin-right: 30px; margin-right: 30px;

View File

@ -6,18 +6,18 @@
<h3 class="drawer-title">主题风格设置</h3> <h3 class="drawer-title">主题风格设置</h3>
</div> </div>
<div class="setting-drawer-block-checbox"> <div class="setting-drawer-block-checbox">
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')"> <!-- <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">-->
<img src="@/assets/images/dark.svg" alt="dark"> <!-- <img src="@/assets/images/dark.svg" alt="dark">-->
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> <!-- <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">-->
<i aria-label="图标: check" class="anticon anticon-check"> <!-- <i aria-label="图标: check" class="anticon anticon-check">-->
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" <!-- <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"-->
focusable="false" class=""> <!-- focusable="false" class="">-->
<path <!-- <path-->
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/> <!-- d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>-->
</svg> <!-- </svg>-->
</i> <!-- </i>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')"> <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
<img src="@/assets/images/light.svg" alt="light"> <img src="@/assets/images/light.svg" alt="light">
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">

View File

@ -3,11 +3,10 @@
<transition name="sidebarLogoFade"> <transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" /> <img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
</router-link> </router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> <router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" /> <img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1> <img v-if="logo1" :src="logo1" class="sidebar-logo1"/>
</router-link> </router-link>
</transition> </transition>
</div> </div>
@ -15,6 +14,7 @@
<script> <script>
import logoImg from '@/assets/logo/logo.png' import logoImg from '@/assets/logo/logo.png'
import logo1Img from '@/assets/logo/logo1.png'
import variables from '@/assets/styles/variables.scss' import variables from '@/assets/styles/variables.scss'
export default { export default {
@ -36,7 +36,8 @@ export default {
data() { data() {
return { return {
title: 'HENGYOU', title: 'HENGYOU',
logo: logoImg logo: logoImg,
logo1:logo1Img,
} }
} }
} }
@ -71,7 +72,12 @@ export default {
vertical-align: middle; vertical-align: middle;
margin-right: 12px; margin-right: 12px;
} }
& .sidebar-logo1 {
width: 132px;
height: 32px;
vertical-align: middle;
margin-right: 12px;
}
& .sidebar-title { & .sidebar-title {
display: inline-block; display: inline-block;
margin: 0; margin: 0;

View File

@ -8,7 +8,7 @@ import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/auth-redirect', '/bind', '/register'] const whiteList = ['/login', '/auth-redirect', '/bind', '/register', '/board/workshop']
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()

View File

@ -87,6 +87,13 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' } meta: { title: '个人中心', icon: 'user' }
} }
] ]
},
{
path: '/board/workshop',
component: () => import('@/views/mes/board/workshop'),
hidden: true,
name: 'WorkshopBoard',
meta: { title: '车间看板', noCache: true }
} }
] ]

View File

@ -2,7 +2,7 @@ module.exports = {
/** /**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light * 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/ */
sideTheme: 'theme-dark', sideTheme: 'theme-light',
/** /**
* 是否系统布局配置 * 是否系统布局配置

View File

@ -64,10 +64,10 @@
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部 --> <!-- 底部
<div class="el-login-footer"> <div class="el-login-footer">
<span @click="toIPC">陕ICP备2022002135号-1</span> <span @click="toIPC">陕ICP备2022002135号-1</span>
</div> </div> -->
</div> </div>
</template> </template>
@ -83,7 +83,7 @@ export default {
return { return {
codeUrl: "", codeUrl: "",
loginForm: { loginForm: {
username: "testuser", username: "admin",
password: "123456", password: "123456",
rememberMe: false, rememberMe: false,
code: "", code: "",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,491 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="88px">
<el-form-item label="测量点编码" prop="pointCode">
<el-input v-model="queryParams.pointCode" placeholder="请输入测量点编码" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="测量点名称" prop="pointName">
<el-input v-model="queryParams.pointName" placeholder="请输入测量点名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="所属车间" prop="workshopId">
<el-select v-model="queryParams.workshopId" placeholder="请选择车间" clearable filterable>
<el-option v-for="item in workshopOptions" :key="item.workshopId" :label="item.workshopName" :value="item.workshopId" />
</el-select>
</el-form-item>
<el-form-item label="设备编码" prop="deviceCode">
<el-input v-model="queryParams.deviceCode" placeholder="请输入设备编码" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="启用状态" prop="enableFlag">
<el-select v-model="queryParams.enableFlag" placeholder="请选择" clearable>
<el-option v-for="dict in dict.type.sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['mes:md:measurepoint:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['mes:md:measurepoint:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['mes:md:measurepoint:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="refreshLatest" v-hasPermi="['mes:md:measurepoint:query']">刷新最新值</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="measurePointList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="测量点编码" align="center" prop="pointCode" min-width="120">
<template slot-scope="scope">
<el-button type="text" @click="handleView(scope.row)" v-hasPermi="['mes:md:measurepoint:query']">{{ scope.row.pointCode }}</el-button>
</template>
</el-table-column>
<el-table-column label="测量点名称" align="center" prop="pointName" min-width="140" />
<el-table-column label="车间" align="center" prop="workshopName" min-width="120" />
<el-table-column label="设备编码" align="center" prop="deviceCode" min-width="120" />
<el-table-column label="节点编码" align="center" prop="nodeCode" min-width="120" />
<el-table-column label="最新值" align="center" min-width="120">
<template slot-scope="scope">
<span>{{ formatLatestValue(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="最新时间" align="center" prop="latestTime" min-width="180" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="字段" align="center" prop="fieldKey" min-width="120" />
<el-table-column label="启用" align="center" prop="enableFlag" width="80">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_yes_no" :value="scope.row.enableFlag" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="260">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-data-line" @click="openHistory(scope.row)" v-hasPermi="['mes:md:measurepoint:query']">历史曲线</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['mes:md:measurepoint:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['mes:md:measurepoint:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
<el-row>
<el-col :span="12">
<el-form-item label="测量点编码" prop="pointCode">
<el-input v-model="form.pointCode" :readonly="optType === 'view'" placeholder="请输入测量点编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="测量点名称" prop="pointName">
<el-input v-model="form.pointName" :readonly="optType === 'view'" placeholder="请输入测量点名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所属车间" prop="workshopId">
<el-select v-model="form.workshopId" :disabled="optType === 'view'" placeholder="请选择车间" filterable style="width: 100%">
<el-option v-for="item in workshopOptions" :key="item.workshopId" :label="item.workshopName" :value="item.workshopId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用状态" prop="enableFlag">
<el-radio-group v-model="form.enableFlag" :disabled="optType === 'view'">
<el-radio v-for="dict in dict.type.sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="设备编码" prop="deviceCode">
<el-input v-model="form.deviceCode" :readonly="optType === 'view'" placeholder="请输入设备编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="节点编码" prop="nodeCode">
<el-input v-model="form.nodeCode" :readonly="optType === 'view'" placeholder="请输入节点编码" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="字段名" prop="fieldKey">
<el-input v-model="form.fieldKey" :readonly="optType === 'view'" placeholder="Influx field key" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" :readonly="optType === 'view'" placeholder="例如 ℃、kPa、A" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="保留位数" prop="precisionDigit">
<el-input-number v-model="form.precisionDigit" :disabled="optType === 'view'" :min="0" :max="6" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="排序号" prop="sortNum">
<el-input-number v-model="form.sortNum" :disabled="optType === 'view'" :min="1" :max="9999" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="Tag 条件" prop="tagJson">
<el-input v-model="form.tagJson" :readonly="optType === 'view'" type="textarea" :rows="4" placeholder='JSON例如 {"lineCode":"L01","sensor":"TEMP"}' />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" :readonly="optType === 'view'" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button v-if="optType !== 'view'" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<el-dialog :title="historyTitle" :visible.sync="historyOpen" width="1100px" append-to-body @opened="renderHistoryChart">
<el-row :gutter="12" class="history-toolbar">
<el-col :span="5">
<el-select v-model="historyQuery.range" placeholder="时间范围" @change="loadHistory">
<el-option label="最近1小时" value="1h" />
<el-option label="最近6小时" value="6h" />
<el-option label="最近24小时" value="24h" />
<el-option label="最近7天" value="7d" />
</el-select>
</el-col>
<el-col :span="13">
<el-date-picker
v-model="historyDateRange"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
@change="handleDateRangeChange"
/>
</el-col>
<el-col :span="4" class="history-toolbar-action">
<el-button type="primary" icon="el-icon-search" size="mini" @click="loadHistory">查询曲线</el-button>
</el-col>
</el-row>
<el-descriptions v-if="currentPoint.pointCode" :column="4" border size="small" class="history-summary">
<el-descriptions-item label="测量点">{{ currentPoint.pointName || currentPoint.pointCode }}</el-descriptions-item>
<el-descriptions-item label="最新值">{{ formatLatestValue(currentPoint) }}</el-descriptions-item>
<el-descriptions-item label="最新时间">{{ currentPoint.latestTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="单位">{{ currentPoint.unit || '-' }}</el-descriptions-item>
</el-descriptions>
<div v-loading="historyLoading" ref="historyChart" class="history-chart"></div>
</el-dialog>
</div>
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons')
import { listAllWorkshop } from '@/api/mes/md/workshop'
import { addMeasurePoint, delMeasurePoint, getMeasurePoint, getMeasurePointHistory, listMeasurePoint, updateMeasurePoint } from '@/api/mes/md/measurepoint'
export default {
name: 'MeasurePoint',
dicts: ['sys_yes_no'],
data() {
return {
loading: false,
historyLoading: false,
open: false,
historyOpen: false,
showSearch: true,
single: true,
multiple: true,
total: 0,
title: '',
historyTitle: '历史曲线',
optType: undefined,
ids: [],
workshopOptions: [],
measurePointList: [],
historyRecords: [],
historyDateRange: [],
currentPoint: {},
historyChart: null,
queryParams: {
pageNum: 1,
pageSize: 10,
pointCode: null,
pointName: null,
workshopId: null,
deviceCode: null,
enableFlag: null
},
form: {},
historyQuery: {
pointCode: null,
range: '24h',
interval: '5m',
startTime: null,
endTime: null
},
rules: {
pointCode: [{ required: true, message: '测量点编码不能为空', trigger: 'blur' }],
pointName: [{ required: true, message: '测量点名称不能为空', trigger: 'blur' }],
fieldKey: [{ required: true, message: '字段名不能为空', trigger: 'blur' }],
enableFlag: [{ required: true, message: '请选择启用状态', trigger: 'change' }]
}
}
},
created() {
this.getWorkshopOptions()
this.getList()
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeHistoryChart)
if (this.historyChart) {
this.historyChart.dispose()
this.historyChart = null
}
},
methods: {
getList() {
this.loading = true
listMeasurePoint(this.queryParams).then(response => {
this.measurePointList = response.rows
this.total = response.total
this.loading = false
}).catch(() => {
this.loading = false
})
},
getWorkshopOptions() {
listAllWorkshop().then(response => {
this.workshopOptions = response.data || []
})
},
reset() {
this.form = {
pointId: null,
pointCode: null,
pointName: null,
workshopId: null,
deviceCode: null,
nodeCode: null,
fieldKey: null,
tagJson: null,
unit: null,
precisionDigit: 2,
sortNum: 1,
enableFlag: 'Y',
remark: null
}
this.resetForm('form')
},
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.pointId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
handleAdd() {
this.reset()
this.open = true
this.optType = 'add'
this.title = '新增测量点'
},
handleUpdate(row) {
this.reset()
const pointId = row.pointId || this.ids[0]
getMeasurePoint(pointId).then(response => {
this.form = response.data
this.open = true
this.optType = 'edit'
this.title = '修改测量点'
})
},
handleView(row) {
this.reset()
getMeasurePoint(row.pointId).then(response => {
this.form = response.data
this.open = true
this.optType = 'view'
this.title = '测量点详情'
})
},
submitForm() {
this.$refs.form.validate(valid => {
if (!valid) {
return
}
const request = this.form.pointId ? updateMeasurePoint(this.form) : addMeasurePoint(this.form)
request.then(() => {
this.$modal.msgSuccess(this.form.pointId ? '修改成功' : '新增成功')
this.open = false
this.getList()
})
})
},
handleDelete(row) {
const pointIds = row.pointId || this.ids
this.$modal.confirm('是否确认删除测量点编号为“' + pointIds + '”的数据项?').then(() => {
return delMeasurePoint(pointIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess('删除成功')
}).catch(() => {})
},
cancel() {
this.open = false
this.reset()
},
refreshLatest() {
this.getList()
},
formatLatestValue(row) {
if (!row || row.latestValue === null || row.latestValue === undefined || row.latestValue === '') {
return '-'
}
return row.unit ? row.latestValue + ' ' + row.unit : row.latestValue
},
openHistory(row) {
this.currentPoint = { ...row }
this.historyQuery.pointCode = row.pointCode
this.historyQuery.range = '24h'
this.historyQuery.interval = '5m'
this.historyQuery.startTime = null
this.historyQuery.endTime = null
this.historyDateRange = []
this.historyTitle = '历史曲线 - ' + (row.pointName || row.pointCode)
this.historyOpen = true
this.loadHistory()
},
handleDateRangeChange(value) {
if (value && value.length === 2) {
this.historyQuery.startTime = value[0]
this.historyQuery.endTime = value[1]
} else {
this.historyQuery.startTime = null
this.historyQuery.endTime = null
}
},
loadHistory() {
if (!this.historyQuery.pointCode) {
return
}
this.historyLoading = true
getMeasurePointHistory(this.historyQuery).then(response => {
const data = response.data || {}
this.currentPoint = data.point || this.currentPoint
this.historyRecords = data.records || []
this.historyLoading = false
this.$nextTick(() => {
this.renderHistoryChart()
})
}).catch(() => {
this.historyLoading = false
})
},
renderHistoryChart() {
if (!this.historyOpen || !this.$refs.historyChart) {
return
}
if (!this.historyChart) {
this.historyChart = echarts.init(this.$refs.historyChart, 'macarons')
window.addEventListener('resize', this.resizeHistoryChart)
}
const xAxisData = this.historyRecords.map(item => item.time)
const seriesData = this.historyRecords.map(item => item.value)
this.historyChart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: 50, right: 30, top: 40, bottom: 80 },
xAxis: {
type: 'category',
data: xAxisData,
boundaryGap: false,
axisLabel: { rotate: 30 }
},
yAxis: {
type: 'value',
name: this.currentPoint.unit || ''
},
dataZoom: [
{ type: 'inside' },
{ type: 'slider', bottom: 20 }
],
series: [{
name: this.currentPoint.pointName || this.currentPoint.pointCode,
type: 'line',
smooth: true,
showSymbol: false,
lineStyle: { width: 2 },
areaStyle: { opacity: 0.15 },
data: seriesData
}]
}, true)
this.resizeHistoryChart()
},
resizeHistoryChart() {
if (this.historyChart) {
this.historyChart.resize()
}
}
}
}
</script>
<style scoped>
.history-toolbar {
margin-bottom: 12px;
}
.history-toolbar .el-select,
.history-toolbar .el-date-editor {
width: 100%;
}
.history-toolbar-action {
text-align: right;
}
.history-summary {
margin-bottom: 12px;
}
.history-chart {
width: 100%;
height: 460px;
}
</style>