Compare commits

...

3 Commits

Author SHA1 Message Date
砂糖
30c319694c feat: 更新UI主题和样式,优化页面布局和交互
- 将侧边栏主题从深色改为浅色
- 移除多个组件的背景色和金属风格样式
- 调整按钮、表格和分页组件的样式和间距
- 新增easycode扫码功能页面
- 更新基础URL配置和应用版本号
- 优化登录后跳转逻辑和登出功能
- 调整滚动条和菜单项的样式
2025-11-03 11:16:07 +08:00
砂糖
a038261888 feat(监控): 添加过程跟踪组件及主页面集成
添加TrackMeasure组件用于展示过程跟踪数据,包括入口、炉温、涂层和出口数据的实时监控图表
组件支持WebSocket连接、数据实时更新、图表切换和响应式布局
在主页面中集成该组件并设置相关数据绑定
2025-11-03 10:51:46 +08:00
砂糖
7f98f145d4 feat(websocket): 添加WebSocket数据监控页面和代理配置
新增WebSocket数据监控页面,包含四种图表展示实时数据,支持数据类型切换
更新vue.config.js添加WebSocket代理配置
添加IDE配置文件到.gitignore
2025-11-03 10:17:57 +08:00
31 changed files with 2907 additions and 838 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@
node_modules
.pnp
.pnp.js
.idea
.vscode
# Turbo
.turbo

View File

@@ -1,7 +1,7 @@
// 应用全局配置
module.exports = {
baseUrl: 'http://192.168.31.116:8080',
// baseUrl: 'http://140.143.206.120:8080',
// baseUrl: 'http://192.168.31.116:8080',
baseUrl: 'http://140.143.206.120:8080',
// baseUrl: 'http://localhost:8080',
// 应用信息
appInfo: {

View File

@@ -2,8 +2,8 @@
"name" : "科伦普",
"appid" : "__UNI__E781B49",
"description" : "",
"versionName" : "1.2.0",
"versionCode" : "100",
"versionName" : "3.4",
"versionCode" : 1,
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,

View File

@@ -1,11 +1,12 @@
{
"pages": [
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "首页",
"path" : "pages/easycode/easycode",
"style" :
{
"navigationBarTitleText" : "扫码",
"navigationStyle": "custom"
}
}
},
{
"path": "pages/login",
@@ -13,6 +14,13 @@
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "首页",
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/index",
@@ -91,28 +99,28 @@
"navigationBarTitleText": "RuoYi",
"navigationBarBackgroundColor": "#FFFFFF"
},
"tabBar": {
"list": [
{
"text": "产线",
"pagePath": "pages/index",
"selectedIconPath": "/static/images/tabbar/home_.png",
"iconPath": "/static/images/tabbar/home.png"
},
{
"text": "扫码",
"pagePath": "pages/code/code",
"selectedIconPath": "/static/images/tabbar/work_.png",
"iconPath": "/static/images/tabbar/work.png"
},
{
"text": "我的",
"pagePath": "pages/mine/index",
"selectedIconPath": "/static/images/tabbar/mine_.png",
"iconPath": "/static/images/tabbar/mine.png"
}
]
},
// "tabBar": {
// "list": [
// {
// "text": "产线",
// "pagePath": "pages/index",
// "selectedIconPath": "/static/images/tabbar/home_.png",
// "iconPath": "/static/images/tabbar/home.png"
// },
// {
// "text": "扫码",
// "pagePath": "pages/code/code",
// "selectedIconPath": "/static/images/tabbar/work_.png",
// "iconPath": "/static/images/tabbar/work.png"
// },
// {
// "text": "我的",
// "pagePath": "pages/mine/index",
// "selectedIconPath": "/static/images/tabbar/mine_.png",
// "iconPath": "/static/images/tabbar/mine.png"
// }
// ]
// },
"easycom": {
"autoscan": true,
"custom": {

View File

@@ -0,0 +1,60 @@
<template>
<view>
<button v-for='item in types' @click="handleScan(item.dictValue)">
{{ item.dictLabel }}
</button>
<button @click='handleLogout'>
退出登录
</button>
</view>
</template>
<script>
import { getDicts } from '@/api/system/dict/data.js'
import { getGenerateRecord } from '@/api/wms/code.js'
export default {
data() {
return {
types: []
}
},
methods: {
handleLogout() {
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
this.$store.dispatch('LogOut').then(() => {}).finally(() => {
this.$tab.reLaunch('/pages/login')
})
})
},
handleScan(type) {
// 1. 扫码
uni.scanCode({
success(res) {
const result = res.result;
// 2. 解析二维码的content获取enter_coil_no、current_coil_no和coil_id
const qrcodeRecord = qrcodeRes.data;
const content = JSON.parse(qrcodeRecord.content);
const enterCoilNo = content.enter_coil_no;
const currentCoilNo = content.current_coil_no;
const coilId = content.coil_id && content.coil_id !== 'null' ? content.coil_id : null;
// 3. 调用创建待操作记录的API
}
})
}
},
mounted() {
// 获取字典
getDicts('easycode_type').then(res => {
console.log(res)
this.types = res.data
})
}
}
</script>
<style>
</style>

View File

@@ -64,7 +64,7 @@
onLoad() {
//#ifdef H5
if (getToken()) {
this.$tab.reLaunch('/pages/index')
this.$tab.reLaunch('/pages/easycode/easycode')
}
//#endif
},
@@ -122,7 +122,7 @@
loginSuccess(result) {
// 设置用户信息
this.$store.dispatch('GetInfo').then(res => {
this.$tab.reLaunch('/pages/index')
this.$tab.reLaunch('/pages/easycode/easycode')
})
}
}

View File

@@ -103,9 +103,9 @@
},
handleLogout() {
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
// this.$store.dispatch('LogOut').then(() => {}).finally(() => {
this.$store.dispatch('LogOut').then(() => {}).finally(() => {
this.$tab.reLaunch('/pages/login')
// })
})
})
},
handleToEditInfo() {

View File

@@ -41,11 +41,11 @@
@include colorBtn($yellow)
}
.pan-btn {
.el-button.pan-btn {
font-size: 14px;
color: #fff;
padding: 14px 36px;
border-radius: 8px;
padding: 4px !important;
border-radius: 4px;
border: none;
outline: none;
transition: 600ms ease all;
@@ -81,7 +81,7 @@
}
}
.custom-button {
.el-button.custom-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
@@ -93,7 +93,21 @@
box-sizing: border-box;
outline: 0;
margin: 0;
padding: 10px 15px;
padding: 2px !important;
font-size: 14px;
border-radius: 4px;
border-radius: 2px;
}
.el-table__cell {
padding: 0 !important;
}
.el-table__cell .el-button {
padding: 0 !important;
}
.el-table__cell + .el-button {
margin-left: 4px !important;
padding: 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,8 @@
**/
/* theme color */
$--color-primary: #647b98;
$--color-primary: #5F7BA0;
// $--color-primary: #2bf;
$--color-success: #13ce66;
$--color-warning: #ffba00;
$--color-danger: #ff4949;
@@ -26,6 +27,6 @@ $--font-path: '~element-ui/lib/theme-chalk/fonts';
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
theme: $--color-primary;
}
// :export {
// theme: $--color-primary;
// }

View File

@@ -10,7 +10,6 @@ body {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
background-color: #a1a6ac;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}

View File

@@ -0,0 +1,291 @@
/**
* 通用css样式布局处理
* Copyright (c) 2019 klp
*/
/** 基础通用 **/
.pt5 {
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
}
.mt5 {
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
}
.mb8 {
margin-bottom: 8px;
}
.ml5 {
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
}
.ml10 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.ml20 {
margin-left: 20px;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
}
.el-message-box__status + .el-message-box__message{
word-break: break-word;
}
.el-dialog:not(.is-fullscreen) {
margin-top: 6vh !important;
}
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
overflow: auto;
overflow-x: hidden;
max-height: 70vh;
padding: 10px 20px 0;
}
// .el-table {
// .el-table__header-wrapper, .el-table__fixed-header-wrapper {
// th {
// word-break: break-word;
// background-color: #f8f8f9;
// color: #515a6e;
// height: 40px;
// font-size: 13px;
// }
// }
// .el-table__body-wrapper {
// .el-button [class*="el-icon-"] + span {
// margin-left: 1px;
// }
// }
// }
/** 表单布局 **/
// .form-header {
// font-size: 15px;
// color: #6379bb;
// border-bottom: 1px solid #ddd;
// margin: 8px 10px 25px 10px;
// padding-bottom: 5px
// }
// /** 表格布局 **/
// .pagination-container {
// position: relative;
// height: 25px;
// margin-bottom: 10px;
// margin-top: 15px;
// padding: 10px 20px !important;
// }
/* tree border */
// .tree-border {
// margin-top: 5px;
// border: 1px solid #e5e6e7;
// background: #FFFFFF none;
// border-radius: 4px;
// }
// .pagination-container .el-pagination {
// right: 0;
// position: absolute;
// }
// @media (max-width: 768px) {
// .pagination-container .el-pagination > .el-pagination__jump {
// display: none !important;
// }
// .pagination-container .el-pagination > .el-pagination__sizes {
// display: none !important;
// }
// }
// .el-table .fixed-width .el-button--mini {
// padding-left: 0;
// padding-right: 0;
// width: inherit;
// }
// /** 表格更多操作下拉样式 */
// .el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
// cursor: pointer;
// margin-left: 5px;
// }
// .el-table .el-dropdown, .el-icon-arrow-down {
// font-size: 12px;
// }
// .el-tree-node__content > .el-checkbox {
// margin-right: 8px;
// }
.list-group-striped > .list-group-item {
border-left: 0;
border-right: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
}
.list-group {
padding-left: 0px;
list-style: none;
}
.list-group-item {
border-bottom: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
margin-bottom: -1px;
padding: 11px 0px;
font-size: 13px;
}
.pull-right {
float: right !important;
}
.el-card__header {
padding: 14px 15px 7px;
min-height: 40px;
}
.el-card__body {
padding: 15px 20px 20px 20px;
}
.card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px;
}
/* button color */
.el-button--cyan.is-active,
.el-button--cyan:active {
background: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
.el-button--cyan:focus,
.el-button--cyan:hover {
background: #48D1CC;
border-color: #48D1CC;
color: #FFFFFF;
}
.el-button--cyan {
background-color: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
/* text color */
.text-navy {
color: #1ab394;
}
.text-primary {
color: inherit;
}
.text-success {
color: #1c84c6;
}
.text-info {
color: #23c6c8;
}
.text-warning {
color: #f8ac59;
}
.text-danger {
color: #ed5565;
}
.text-muted {
color: #888888;
}
/* image */
.img-circle {
border-radius: 50%;
}
.img-lg {
width: 120px;
height: 120px;
}
.avatar-upload-preview {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
/* 拖拽列样式 */
.sortable-ghost {
opacity: .8;
color: #fff !important;
background: #42b983 !important;
}
.top-right-btn {
position: relative;
float: right;
}

View File

@@ -1,415 +0,0 @@
/**
* 通用css样式布局处理
* Copyright (c) 2019 ruoyi
*/
/** 基础通用 **/
.pt5 {
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
}
.mt5 {
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
}
.mb8 {
margin-bottom: 8px;
}
.ml5 {
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
}
.ml10 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.ml20 {
margin-left: 20px;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
}
.el-message-box__status + .el-message-box__message{
word-break: break-word;
}
.el-dialog:not(.is-fullscreen) {
margin-top: 6vh !important;
}
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
overflow: auto;
overflow-x: hidden;
max-height: 70vh;
padding: 10px 20px 0;
}
.el-table {
/* 固定列表格容器背景与分割线 */
.el-table__fixed,
.el-table__fixed-left,
.el-table__fixed-right {
background: transparent; /* 让内部单元格背景生效 */
}
.el-table__fixed::before,
.el-table__fixed-left::before,
.el-table__fixed-right::before {
/* 顶部那条细线颜色 */
background-color: #444A52;
}
/* 固定列表头 */
.el-table__fixed-header-wrapper th,
.el-table__fixed-left .el-table__fixed-header-wrapper th,
.el-table__fixed-right .el-table__fixed-header-wrapper th {
background: #1F2227 !important; /* 与主表头一致的深灰 */
color: #FFFFFF !important; /* 白字 */
border-bottom: 1px solid #444A52 !important;
font-weight: 600;
}
/* 固定列表体单元格(奇偶行) */
.el-table__fixed-body-wrapper .el-table__row:nth-child(odd) .el-table__cell,
.el-table__fixed-left .el-table__fixed-body-wrapper .el-table__row:nth-child(odd) .el-table__cell,
.el-table__fixed-right .el-table__fixed-body-wrapper .el-table__row:nth-child(odd) .el-table__cell {
background: #2F3339 !important; /* 中深灰 */
color: #EAEAEA !important; /* 浅灰白字 */
border-bottom: 1px solid #444A52 !important;
}
.el-table__fixed-body-wrapper .el-table__row:nth-child(even) .el-table__cell,
.el-table__fixed-left .el-table__fixed-body-wrapper .el-table__row:nth-child(even) .el-table__cell,
.el-table__fixed-right .el-table__fixed-body-wrapper .el-table__row:nth-child(even) .el-table__cell {
background: #353A40 !important; /* 稍亮一档 */
color: #EAEAEA !important;
border-bottom: 1px solid #444A52 !important;
}
/* 固定列 hover / current-row 同步 */
.el-table__fixed-body-wrapper .el-table__row:hover .el-table__cell,
.el-table__fixed-left .el-table__fixed-body-wrapper .el-table__row:hover .el-table__cell,
.el-table__fixed-right .el-table__fixed-body-wrapper .el-table__row:hover .el-table__cell {
background: rgba(95, 123, 160, 0.25) !important; /* 工业蓝 hover */
color: #FFFFFF !important;
}
.el-table__fixed-body-wrapper .el-table__row.current-row .el-table__cell,
.el-table__fixed-left .el-table__fixed-body-wrapper .el-table__row.current-row .el-table__cell,
.el-table__fixed-right .el-table__fixed-body-wrapper .el-table__row.current-row .el-table__cell {
background: rgba(95, 123, 160, 0.35) !important; /* current-row 更明显 */
color: #FFFFFF !important;
font-weight: 600;
}
/* 固定列滚动条(可选) */
.el-table__fixed-body-wrapper::-webkit-scrollbar,
.el-table__fixed-left .el-table__fixed-body-wrapper::-webkit-scrollbar,
.el-table__fixed-right .el-table__fixed-body-wrapper::-webkit-scrollbar {
width: 8px; height: 8px;
}
.el-table__fixed-body-wrapper::-webkit-scrollbar-thumb,
.el-table__fixed-left .el-table__fixed-body-wrapper::-webkit-scrollbar-thumb,
.el-table__fixed-right .el-table__fixed-body-wrapper::-webkit-scrollbar-thumb {
background: #4A525B; border-radius: 6px;
}
}
/* =========================
Splitpanes 工业风深色主题
仍保留 default-theme 类名
========================= */
/* 根容器:与页面主背景统一,去掉默认白底 */
.splitpanes.default-theme {
background: #2B2F36; /* 页面主底色 */
border: none;
}
/* pane统一深灰金属风提供一致的内边距 */
.splitpanes.default-theme .splitpanes__pane {
background: linear-gradient(145deg, #1F242A, #21262D) !important; /* 深灰渐变 */
color: #EAEAEA !important;
padding: 12px 12px; /* 两侧内容留白一致 */
box-sizing: border-box;
overflow: hidden; /* 保持干净 */
}
/* 左/右外侧圆角,仅在最外侧边缘展示,避免中缝突兀 */
.splitpanes.default-theme .splitpanes__pane:first-child {
border-radius: 8px 0 0 8px;
}
.splitpanes.default-theme .splitpanes__pane:last-child {
border-radius: 0 8px 8px 0;
}
/* 分隔条splitter工业灰hover 工业蓝,带内嵌“握把” */
.splitpanes.default-theme .splitpanes__splitter {
position: relative;
background: #39414A !important; /* 静态 */
transition: background .2s ease;
}
.splitpanes.default-theme .splitpanes__splitter:hover {
background: #46505A !important; /* 悬停稍亮 */
}
/* 把握把做成中线,水平/垂直两种方向都美观 */
.splitpanes.default-theme .splitpanes__splitter::before {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
border-radius: 2px;
background: #4A525B;
}
.splitpanes.default-theme.splitpanes--vertical .splitpanes__splitter::before {
width: 2px; height: 60%;
}
.splitpanes.default-theme.splitpanes--horizontal .splitpanes__splitter::before {
height: 2px; width: 60%;
}
/* pane 内滚动条(如果有)与全站一致 */
.splitpanes.default-theme .splitpanes__pane::-webkit-scrollbar { width: 8px; height: 8px; }
.splitpanes.default-theme .splitpanes__pane::-webkit-scrollbar-thumb {
background: #4A525B; border-radius: 6px;
}
.splitpanes.default-theme .splitpanes__pane::-webkit-scrollbar-track { background: transparent; }
/* 可选:让右侧主区域看起来像一张卡片(若你的右 pane 是内容主区) */
.splitpanes.default-theme .splitpanes__pane:last-child {
box-shadow: 0 12px 24px rgba(0,0,0,.25) inset,
0 1px 0 rgba(255,255,255,.04) inset;
}
/* 可选:在窄屏时减小 pane 内边距,避免拥挤 */
@media (max-width: 992px) {
.splitpanes.default-theme .splitpanes__pane { padding: 8px; }
}
/** 表单布局 **/
.form-header {
font-size: 15px;
color: #6379bb;
border-bottom: 1px solid #ddd;
margin: 8px 10px 25px 10px;
padding-bottom: 5px
}
/** 表格布局 **/
.pagination-container {
position: relative;
height: 25px;
margin-bottom: 10px;
margin-top: 15px;
padding: 10px 20px !important;
}
/* tree border */
.tree-border {
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #FFFFFF none;
border-radius: 4px;
}
.pagination-container .el-pagination {
right: 0;
position: absolute;
}
@media (max-width: 768px) {
.pagination-container .el-pagination > .el-pagination__jump {
display: none !important;
}
.pagination-container .el-pagination > .el-pagination__sizes {
display: none !important;
}
}
.el-table .fixed-width .el-button--mini {
padding-left: 0;
padding-right: 0;
width: inherit;
}
/** 表格更多操作下拉样式 */
.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
cursor: pointer;
margin-left: 5px;
}
.el-table .el-dropdown, .el-icon-arrow-down {
font-size: 12px;
}
.el-tree-node__content > .el-checkbox {
margin-right: 8px;
}
.list-group-striped > .list-group-item {
border-left: 0;
border-right: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
}
.list-group {
padding-left: 0px;
list-style: none;
}
.list-group-item {
border-bottom: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
margin-bottom: -1px;
padding: 11px 0px;
font-size: 13px;
}
.pull-right {
float: right !important;
}
.el-card__header {
padding: 14px 15px 7px;
min-height: 40px;
}
.el-card__body {
padding: 15px 20px 20px 20px;
}
.card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px;
}
/* button color */
.el-button--cyan.is-active,
.el-button--cyan:active {
background: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
.el-button--cyan:focus,
.el-button--cyan:hover {
background: #48D1CC;
border-color: #48D1CC;
color: #FFFFFF;
}
.el-button--cyan {
background-color: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
/* text color */
.text-navy {
color: #1ab394;
}
.text-primary {
color: inherit;
}
.text-success {
color: #1c84c6;
}
.text-info {
color: #23c6c8;
}
.text-warning {
color: #f8ac59;
}
.text-danger {
color: #ed5565;
}
.text-muted {
color: #888888;
}
/* image */
.img-circle {
border-radius: 50%;
}
.img-lg {
width: 120px;
height: 120px;
}
.avatar-upload-preview {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
/* 拖拽列样式 */
.sortable-ghost {
opacity: .8;
color: #fff !important;
background: #42b983 !important;
}
.top-right-btn {
position: relative;
float: right;
}

View File

@@ -4,24 +4,25 @@
--text-regular: #333333;
--text-secondary: #555555;
--text-placeholder: #777777;
--background-color: #fff;
.main-container {
height: 100%;
transition: margin-left .28s, box-shadow .3s ease;
margin-left: $base-sidebar-width;
position: relative;
background: #3f4449; // 金属浅色渐变
// background: #1E2227; // 金属浅色渐变
}
.sidebarHide {
margin-left: 0!important;
margin-left: 0 !important;
}
.sidebar-container {
-webkit-transition: width .28s, background .3s ease;
transition: width 0.28s, background .3s ease;
width: $base-sidebar-width !important;
background: #3f4449; // 金属深色渐变
background: var(--background-color); // 金属深色渐变
border-right: 1px solid #8d939b;
height: 100%;
position: fixed;
@@ -44,11 +45,12 @@
.el-scrollbar__bar.is-vertical {
right: 0px;
background: rgba(0, 0, 0, 0.05);
background: #2Bf;
width: 0;
}
.el-scrollbar__thumb {
background: #1E2227;
background: var(--background-color);
border-radius: 3px;
}
@@ -86,7 +88,8 @@
background: transparent;
}
.el-menu-item, .el-submenu__title {
.el-menu-item,
.el-submenu__title {
// 明确默认状态样式(关键修复)
background: transparent !important;
box-shadow: none !important;
@@ -96,7 +99,7 @@
white-space: nowrap !important;
color: var(--text-regular); // 菜单项文本偏黑
border-radius: 4px;
margin: 0 6px;
margin: 0;
transition: all 0.2s ease;
}
@@ -107,17 +110,10 @@
background: rgba(255, 255, 255, 0.1) !important;
color: var(--text-primary) !important; // hover时文本更深
box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.1),
inset -1px -1px 2px rgba(255, 255, 255, 0.05);
inset -1px -1px 2px rgba(255, 255, 255, 0.05);
}
}
// 深色主题下子菜单选中高亮
& .theme-dark .is-active > .el-submenu__title {
color: #fff !important; // 选中时文字纯白
// background-color: rgba(95, 123, 160, 0.25) !important; // 工业蓝浅高亮
// border-left: 3px solid #5F7BA0; // 左边高亮条
}
// & .nest-menu .el-submenu>.el-submenu__title,
& .el-submenu .el-menu-item {
// 子菜单默认样式
@@ -145,13 +141,20 @@
&.is-active {
background: rgba(95, 123, 160, 0.28) !important; // 激活背景
color: #fff !important; // 激活文字白色
color: #000 !important; // 激活文字白色
font-weight: 600;
border-left: 3px solid #5F7BA0; // 左边高亮条
}
}
}
.el-menu-item.is-active.submenu-title-noDropdown {
background: #657b96; // 激活背景
color: #000; // 激活文字白色
font-weight: 600;
border-left: 3px solid #657b96; // 左边高亮条
}
.hideSidebar {
.sidebar-container {
width: 54px !important;
@@ -205,6 +208,10 @@
min-width: $base-sidebar-width !important;
}
.el-submenu .el-menu {
padding-left: 10px;
}
// mobile responsive
.mobile {
.main-container {
@@ -227,6 +234,7 @@
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
@@ -234,7 +242,7 @@
}
}
// when menu collapsed
// 收起状态下的菜单
.el-menu--vertical {
&>.el-menu {
.svg-icon {
@@ -252,7 +260,7 @@
background: rgba(255, 255, 255, 0.1) !important;
color: var(--text-primary) !important;
box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.1),
inset -1px -1px 2px rgba(255, 255, 255, 0.05);
inset -1px -1px 2px rgba(255, 255, 255, 0.05);
}
::v-deep &.is-active {
@@ -261,7 +269,7 @@
font-weight: 600;
border-left: 3px solid #5F7BA0;
box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.15),
inset -1px -1px 2px rgba(255, 255, 255, 0.08);
inset -1px -1px 2px rgba(255, 255, 255, 0.08);
}
::v-deep .el-menu-item.is-active span,
@@ -293,7 +301,6 @@
}
}
#app .sidebar-container .el-menu-item,
#app .sidebar-container .el-submenu__title {
margin: 0;
#app .sidebar-container .nest-menu .el-submenu .el-submenu__title {
margin: 0 4px;
}

View File

@@ -1,38 +1,45 @@
// 基础金属色调
$metal-dark: #637994; // 主色调1 - 深金属色
$metal-light: #bec3c9; // 主色调2 - 浅金属色
$metal-bg: #a1a6ac; // 背景主色调
$metal-highlight: #d0d5db; // 金属高光色
$metal-shadow: #8c949d; // 金属阴影色
// base color
$blue:#324157;
$light-blue:#3A71A8;
$red:#C03639;
$pink: #E65D6E;
$green: #30B08F;
$tiffany: #4AB7BD;
$yellow:#FEC171;
$panGreen: #30B08F;
// 功能色(保持原有,但调整为金属质感)
$blue: mix($metal-dark, #324157, 30%);
$light-blue: mix($metal-light, #3A71A8, 30%);
$red: mix($metal-light, #C03639, 20%);
$pink: mix($metal-light, #E65D6E, 20%);
$green: mix($metal-light, #30B08F, 20%);
$tiffany: mix($metal-light, #4AB7BD, 20%);
$yellow: mix($metal-light, #FEC171, 20%);
$panGreen: mix($metal-light, #30B08F, 20%);
// 默认菜单主题风格
$base-menu-color:#bfcbd9;
$base-menu-color-active:#f4f4f5;
$base-menu-background:#304156;
$base-logo-title-color: #ffffff;
// 金属风格菜单主题
$base-menu-color: mix($metal-light, rgba(255, 255, 255, 0.7), 60%); // 菜单文字色
$base-menu-color-active: #ffffff; // 激活菜单文字色
$base-menu-background: linear-gradient(145deg, darken($metal-bg, 3%), $metal-bg); // 菜单背景
$base-logo-title-color: $metal-highlight; // Logo文字色
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
// 浅色金属菜单风格
$base-menu-light-color: mix($metal-dark, rgba(0, 0, 0, 0.7), 70%); // 浅色菜单文字色
$base-menu-light-background: linear-gradient(145deg, $metal-bg, lighten($metal-bg, 3%)); // 浅色菜单背景
$base-logo-light-title-color: $metal-dark; // 浅色Logo文字色
$base-sub-menu-background:#1f2d3d;
$base-sub-menu-hover:#001528;
// 子菜单样式
$base-sub-menu-background: darken($metal-bg, 5%); // 子菜单背景
$base-sub-menu-hover: linear-gradient(145deg, $metal-bg, $metal-dark); // 子菜单悬停背景
// 自定义暗色菜单风格
/**
$base-menu-color:hsla(0,0%,100%,.65);
$base-menu-color-active:#fff;
$base-menu-background:#001529;
$base-logo-title-color: #ffffff;
$base-sidebar-width: 200px; // 侧边栏宽度
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
// 导出变量供JS使用
$base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$base-sidebar-width: 200px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
menuColor: $base-menu-color;
menuLightColor: $base-menu-light-color;
@@ -43,9 +50,5 @@ $base-sidebar-width: 200px; // 侧边栏宽度
subMenuHover: $base-sub-menu-hover;
sideBarWidth: $base-sidebar-width;
logoTitleColor: $base-logo-title-color;
logoLightTitleColor: $base-logo-light-title-color;
// 导出金属主题基础色供全局使用
metalDark: $metal-dark;
metalLight: $metal-light;
metalBg: $metal-bg;
logoLightTitleColor: $base-logo-light-title-color
}

View File

@@ -93,9 +93,9 @@ export default {
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
line-height: 40px;
margin-left: 8px;
color: #fff;
color: #111;
.no-redirect {
color: #ddd;
cursor: text;
@@ -103,6 +103,6 @@ export default {
}
.el-breadcrumb__inner.is-link, .el-breadcrumb__inner a {
color: #fff;
color: #111;
}
</style>

View File

@@ -43,6 +43,6 @@ export default {
}
svg {
fill: #fff;
fill: #111;
}
</style>

View File

@@ -65,7 +65,7 @@ export default {
}
</script>
<style lang="scss" scoped>
<!-- <style lang="scss" scoped>
/* 工业风:石墨灰体系,深色背景适配。无蓝色。 */
.pagination-container {
background: transparent; /* 不要白底 */
@@ -93,9 +93,9 @@ export default {
/* sizes 选择器(下拉的输入框外观) */
.el-pagination__sizes .el-select .el-input .el-input__inner {
background: var(--pg-bg);
border-color: var(--pg-border);
color: var(--pg-text);
// background: var(--pg-bg);
// border-color: var(--pg-border);
// color: var(--pg-text);
}
.el-pagination__sizes .el-select .el-input .el-input__inner:hover {
background: var(--pg-bg-hover);
@@ -183,4 +183,4 @@ export default {
color: #FFFFFF;
}
}
</style>
</style> -->

View File

@@ -0,0 +1,489 @@
<template>
<div class="process-monitor">
<!-- 控制区 -->
<div class="control-bar">
<div class="chart-selector">
<label>图表视图</label>
<select v-model="currentChart" @change="handleChartChange">
<option v-for="chart in chartTypes" :key="chart.value" :value="chart.value">
{{ chart.label }}
</option>
</select>
</div>
<div class="connection-status" :class="{ connected: isConnected }">
连接状态{{ isConnected ? '已连接' : '连接中...' }}
</div>
</div>
<!-- 图表展示区 -->
<div class="chart-container">
<h3 class="chart-title">{{ currentChartLabel }}</h3>
<div ref="chartDom" class="chart"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'ProcessTrackMonitor',
data() {
return {
// WebSocket相关固定为track_measure
socket: null,
isConnected: false,
// 图表相关
chartTypes: [
{ value: 'entry', label: '入口数据监控' },
{ value: 'furnace', label: '炉温数据监控' },
{ value: 'coat', label: '涂层数据监控' },
{ value: 'exit', label: '出口数据监控' }
],
currentChart: 'entry', // 默认显示入口数据图表
chartInstance: null, // 当前图表实例
// 图表数据存储
chartData: {
entry: {
time: [],
tensionPorBr1: [],
tensionBr1Br2: [],
tensionBr2Br3: [],
stripSpeed: []
},
furnace: {
time: [],
phFurnaceTemperatureActual: [],
nof1FurnaceTemperatureActual: [],
nof1FurnaceTemperatureSet: []
},
coat: {
time: [],
avrCoatingWeightTop: [],
avrCoatingWeightBottom: [],
airKnifePressure: [],
stripSpeedTmExit: []
},
exit: {
time: [],
tensionBr8Br9: [],
tensionBr9Tr: [],
speedExitSection: []
}
},
maxDataPoints: 30 // 最多显示的数据点数量
};
},
computed: {
// 当前图表标题
currentChartLabel() {
const chart = this.chartTypes.find(item => item.value === this.currentChart);
return chart ? chart.label : '';
}
},
mounted() {
// 初始化图表
this.initChart();
// 建立WebSocket连接固定为track_measure
this.connectWebSocket();
// 监听窗口大小变化
window.addEventListener('resize', this.handleWindowResize);
},
unmounted() {
// 清理资源
this.disconnectWebSocket();
this.destroyChart();
window.removeEventListener('resize', this.handleWindowResize);
},
methods: {
// 初始化当前图表
initChart() {
// 先销毁已有实例
this.destroyChart();
// 初始化新图表
if (this.$refs.chartDom) {
this.chartInstance = echarts.init(this.$refs.chartDom);
this.chartInstance.setOption(this.getChartOption());
}
},
// 根据当前图表类型获取配置
getChartOption() {
const baseOption = {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chartData[this.currentChart].time,
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
}
};
// 不同图表的系列配置
switch (this.currentChart) {
case 'entry':
return {
...baseOption,
legend: {
data: ['入口张力1', '入口张力2', '入口张力3', '带钢速度'],
textStyle: { color: '#e0e0e0' }
},
series: [
{ name: '入口张力1', type: 'line', data: this.chartData.entry.tensionPorBr1, smooth: true, lineStyle: { width: 2 } },
{ name: '入口张力2', type: 'line', data: this.chartData.entry.tensionBr1Br2, smooth: true, lineStyle: { width: 2 } },
{ name: '入口张力3', type: 'line', data: this.chartData.entry.tensionBr2Br3, smooth: true, lineStyle: { width: 2 } },
{ name: '带钢速度', type: 'line', data: this.chartData.entry.stripSpeed, smooth: true, lineStyle: { width: 2 } }
]
};
case 'furnace':
return {
...baseOption,
legend: {
data: ['PH炉实际温度', 'NOF1炉实际温度', 'NOF1炉设定温度'],
textStyle: { color: '#e0e0e0' }
},
series: [
{ name: 'PH炉实际温度', type: 'line', data: this.chartData.furnace.phFurnaceTemperatureActual, smooth: true, lineStyle: { width: 2 } },
{ name: 'NOF1炉实际温度', type: 'line', data: this.chartData.furnace.nof1FurnaceTemperatureActual, smooth: true, lineStyle: { width: 2 } },
{ name: 'NOF1炉设定温度', type: 'line', data: this.chartData.furnace.nof1FurnaceTemperatureSet, smooth: true, lineStyle: { width: 2, type: 'dashed' } }
]
};
case 'coat':
return {
...baseOption,
legend: {
data: ['顶部平均涂层重量', '底部平均涂层重量', '气刀压力', '出口速度'],
textStyle: { color: '#e0e0e0' }
},
series: [
{ name: '顶部平均涂层重量', type: 'line', data: this.chartData.coat.avrCoatingWeightTop, smooth: true, lineStyle: { width: 2 } },
{ name: '底部平均涂层重量', type: 'line', data: this.chartData.coat.avrCoatingWeightBottom, smooth: true, lineStyle: { width: 2 } },
{ name: '气刀压力', type: 'line', data: this.chartData.coat.airKnifePressure, smooth: true, lineStyle: { width: 2 } },
{ name: '出口速度', type: 'line', data: this.chartData.coat.stripSpeedTmExit, smooth: true, lineStyle: { width: 2 } }
]
};
case 'exit':
return {
...baseOption,
legend: {
data: ['出口张力1', '出口张力2', '出口速度'],
textStyle: { color: '#e0e0e0' }
},
series: [
{ name: '出口张力1', type: 'line', data: this.chartData.exit.tensionBr8Br9, smooth: true, lineStyle: { width: 2 } },
{ name: '出口张力2', type: 'line', data: this.chartData.exit.tensionBr9Tr, smooth: true, lineStyle: { width: 2 } },
{ name: '出口速度', type: 'line', data: this.chartData.exit.speedExitSection, smooth: true, lineStyle: { width: 2 } }
]
};
default:
return baseOption;
}
},
// 处理窗口大小变化
handleWindowResize() {
if (this.chartInstance) {
this.chartInstance.resize();
}
},
// 销毁当前图表
destroyChart() {
if (this.chartInstance) {
this.chartInstance.dispose();
this.chartInstance = null;
}
},
// 建立WebSocket连接固定连接track_measure
connectWebSocket() {
// 先断开现有连接
this.disconnectWebSocket();
this.isConnected = false;
const url = 'ws://140.143.206.120:18081/websocket?type=track_measure';
try {
this.socket = new WebSocket(url);
this.socket.onopen = () => {
console.log('WebSocket连接已建立track_measure');
this.isConnected = true;
};
this.socket.onmessage = (event) => {
this.processData(event.data);
};
this.socket.onerror = (error) => {
console.error('WebSocket错误:', error);
this.isConnected = false;
};
this.socket.onclose = (event) => {
console.log(`WebSocket连接已关闭: ${event.code} - ${event.reason}`);
this.isConnected = false;
// 自动重连(非主动关闭)
if (event.code !== 1000) {
setTimeout(() => this.connectWebSocket(), 3000);
}
};
} catch (error) {
console.error('建立WebSocket连接失败:', error);
setTimeout(() => this.connectWebSocket(), 3000);
}
},
// 断开WebSocket连接
disconnectWebSocket() {
if (this.socket) {
this.socket.close(1000, '主动关闭');
this.socket = null;
}
},
// 处理图表切换
handleChartChange() {
this.initChart();
},
// 处理接收到的数据
processData(data) {
try {
const parsedData = JSON.parse(data);
this.processTrackMeasureData(parsedData);
} catch (error) {
console.error('数据解析错误:', error);
}
},
// 处理track_measure类型数据
processTrackMeasureData(data) {
// 获取当前时间标签(分:秒.毫秒)
const now = new Date();
const timeLabel = `${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}.${now.getMilliseconds().toString().slice(0, 2)}`;
// 处理入口数据
if (data.appMeasureEntryMessage) {
this.addDataPoint('entry', timeLabel, {
tensionPorBr1: data.appMeasureEntryMessage.tensionPorBr1,
tensionBr1Br2: data.appMeasureEntryMessage.tensionBr1Br2,
tensionBr2Br3: data.appMeasureEntryMessage.tensionBr2Br3,
stripSpeed: data.appMeasureEntryMessage.stripSpeed
});
}
// 处理炉温数据
if (data.appMeasureFurnaceMessage) {
this.addDataPoint('furnace', timeLabel, {
phFurnaceTemperatureActual: data.appMeasureFurnaceMessage.phFurnaceTemperatureActual,
nof1FurnaceTemperatureActual: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureActual,
nof1FurnaceTemperatureSet: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureSet
});
}
// 处理涂层数据
if (data.appMeasureCoatMessage) {
this.addDataPoint('coat', timeLabel, {
avrCoatingWeightTop: data.appMeasureCoatMessage.avrCoatingWeightTop,
avrCoatingWeightBottom: data.appMeasureCoatMessage.avrCoatingWeightBottom,
airKnifePressure: data.appMeasureCoatMessage.airKnifePressure,
stripSpeedTmExit: data.appMeasureCoatMessage.stripSpeedTmExit
});
}
// 处理出口数据
if (data.appMeasureExitMessage) {
this.addDataPoint('exit', timeLabel, {
tensionBr8Br9: data.appMeasureExitMessage.tensionBr8Br9,
tensionBr9Tr: data.appMeasureExitMessage.tensionBr9Tr,
speedExitSection: data.appMeasureExitMessage.speedExitSection
});
}
// 更新当前显示的图表
this.updateCurrentChart();
},
// 添加数据点到对应图表数据
addDataPoint(chartType, time, values) {
// 添加时间标签
this.chartData[chartType].time.push(time);
// 添加各项数据
Object.keys(values).forEach(key => {
if (this.chartData[chartType][key] !== undefined) {
this.chartData[chartType][key].push(values[key]);
}
});
// 保持数据点数量在maxDataPoints以内
if (this.chartData[chartType].time.length > this.maxDataPoints) {
this.chartData[chartType].time.shift();
Object.keys(values).forEach(key => {
if (this.chartData[chartType][key] !== undefined) {
this.chartData[chartType][key].shift();
}
});
}
},
// 更新当前显示的图表
updateCurrentChart() {
if (this.chartInstance) {
this.chartInstance.setOption({
xAxis: { data: this.chartData[this.currentChart].time },
series: this.getSeriesData()
});
}
},
// 获取当前图表的系列数据
getSeriesData() {
switch (this.currentChart) {
case 'entry':
return [
{ data: this.chartData.entry.tensionPorBr1 },
{ data: this.chartData.entry.tensionBr1Br2 },
{ data: this.chartData.entry.tensionBr2Br3 },
{ data: this.chartData.entry.stripSpeed }
];
case 'furnace':
return [
{ data: this.chartData.furnace.phFurnaceTemperatureActual },
{ data: this.chartData.furnace.nof1FurnaceTemperatureActual },
{ data: this.chartData.furnace.nof1FurnaceTemperatureSet }
];
case 'coat':
return [
{ data: this.chartData.coat.avrCoatingWeightTop },
{ data: this.chartData.coat.avrCoatingWeightBottom },
{ data: this.chartData.coat.airKnifePressure },
{ data: this.chartData.coat.stripSpeedTmExit }
];
case 'exit':
return [
{ data: this.chartData.exit.tensionBr8Br9 },
{ data: this.chartData.exit.tensionBr9Tr },
{ data: this.chartData.exit.speedExitSection }
];
default:
return [];
}
}
}
};
</script>
<style scoped>
.process-monitor {
padding: 20px;
font-family: Arial, sans-serif;
background-color: #3f4449;
color: #e0e0e0;
}
.control-bar {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.chart-selector {
padding: 10px;
background-color: #4a4f55;
border-radius: 4px;
display: flex;
align-items: center;
}
.chart-selector label {
margin-right: 10px;
color: #e0e0e0;
}
.chart-selector select {
padding: 5px 10px;
border: 1px solid #5d6268;
border-radius: 4px;
background-color: #555a60;
color: #e0e0e0;
cursor: pointer;
}
.connection-status {
padding: 8px 10px;
border-radius: 4px;
background-color: #4a4f55;
color: #ffd700;
margin-left: auto;
}
.connection-status.connected {
color: #32cd32;
}
.chart-container {
background-color: #4a4f55;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
padding: 15px;
}
.chart-title {
margin-top: 0;
color: #f0f0f0;
font-size: 18px;
border-bottom: 1px solid #5d6268;
padding-bottom: 10px;
margin-bottom: 15px;
}
.chart {
width: 100%;
height: 400px; /* 增大图表高度提升可读性 */
}
/* 响应式调整 */
@media (max-width: 768px) {
.control-bar {
flex-direction: column;
align-items: flex-start;
}
.connection-status {
margin-left: 0;
width: 100%;
text-align: center;
}
.chart {
height: 300px;
}
}
</style>

View File

@@ -30,7 +30,7 @@ export default {
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
background-color: #3f4449;
// background-color: #3f4449;
width: 100%;
position: relative;
overflow: hidden;

View File

@@ -104,7 +104,7 @@ export default {
overflow: hidden;
position: relative;
// 金属质感渐变背景
background: #454c51;
// background: #454c51;
border-bottom: 1px solid #8d939b;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1),
0 1px 1px rgba(255, 255, 255, 0.08) inset;
@@ -156,7 +156,7 @@ export default {
height: 100%;
font-size: 18px;
// 金属风格文字色
color: #ddd;
color: #111;
vertical-align: text-bottom;
transition: all 0.2s ease;

View File

@@ -3,11 +3,11 @@
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu
active-text-color="#fff"
active-text-color="#000"
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
text-color="#111"
:unique-opened="true"
:collapse-transition="false"
mode="vertical"

View File

@@ -242,7 +242,7 @@ export default {
height: 34px;
width: 100%;
// 金属浅色渐变背景(直接写死渐变值)
background: #454c51;
// background: #454c51;
border-bottom: 1px solid #a0a6ad;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.05) inset;
@@ -254,9 +254,9 @@ export default {
height: 26px;
line-height: 26px;
border: 1px solid #a0a6ad;
color: #fff;
// color: #fff;
// 标签金属渐变背景
background: #454c51;
// background: #454c51;
padding: 0 8px;
font-size: 12px;
margin-left: 5px;

View File

@@ -76,7 +76,6 @@ export default {
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;

View File

@@ -7,7 +7,7 @@ import Element from 'element-ui'
import './assets/styles/element-variables.scss'
import '@/assets/styles/index.scss' // global css
import '@/assets/styles/ruoyi.scss' // ruoyi css
// import '@/assets/styles/ruoyi.scss' // ruoyi css
import App from './App'
import store from './store'
import router from './router'

View File

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

View File

@@ -47,6 +47,17 @@
/>
</el-card>
</el-col>
<el-col :span="24">
<el-card>
<div slot="header"><span>过程跟踪</span></div>
<TrackMeasure
v-loading="measureLoading"
:columns="measureColumns"
:data="measureData"
tableHeight="300px"
/>
</el-card>
</el-col>
</el-row>
</div>
</template>
@@ -59,10 +70,11 @@ import MiniTable from "./components/MiniTable.vue";
import { getLogDataPage } from "@/api/l2/log";
import { getRollHistorytList } from '@/api/l2/roller'
import { listPlan } from "@/api/l2/plan";
import TrackMeasure from "@/components/TrackMeasure/index.vue";
export default {
name: "Index",
components: { CurrentTime, HomeMain, MiniTable },
components: { CurrentTime, HomeMain, MiniTable, TrackMeasure },
data() {
return {
featureCards: [

View File

@@ -44,8 +44,8 @@
<Pagination
v-show="pagination.total>0"
:total="pagination.total"
v-model:page="pagination.currentPage"
v-model:limit="pagination.pageSize"
:page.sync="pagination.currentPage"
:limit.sync="pagination.pageSize"
@pagination="getList"
/>
</div>
@@ -175,7 +175,7 @@ export default {
// 从父组件调用的查询方法
getList(params) {
console.log('接收到父组件的搜索参数:', params)
this.pagination.currentPage = 1
// this.pagination.currentPage = 1
this.fetchData()
},

View File

@@ -31,7 +31,7 @@
<el-table-column prop="rolledLength" label="长度" width="70" />
<el-table-column prop="rolledWeight" label="重量" width="70" />
<el-table-column prop="rolledCount" label="轧制数量" width="75" />
<el-table-column prop="instalTime" label="装机时间" width="133" />
<el-table-column prop="instalTime" label="装机时间" width="160" />
</el-table>
</div>
</template>

View File

@@ -0,0 +1,637 @@
<template>
<div class="socket-monitor">
<!-- 类型选择器 -->
<div class="type-selector">
<label>数据类型</label>
<select v-model="currentType" @change="handleTypeChange">
<option v-for="type in types" :key="type" :value="type">{{ type }}</option>
</select>
</div>
<!-- 连接状态指示 -->
<div class="connection-status" :class="{ connected: isConnected }">
连接状态{{ isConnected ? '已连接' : '连接中...' }}
</div>
<!-- 图表区域 - 仅在track_measure类型时显示 -->
<div v-if="currentType === 'track_measure'" class="charts-container">
<div class="chart-group">
<h3>入口数据监控</h3>
<div ref="entryChart" class="chart"></div>
</div>
<div class="chart-group">
<h3>炉温数据监控</h3>
<div ref="furnaceChart" class="chart"></div>
</div>
<div class="chart-group">
<h3>涂层数据监控</h3>
<div ref="coatChart" class="chart"></div>
</div>
<div class="chart-group">
<h3>出口数据监控</h3>
<div ref="exitChart" class="chart"></div>
</div>
</div>
<!-- 其他类型提示 -->
<div v-else class="other-type-info">
选择 "track_measure" 类型以查看数据图表
</div>
<!-- 原始数据展示区 -->
<div class="raw-data">
<h3>原始数据</h3>
<pre>{{ formattedRawData }}</pre>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'SocketMonitor',
data() {
return {
socket: null,
types: [
'alarm',
'track_position',
'calc_setup_result',
'track_measure',
'track_signal',
'track_matmap'
],
currentType: 'track_measure',
isConnected: false,
rawData: null,
// 图表实例
entryChart: null,
furnaceChart: null,
coatChart: null,
exitChart: null,
// 图表数据存储
chartData: {
entry: {
time: [],
tensionPorBr1: [],
tensionBr1Br2: [],
tensionBr2Br3: [],
stripSpeed: []
},
furnace: {
time: [],
phFurnaceTemperatureActual: [],
nof1FurnaceTemperatureActual: [],
nof1FurnaceTemperatureSet: []
},
coat: {
time: [],
avrCoatingWeightTop: [],
avrCoatingWeightBottom: [],
airKnifePressure: [],
stripSpeedTmExit: []
},
exit: {
time: [],
tensionBr8Br9: [],
tensionBr9Tr: [],
speedExitSection: []
}
},
// 最多显示的数据点数量
maxDataPoints: 30
};
},
computed: {
formattedRawData() {
if (!this.rawData) return '等待接收数据...';
try {
return JSON.stringify(JSON.parse(this.rawData), null, 2);
} catch (e) {
return this.rawData;
}
}
},
mounted() {
// 初始化为track_measure时直接初始化图表
if (this.currentType === 'track_measure') {
this.initCharts();
}
this.connectWebSocket();
window.addEventListener('resize', this.handleWindowResize);
},
updated() {
// 当组件更新且类型为track_measure时确保图表已初始化
if (this.currentType === 'track_measure' && !this.entryChart) {
this.initCharts();
}
},
unmounted() {
this.disconnectWebSocket();
this.destroyCharts();
window.removeEventListener('resize', this.handleWindowResize);
},
methods: {
// 初始化所有图表
initCharts() {
// 先销毁可能存在的旧实例
this.destroyCharts();
// 确保DOM元素存在再初始化
if (this.$refs.entryChart) {
this.entryChart = echarts.init(this.$refs.entryChart);
this.entryChart.setOption(this.getEntryChartOption());
}
if (this.$refs.furnaceChart) {
this.furnaceChart = echarts.init(this.$refs.furnaceChart);
this.furnaceChart.setOption(this.getFurnaceChartOption());
}
if (this.$refs.coatChart) {
this.coatChart = echarts.init(this.$refs.coatChart);
this.coatChart.setOption(this.getCoatChartOption());
}
if (this.$refs.exitChart) {
this.exitChart = echarts.init(this.$refs.exitChart);
this.exitChart.setOption(this.getExitChartOption());
}
},
// 入口数据图表配置
getEntryChartOption() {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
legend: {
data: ['入口张力1', '入口张力2', '入口张力3', '带钢速度'],
textStyle: { color: '#e0e0e0' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
},
series: [
{ name: '入口张力1', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '入口张力2', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '入口张力3', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '带钢速度', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } }
]
};
},
// 炉温数据图表配置
getFurnaceChartOption() {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
legend: {
data: ['PH炉实际温度', 'NOF1炉实际温度', 'NOF1炉设定温度'],
textStyle: { color: '#e0e0e0' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
},
series: [
{ name: 'PH炉实际温度', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: 'NOF1炉实际温度', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: 'NOF1炉设定温度', type: 'line', data: [], smooth: true, lineStyle: { width: 2, type: 'dashed' } }
]
};
},
// 涂层数据图表配置
getCoatChartOption() {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
legend: {
data: ['顶部平均涂层重量', '底部平均涂层重量', '气刀压力', '出口速度'],
textStyle: { color: '#e0e0e0' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
},
series: [
{ name: '顶部平均涂层重量', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '底部平均涂层重量', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '气刀压力', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '出口速度', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } }
]
};
},
// 出口数据图表配置
getExitChartOption() {
return {
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
legend: {
data: ['出口张力1', '出口张力2', '出口速度'],
textStyle: { color: '#e0e0e0' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#666' } },
axisLabel: { color: '#b0b0b0' },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.1)' } }
},
series: [
{ name: '出口张力1', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '出口张力2', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } },
{ name: '出口速度', type: 'line', data: [], smooth: true, lineStyle: { width: 2 } }
]
};
},
handleWindowResize() {
if (this.entryChart) this.entryChart.resize();
if (this.furnaceChart) this.furnaceChart.resize();
if (this.coatChart) this.coatChart.resize();
if (this.exitChart) this.exitChart.resize();
},
destroyCharts() {
if (this.entryChart) {
this.entryChart.dispose();
this.entryChart = null;
}
if (this.furnaceChart) {
this.furnaceChart.dispose();
this.furnaceChart = null;
}
if (this.coatChart) {
this.coatChart.dispose();
this.coatChart = null;
}
if (this.exitChart) {
this.exitChart.dispose();
this.exitChart = null;
}
},
connectWebSocket() {
this.disconnectWebSocket();
this.isConnected = false;
const url = `ws://140.143.206.120:18081/websocket?type=${this.currentType}`;
try {
this.socket = new WebSocket(url);
this.socket.onopen = () => {
console.log('WebSocket连接已建立');
this.isConnected = true;
};
this.socket.onmessage = (event) => {
this.rawData = event.data;
this.processData(event.data);
};
this.socket.onerror = (error) => {
console.error('WebSocket错误:', error);
this.isConnected = false;
};
this.socket.onclose = (event) => {
console.log(`WebSocket连接已关闭: ${event.code} - ${event.reason}`);
this.isConnected = false;
if (event.code !== 1000) {
setTimeout(() => this.connectWebSocket(), 3000);
}
};
} catch (error) {
console.error('建立WebSocket连接失败:', error);
setTimeout(() => this.connectWebSocket(), 3000);
}
},
disconnectWebSocket() {
if (this.socket) {
this.socket.close(1000, '主动关闭');
this.socket = null;
}
},
// 修复核心:切换类型时重新初始化图表
handleTypeChange() {
this.rawData = null;
this.resetChartData();
// 如果切换到track_measure类型需要重新初始化图表
if (this.currentType === 'track_measure') {
// 确保DOM更新后再初始化图表使用$nextTick
this.$nextTick(() => {
this.initCharts();
});
} else {
// 切换到其他类型时销毁图表
this.destroyCharts();
}
this.connectWebSocket();
},
resetChartData() {
this.chartData = {
entry: { time: [], tensionPorBr1: [], tensionBr1Br2: [], tensionBr2Br3: [], stripSpeed: [] },
furnace: { time: [], phFurnaceTemperatureActual: [], nof1FurnaceTemperatureActual: [], nof1FurnaceTemperatureSet: [] },
coat: { time: [], avrCoatingWeightTop: [], avrCoatingWeightBottom: [], airKnifePressure: [], stripSpeedTmExit: [] },
exit: { time: [], tensionBr8Br9: [], tensionBr9Tr: [], speedExitSection: [] }
};
this.updateCharts();
},
processData(data) {
try {
const parsedData = JSON.parse(data);
if (this.currentType === 'track_measure') {
this.processTrackMeasureData(parsedData);
}
} catch (error) {
console.error('数据解析错误:', error);
}
},
processTrackMeasureData(data) {
const now = new Date();
const timeLabel = `${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}.${now.getMilliseconds().toString().slice(0, 2)}`;
if (data.appMeasureEntryMessage) {
this.addDataPoint('entry', timeLabel, {
tensionPorBr1: data.appMeasureEntryMessage.tensionPorBr1,
tensionBr1Br2: data.appMeasureEntryMessage.tensionBr1Br2,
tensionBr2Br3: data.appMeasureEntryMessage.tensionBr2Br3,
stripSpeed: data.appMeasureEntryMessage.stripSpeed
});
}
if (data.appMeasureFurnaceMessage) {
this.addDataPoint('furnace', timeLabel, {
phFurnaceTemperatureActual: data.appMeasureFurnaceMessage.phFurnaceTemperatureActual,
nof1FurnaceTemperatureActual: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureActual,
nof1FurnaceTemperatureSet: data.appMeasureFurnaceMessage.nof1FurnaceTemperatureSet
});
}
if (data.appMeasureCoatMessage) {
this.addDataPoint('coat', timeLabel, {
avrCoatingWeightTop: data.appMeasureCoatMessage.avrCoatingWeightTop,
avrCoatingWeightBottom: data.appMeasureCoatMessage.avrCoatingWeightBottom,
airKnifePressure: data.appMeasureCoatMessage.airKnifePressure,
stripSpeedTmExit: data.appMeasureCoatMessage.stripSpeedTmExit
});
}
if (data.appMeasureExitMessage) {
this.addDataPoint('exit', timeLabel, {
tensionBr8Br9: data.appMeasureExitMessage.tensionBr8Br9,
tensionBr9Tr: data.appMeasureExitMessage.tensionBr9Tr,
speedExitSection: data.appMeasureExitMessage.speedExitSection
});
}
this.updateCharts();
},
addDataPoint(chartType, time, values) {
this.chartData[chartType].time.push(time);
Object.keys(values).forEach(key => {
if (this.chartData[chartType][key] !== undefined) {
this.chartData[chartType][key].push(values[key]);
}
});
if (this.chartData[chartType].time.length > this.maxDataPoints) {
this.chartData[chartType].time.shift();
Object.keys(values).forEach(key => {
if (this.chartData[chartType][key] !== undefined) {
this.chartData[chartType][key].shift();
}
});
}
},
updateCharts() {
if (this.entryChart) {
this.entryChart.setOption({
xAxis: { data: this.chartData.entry.time },
series: [
{ data: this.chartData.entry.tensionPorBr1 },
{ data: this.chartData.entry.tensionBr1Br2 },
{ data: this.chartData.entry.tensionBr2Br3 },
{ data: this.chartData.entry.stripSpeed }
]
});
}
if (this.furnaceChart) {
this.furnaceChart.setOption({
xAxis: { data: this.chartData.furnace.time },
series: [
{ data: this.chartData.furnace.phFurnaceTemperatureActual },
{ data: this.chartData.furnace.nof1FurnaceTemperatureActual },
{ data: this.chartData.furnace.nof1FurnaceTemperatureSet }
]
});
}
if (this.coatChart) {
this.coatChart.setOption({
xAxis: { data: this.chartData.coat.time },
series: [
{ data: this.chartData.coat.avrCoatingWeightTop },
{ data: this.chartData.coat.avrCoatingWeightBottom },
{ data: this.chartData.coat.airKnifePressure },
{ data: this.chartData.coat.stripSpeedTmExit }
]
});
}
if (this.exitChart) {
this.exitChart.setOption({
xAxis: { data: this.chartData.exit.time },
series: [
{ data: this.chartData.exit.tensionBr8Br9 },
{ data: this.chartData.exit.tensionBr9Tr },
{ data: this.chartData.exit.speedExitSection }
]
});
}
}
}
};
</script>
<style scoped>
/* 样式保持不变 */
.socket-monitor {
padding: 20px;
max-width: 1400px;
margin: 0 auto;
font-family: Arial, sans-serif;
background-color: #3f4449;
color: #e0e0e0;
}
.type-selector {
margin-bottom: 15px;
padding: 10px;
background-color: #4a4f55;
border-radius: 4px;
}
.type-selector select {
margin-left: 10px;
padding: 5px 10px;
border: 1px solid #5d6268;
border-radius: 4px;
background-color: #555a60;
color: #e0e0e0;
}
.connection-status {
margin-bottom: 20px;
padding: 8px 10px;
border-radius: 4px;
background-color: #4a4f55;
color: #ffd700;
}
.connection-status.connected {
background-color: #4a4f55;
color: #32cd32;
}
.charts-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(600px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.chart-group {
background-color: #4a4f55;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
padding: 15px;
}
.chart-group h3 {
margin-top: 0;
color: #f0f0f0;
font-size: 16px;
border-bottom: 1px solid #5d6268;
padding-bottom: 8px;
margin-bottom: 15px;
}
.chart {
width: 100%;
height: 300px;
}
.other-type-info {
text-align: center;
padding: 50px;
background-color: #4a4f55;
border-radius: 6px;
color: #b0b0b0;
margin-bottom: 30px;
}
.raw-data {
background-color: #4a4f55;
border-radius: 6px;
padding: 15px;
max-height: 300px;
overflow-y: auto;
}
.raw-data h3 {
margin-top: 0;
color: #f0f0f0;
font-size: 16px;
margin-bottom: 10px;
border-bottom: 1px solid #5d6268;
padding-bottom: 8px;
}
.raw-data pre {
margin: 0;
font-family: monospace;
color: #b0b0b0;
white-space: pre-wrap;
word-wrap: break-word;
}
.raw-data::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.raw-data::-webkit-scrollbar-track {
background: #555a60;
border-radius: 4px;
}
.raw-data::-webkit-scrollbar-thumb {
background: #6d7278;
border-radius: 4px;
}
.raw-data::-webkit-scrollbar-thumb:hover {
background: #858a90;
}
</style>

View File

@@ -39,7 +39,16 @@ module.exports = {
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
// 新增WebSocket代理配置
// '/ws-api': { // 匹配前端WebSocket连接的路径如ws://localhost:80/ws-api
// target: '140.143.206.120:8089', // 目标WebSocket服务地址
// ws: true, // 启用WebSocket代理
// changeOrigin: true, // 改变请求源,解决跨域问题
// pathRewrite: {
// '^/ws-api': '' // 如果目标服务不需要路径前缀,可移除
// }
// }
},
disableHostCheck: true
},