Commit 5d435893 authored by liuzhaoh's avatar liuzhaoh

Merge branch 'dev' of http://app.bmetech.com/liuzhaohui/dctomproject into dev

parents 1965f46c 19159cb8
...@@ -19,3 +19,10 @@ export function getExceptionMonitor() { ...@@ -19,3 +19,10 @@ export function getExceptionMonitor() {
method: "get", method: "get",
}); });
} }
export function getDusterAlarm() {
return request({
url: "/api/home/duster/alarm",
method: "get",
});
}
...@@ -7,15 +7,87 @@ export function getDusterLeakNum() { ...@@ -7,15 +7,87 @@ export function getDusterLeakNum() {
} }
export function getHealthPercent() { export function getHealthPercent() {
return request({
url: "/getHealthPercent",
method: "get",
});
}
export function getCloseLoopNum() {
return request({
url: "/getCloseLoopNum",
method: "get",
});
}
export function getProductionLine() {
return request({
url: "/transaction/getProductionLine",
method: "get",
});
}
export function getDusterList(params) {
return request({
url: "/getDusterList",
method: "get",
params,
});
}
export function getVisDusterList(params) {
return request({ return request({
url: "/getHealthPercent", url: "/queryVisDusterList",
method: "get", method: "get",
params,
});
}
export function postAddDuster(params) {
return request({
url: "/addDuster",
method: "post",
data: params,
});
}
export function postUpdateDuster(params) {
return request({
url: "/updateDuster",
method: "post",
data: params,
});
}
export function getCompartAllocation(params) {
return request({
url: "/queryCompartAllocation",
method: "get",
params,
});
}
export function postAddCompartAllocation(params) {
return request({
url: "/addCompartAllocation",
method: "post",
data: params,
});
}
export function postAddValveInfo(params) {
return request({
url: "/addValveInfo",
method: "post",
data: params,
}); });
} }
export function getCloseLoopNum() { export function getValveAllocation(params) {
return request({ return request({
url: "/getCloseLoopNum", url: "/queryValveAllocation",
method: "get", method: "get",
params,
}); });
} }
\ No newline at end of file
...@@ -2,15 +2,17 @@ import { createWebHistory, createRouter } from 'vue-router' ...@@ -2,15 +2,17 @@ import { createWebHistory, createRouter } from 'vue-router'
import Dashboard from '../views/dashboard/index.vue' import Dashboard from '../views/dashboard/index.vue'
import DustOverview from '../views/dustOverview/index.vue' import DustOverview from '../views/dustOverview/index.vue'
import AboutView from '../views/AboutView.vue' import AboutView from '../views/AboutView/AboutView.vue'
import CollectorList from '../views/collectorList/collectorList.vue' import CollectorList from '../views/collectorList/collectorList.vue'
import User from '../views/user.vue' import User from '../views/user.vue'
import Layout from '../layout/index.vue' import Layout from '../layout/index.vue'
import Login from '../views/login/index.vue' import Login from '../views/login/index.vue'
import equipmentManagement from '../views/equipmentManagement/index.vue' import equipmentManagement from '../views/equipmentManagement/index.vue'
import suspendManagement from '../views/equipmentManagement/suspendManagement/suspendManagement.vue'
import dustMonitoring from '../views/dustMonitoring/index.vue' import dustMonitoring from '../views/dustMonitoring/index.vue'
import bagMonitoring from '../views/dustMonitoring/bag-monitoring.vue' import bagMonitoring from '../views/dustMonitoring/bag-monitoring.vue'
import myAgency from '@/views/closeManage/myAgency.vue'; import myAgency from '@/views/closeManage/myAgency.vue';
import myDone from '@/views/closeManage/myDone.vue'; import myDone from '@/views/closeManage/myDone.vue';
const routes = [ const routes = [
...@@ -31,8 +33,19 @@ const routes = [ ...@@ -31,8 +33,19 @@ const routes = [
}, },
{ {
path: '/device-management', path: '/device-management',
component: equipmentManagement,
meta: { title: '设备管理' }, meta: { title: '设备管理' },
children: [
{
path: '/management/device-management',
component: equipmentManagement,
meta: { title: '设备管理' },
},
{
path: '/management/suspend-management',
component: suspendManagement,
meta: { title: '挂起设备管理' },
},
]
}, },
{ {
path: '/monitor', path: '/monitor',
......
<template>
<div>about</div>
</template>
\ No newline at end of file
<template>
<div class="page-container collectorList">
<div class="content-box">
<div class="search">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="事件名称">
<el-input
v-model="formInline.eventName"
placeholder="请输入事件名称"
style="width: 200px"
clearable
/>
</el-form-item>
<el-form-item label="发生位置">
<el-input
v-model="formInline.position"
placeholder="请输入发生位置"
style="width: 200px"
clearable
/>
</el-form-item>
<el-form-item label="除尘器名称">
<el-input
v-model="formInline.deviceName"
placeholder="请输入除尘器名称"
style="width: 200px"
clearable
/>
</el-form-item>
<el-form-item label="设备类型">
<el-select v-model="formInline.type" style="width: 200px">
<el-option
v-for="i in dustList.list"
:key="i"
:label="`${i.deviceName}`"
:value="i.deviceNo"
/>
</el-select>
</el-form-item>
<el-form-item label="告警时间">
<el-date-picker
v-model="formInline.date"
type="datetimerange"
range-separator="~"
start-placeholder="开始时间"
end-placeholder="结束时间"
:teleported="false"
/>
</el-form-item>
<el-form-item>
<el-button type="default" class="default-btn" @click="onSubmit"
>重置</el-button
>
<el-button type="primary" class="search-btn" @click="onSubmit"
>查询</el-button
>
<el-button
type="success"
style="width: 140px"
class="add-btn"
@click="openRound()"
>挂起设备</el-button
>
</el-form-item>
<br />
<el-form-item>
<el-radio-group v-model="formInline.warnType">
<el-radio value="1">挂起期间告警</el-radio>
<el-radio value="2">非挂起期间告警</el-radio>
<el-radio value="3">全部告警</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<div class="table-box">
<common-table
:data="tableData.list"
:columns="tableColumns"
:default-page-size="10"
@pagination-change="handlePaginationChange"
:pagination-texts="{
total: '共',
sizeChange: '条/页',
prev: '前一页',
next: '后一页',
jumper: '跳至',
}"
>
<template #index="{ $index }">
{{ getIndex($index) }}
</template>
<!-- <template #deviceName="{ row }">
<span class="health-score" @dblclick="openDialog(row.deviceName)">{{
row.deviceName
}}</span>
</template> -->
<!-- <template #operation="{ row }">
<span class="view-btn" @click="handleView(row)">详情</span>
<span class="edit-btn" @click="handleEdit(row)">编辑</span>
</template> -->
</common-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed, reactive } from "vue";
import CommonTable from "@/components/commonTable/index.vue";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
const formInline = ref({
eventName: "",
deviceName: "",
position: "",
type: "",
date: "",
warnType: "3",
});
const currentPage = ref(1);
const pageSize = ref(10);
const tableColumns = ref([
{
prop: "index",
label: "序号",
width: "5%",
},
{
prop: "deviceName",
label: "事件名称",
width: "9%",
},
{
prop: "compart",
label: "发生位置",
width: "9%",
},
{
prop: "position",
label: "设备类型",
width: "9%",
},
{
prop: "changeDateRemind",
label: "告警指标",
width: "9%",
},
{
prop: "changeDate",
label: "监测值",
width: "9%",
},
{
prop: "changePeo",
label: "告警时间",
width: "9%",
},
{
prop: "ownerdeviceName",
label: "是否挂起期间告警",
width: "9%",
},
{
prop: "lastAlarmTime",
label: "操作",
width: "10%",
},
]);
const tableData = reactive({
list: [
{
deviceName: "1#除尘器",
compart: "1234567890",
position: "转炉",
changeDateRemind: "xx",
changeDate: "xx",
changePeo: "xx",
ownerdeviceName: "xx",
lastAlarmTime: "xx",
changeRound: "xx",
},
],
});
const dustList = reactive({
list: [],
});
const getDustList = () => {
dustList.list = [
{
deviceName: "1#除尘器",
deviceNo: "11111",
},
{
deviceName: "2#除尘器",
deviceNo: "22222",
},
{
deviceName: "3#除尘器",
deviceNo: "333333",
},
];
};
getDustList();
const getIndex = (index) => {
return (currentPage.value - 1) * pageSize.value + index + 1;
};
const handlePaginationChange = (pagination) => {
currentPage.value = pagination.currentPage;
pageSize.value = pagination.pageSize;
console.log("分页变化", pagination);
};
const onSubmit = () => {
console.log("submit!", formInline.value);
};
const openRound = () => {
router.push({ path: "/management/suspend-management" });
};
onMounted(async () => {});
onBeforeUnmount(() => {});
</script>
<style lang="scss" scoped>
.collectorList {
width: 100%;
height: calc(100% - 14px);
box-sizing: border-box;
:deep(.el-input--small) {
width: 100%;
}
.content-box {
margin-top: 24px;
.search {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-box {
width: 100%;
height: calc(100vh - 400px);
}
}
.default-btn {
width: 85px;
}
.search-btn {
width: 85px;
background: #2182a0;
border: 1px solid #2182a0;
}
.add-btn {
width: 85px;
}
.health-score {
color: #027ffc;
cursor: pointer;
display: block;
width: 100%;
}
.status-matrix {
width: fit-content;
display: flex;
padding: 10px;
box-sizing: border-box;
flex-direction: column;
align-items: flex-start;
gap: 6px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.matrix-row {
display: flex;
gap: 6px;
justify-content: flex-start;
}
.status-dot {
width: 14px;
height: 14px;
border-radius: 50%;
&:hover {
cursor: pointer;
transform: scale(1.2);
}
}
.status-normal {
background-color: #67c23a; // 绿色
}
.status-warning {
background-color: #e6a23c; // 橙色
}
.status-error {
background-color: #f56c6c; // 红色
}
}
.view-btn {
margin-right: 8px;
}
.dialog-footer {
display: flex;
justify-content: center;
gap: 12px;
}
:deep(.el-dialog__body) {
padding: 20px;
}
.distribution-table {
margin-top: 20px;
border-top: 1px solid #ebeef5;
padding-top: 20px;
}
.table-title {
font-size: 14px;
color: #2182a0;
margin-bottom: 16px;
font-weight: 500;
}
:deep(.el-input-number.el-input-number--small) {
width: 130px;
}
:deep(.distribution-table .el-table--border .el-table__cell) {
border-right: 1px solid #ebeef5 !important;
}
.valve-setting {
.setting-row {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 20px;
.input-group {
display: flex;
align-items: center;
gap: 8px;
span {
white-space: nowrap;
color: #606266;
}
}
}
}
.valve-distribution-grid {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
background: #f5f7fa;
border-radius: 4px;
.valve-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.valve-cell {
width: 41px;
background: white;
padding: 4px;
border-radius: 4px;
text-align: center;
border: 1px solid #dcdfe6;
.cell-index {
font-size: 12px;
color: #909399;
margin-bottom: 8px;
}
.cell-value {
:deep(.el-input-number) {
width: 100px;
}
}
}
}
.readonly-value {
font-size: 14px;
color: #606266;
line-height: 32px;
padding: 0 12px;
}
.distribution-warning {
display: inline-block;
font-size: 13px;
margin-left: 12px;
padding: 2px 8px;
border-radius: 4px;
&.warning-more {
color: #e6a23c;
background-color: #fdf6ec;
}
&.warning-less {
color: #f56c6c;
background-color: #fef0f0;
}
}
}
</style>
...@@ -2,18 +2,8 @@ ...@@ -2,18 +2,8 @@
<div class="my-agency"> <div class="my-agency">
<el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="事件名称:"> <el-form-item label="事件名称:">
<el-select v-model="formInline.eventNameId" <el-input v-model="formInline.eventName">
placeholder="请选择" </el-input>
style="width: 280px"
>
<el-option
v-for="(item, index) in basicConfiguration.ticketEventName"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="发生位置:"> <el-form-item label="发生位置:">
<el-input v-model="formInline.keyword" placeholder="请输入"></el-input> <el-input v-model="formInline.keyword" placeholder="请输入"></el-input>
...@@ -39,8 +29,8 @@ ...@@ -39,8 +29,8 @@
<el-option <el-option
v-for="(item, index) in basicConfiguration.deviceList" v-for="(item, index) in basicConfiguration.deviceList"
index="item.id" index="item.id"
:label="item.name" :label="item.desc"
:value="item.id" :value="item.code"
> >
</el-option> </el-option>
</el-select> </el-select>
...@@ -389,14 +379,14 @@ ...@@ -389,14 +379,14 @@
<div class="demo-image__preview"> <div class="demo-image__preview">
<div <div
class="image-preview" class="image-preview"
v-for="(item, index) in alarmImags" v-for="(item, index) in alarmImg"
:key="index" :key="index"
> >
<el-image <el-image
style="width: 100px; height: 100px" style="width: 100px; height: 100px"
:lazy="true" :lazy="true"
:src="item" :src="item"
:preview-src-list="alarmImags" :preview-src-list="alarmImg"
></el-image> ></el-image>
</div> </div>
</div> </div>
...@@ -614,7 +604,7 @@ import { storeToRefs } from 'pinia' ...@@ -614,7 +604,7 @@ import { storeToRefs } from 'pinia'
import { useUsersStore } from "@/pinia/user.js"; import { useUsersStore } from "@/pinia/user.js";
const { functionAuthority } = storeToRefs(useUsersStore()); const { functionAuthority } = storeToRefs(useUsersStore());
const formInline = ref({ const formInline = ref({
eventNameId: '', eventName: '',
keyword: '', keyword: '',
warnType: '', warnType: '',
branchFactoryIds: '', branchFactoryIds: '',
...@@ -779,7 +769,7 @@ const onSearch = ()=> { ...@@ -779,7 +769,7 @@ const onSearch = ()=> {
const onReset =()=> { const onReset =()=> {
currentPage.value = 1; currentPage.value = 1;
pageSize.value = 20; pageSize.value = 20;
formInline.value.eventNameId = ''; formInline.value.eventName = '';
formInline.value.keyword = ''; formInline.value.keyword = '';
formInline.value.branchFactoryIds = ''; formInline.value.branchFactoryIds = '';
formInline.value.deviceType = ''; formInline.value.deviceType = '';
...@@ -974,13 +964,19 @@ const getWarnAndTicketConfigMap = ()=> { ...@@ -974,13 +964,19 @@ const getWarnAndTicketConfigMap = ()=> {
} }
getDataFun(url,params).then(res => { getDataFun(url,params).then(res => {
if (res && res.code === 1) { if (res && res.code === 1) {
const { ticketEventName, deviceType} = res.data; const { ticketEventName } = res.data;
basicConfiguration.ticketEventName = basicConfiguration.ticketEventName.concat(ticketEventName); basicConfiguration.ticketEventName = basicConfiguration.ticketEventName.concat(ticketEventName);
basicConfiguration.deviceList = deviceType;
} }
}); });
}; };
const getDeviceType =() => {
const url = '/alarm/getDeviceType';
getData(url).then(res=>{
basicConfiguration.deviceList = res.data;
});
}
let realBtn = ''; let realBtn = '';
const searchData =()=> { const searchData =()=> {
...@@ -1004,7 +1000,7 @@ const searchData =()=> { ...@@ -1004,7 +1000,7 @@ const searchData =()=> {
const getTableData = ()=> { const getTableData = ()=> {
let keyWord = formInline.value.keyword?.replace(/#/g, '%23'); let keyWord = formInline.value.keyword?.replace(/#/g, '%23');
const params = { const params = {
eventNameId: formInline.value.eventNameId, eventName: formInline.value.eventName,
warnType: formInline.value.warnType, warnType: formInline.value.warnType,
createStartTime: formInline.value.createTime[0], createStartTime: formInline.value.createTime[0],
createEndTime: formInline.value.createTime[1], createEndTime: formInline.value.createTime[1],
...@@ -1014,6 +1010,7 @@ const getTableData = ()=> { ...@@ -1014,6 +1010,7 @@ const getTableData = ()=> {
pageSize: pageSize.value, pageSize: pageSize.value,
handleState: 1, handleState: 1,
belongTo: 1, belongTo: 1,
isDctom: 1,
deviceType: formInline.value.deviceType deviceType: formInline.value.deviceType
} }
tableData.value = []; tableData.value = [];
...@@ -1071,7 +1068,7 @@ const srcList = ref([]); ...@@ -1071,7 +1068,7 @@ const srcList = ref([]);
const dialogReason = ref(''); const dialogReason = ref('');
const dialogMeasure = ref(''); const dialogMeasure = ref('');
const imgUrlList = ref([]); const imgUrlList = ref([]);
const alarmImags = ref([]); const alarmImg = ref([]);
const disposeWorkSheetDetail = (obj)=> { const disposeWorkSheetDetail = (obj)=> {
const { const {
reason, reason,
...@@ -1085,6 +1082,8 @@ const disposeWorkSheetDetail = (obj)=> { ...@@ -1085,6 +1082,8 @@ const disposeWorkSheetDetail = (obj)=> {
if (forwards.length > 0) { if (forwards.length > 0) {
let receiveUserItem = forwards.slice(-1)[0]; let receiveUserItem = forwards.slice(-1)[0];
} }
dialogMeasure.value = '';
dialogMeasure.value = '';
srcList.value = []; srcList.value = [];
imgUrlList.value = []; imgUrlList.value = [];
...@@ -1096,7 +1095,7 @@ const disposeWorkSheetDetail = (obj)=> { ...@@ -1096,7 +1095,7 @@ const disposeWorkSheetDetail = (obj)=> {
} }
if (alarmImags && alarmImags.length) { if (alarmImags && alarmImags.length) {
for (let item of alarmImags) { for (let item of alarmImags) {
alarmImags.push(item.imageUrl); alarmImg.value.push(item.imageUrl);
} }
} }
if (imgUrl) { if (imgUrl) {
...@@ -1107,6 +1106,7 @@ const disposeWorkSheetDetail = (obj)=> { ...@@ -1107,6 +1106,7 @@ const disposeWorkSheetDetail = (obj)=> {
onMounted(()=>{ onMounted(()=>{
getBranchTypeList(); getBranchTypeList();
getWarnAndTicketConfigMap(); getWarnAndTicketConfigMap();
getDeviceType();
searchData(); searchData();
}); });
...@@ -1264,6 +1264,267 @@ const handlePaginationChange = (pagination) => { ...@@ -1264,6 +1264,267 @@ const handlePaginationChange = (pagination) => {
height: auto; height: auto;
} }
} }
.improve-situation {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 50px;
.improve-situation-item {
width: 310px;
height: 71px;
border-radius: 2px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28px;
font-size: 24px;
font-weight: 500;
color: #ffffff;
line-height: 33px;
&:first-child {
background: linear-gradient(
225deg,
rgba(255, 133, 128, 0.65) 0%,
rgba(255, 58, 71, 0.61) 100%,
#0049fa 100%
);
}
&:last-child {
background: linear-gradient(
225deg,
rgba(128, 255, 178, 0.65) 0%,
rgba(58, 120, 255, 0.61) 100%,
#0049fa 100%
);
}
.road-cleanliness-index {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
.name {
font-size: 14px;
}
}
.star {
display: flex;
align-items: center;
justify-content: center;
span {
margin-right: 5px;
}
}
.value {
padding-right: 30px;
span {
font-size: 14px;
font-weight: 400;
}
}
}
}
.tips-content {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 0px 50px;
.content-item {
width: 50%;
font-size: 14px;
font-weight: 400;
color: #3b3b3b;
line-height: 19px;
min-height: 34px;
display: flex;
.value {
color: #ff7373;
font-size: 15px;
}
}
}
.leged-bg {
position: fixed;
left: 0;
right: 0;
width: 100%;
height: 600px;
background-color: rgba(0, 0, 0, 0.3);
.leged-wrap {
width: 300px;
height: 300px;
background-color: #fff;
}
}
.processing-records {
display: flex;
align-items: center;
// justify-content: space-between;
padding: 0 40px;
position: relative;
&::before {
content: "";
// width: calc(100% - 220px);
height: 6px;
background: #076d4e;
position: absolute;
left: 50%;
top: 48px;
transform: translate(-50%, -50%);
box-sizing: border-box;
}
.processing-records-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.handler {
min-width: 80px;
// max-width: 110px;
padding: 0 5px;
height: 26px;
text-align: center;
background: #bbeedf;
box-shadow: 0px 10px 5px -7px rgba(33, 179, 134, 0.5);
border: 1px solid #0b5a68;
border-radius: 2px;
line-height: 25px;
font-size: 14px;
font-weight: 400;
color: #0b5a68;
position: relative;
margin-bottom: 10px;
text-overflow: ellipsis;
// overflow: hidden;
white-space: nowrap;
&::before {
content: "";
width: 8px;
height: 8px;
background: #bbeedf;
border-left: 1px solid #0b5a68;
border-bottom: 1px solid #0b5a68;
// transform: rotate3d(90deg);
position: absolute;
left: 50%;
transform: rotate(-45deg) translateX(-50%);
bottom: -2px;
}
}
.circle {
width: 22px;
height: 22px;
background: #ffffff;
box-shadow: 0px 2px 4px 0px rgba(33, 176, 179, 0.43);
border: 1px solid #076d4e;
position: relative;
border-radius: 50%;
&::before {
content: "";
width: 8px;
height: 8px;
background: #0b5a68;
border-radius: 4px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.header {
width: 50%;
height: 6px;
background: #076d4e;
position: absolute;
box-sizing: border-box;
}
.footer {
width: 50%;
height: 6px;
left: 50%;
background: #076d4e;
position: absolute;
box-sizing: border-box;
}
.steps-line {
top: 45px;
width: 100%;
position: relative;
}
.step-name {
font-size: 12px;
font-weight: 400;
color: #0b5a68;
line-height: 12px;
margin-top: 8px;
font-weight: 500;
}
.partment {
font-size: 14px;
font-weight: 400;
line-height: 12px;
margin-top: 8px;
}
.handler-time {
text-align: center;
font-size: 12px;
font-weight: 400;
color: #606060;
line-height: 14px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 10px;
padding-right: 10px;
width: 180px;
}
.led-btn {
color: #fff;
}
}
.mb-20 {
margin-bottom: 20px;
}
}
.label-title-content {
width: 90%;
padding-left: 30px;
margin-bottom: 10px;
}
.deal-line-wrap {
overflow: auto;
width: 100%;
}
.qusetion-records {
padding: 5px 20px;
.qusetion-records-item {
text-indent: 10px;
}
}
.demo-image__preview {
margin: 0 50px;
display: flex;
flex-wrap: wrap;
.image-preview {
margin-right: 10px;
margin-bottom: 10px;
}
}
:deep(.el-row) {
margin-bottom: 28px;
}
}
.input-style {
padding-left: 50px;
}
.input-style-text {
padding: 0 50px;
font-size: 14px;
font-weight: 400;
color: #3b3b3b;
line-height: 24px;
} }
.default-btn { .default-btn {
......
...@@ -2,18 +2,8 @@ ...@@ -2,18 +2,8 @@
<div class="my-agency"> <div class="my-agency">
<el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="事件名称:"> <el-form-item label="事件名称:">
<el-select v-model="formInline.eventNameId" <el-input v-model="formInline.eventName">
placeholder="请选择" </el-input>
style="width: 280px"
>
<el-option
v-for="(item, index) in basicConfiguration.ticketEventName"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="发生位置:"> <el-form-item label="发生位置:">
<el-input v-model="formInline.keyword" placeholder="请输入"></el-input> <el-input v-model="formInline.keyword" placeholder="请输入"></el-input>
...@@ -39,8 +29,8 @@ ...@@ -39,8 +29,8 @@
<el-option <el-option
v-for="(item, index) in basicConfiguration.deviceList" v-for="(item, index) in basicConfiguration.deviceList"
index="item.id" index="item.id"
:label="item.name" :label="item.desc"
:value="item.id" :value="item.code"
> >
</el-option> </el-option>
</el-select> </el-select>
...@@ -371,14 +361,14 @@ ...@@ -371,14 +361,14 @@
<div class="demo-image__preview"> <div class="demo-image__preview">
<div <div
class="image-preview" class="image-preview"
v-for="(item, index) in alarmImags" v-for="(item, index) in alarmImg"
:key="index" :key="index"
> >
<el-image <el-image
style="width: 100px; height: 100px" style="width: 100px; height: 100px"
:lazy="true" :lazy="true"
:src="item" :src="item"
:preview-src-list="alarmImags" :preview-src-list="alarmImg"
></el-image> ></el-image>
</div> </div>
</div> </div>
...@@ -685,6 +675,7 @@ ...@@ -685,6 +675,7 @@
<common-dialog <common-dialog
:show-dialog="rejectDialog.show" :show-dialog="rejectDialog.show"
:title="rejectDialog.title" :title="rejectDialog.title"
:width="rejectDialog.width"
@handleBtn="saveReject" @handleBtn="saveReject"
@close:showDialog="rejectDialog.show = false" @close:showDialog="rejectDialog.show = false"
> >
...@@ -700,7 +691,7 @@ ...@@ -700,7 +691,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-row> <el-row>
<el-col :span="21"> <el-col :span="24">
<el-input type="textarea" v-model="rejectReason" :autosize="{ minRows: 2, maxRows: 12 }" placeholder="请输入内容"> <el-input type="textarea" v-model="rejectReason" :autosize="{ minRows: 2, maxRows: 12 }" placeholder="请输入内容">
</el-input> </el-input>
</el-col> </el-col>
...@@ -714,12 +705,12 @@ ...@@ -714,12 +705,12 @@
import { ref, reactive, onMounted, onBeforeUnmount,computed } from 'vue' import { ref, reactive, onMounted, onBeforeUnmount,computed } from 'vue'
import CommonTable from "@/components/commonTable/index.vue"; import CommonTable from "@/components/commonTable/index.vue";
import commonDialog from "./components/dialog.vue"; import commonDialog from "./components/dialog.vue";
import { getDataFun, postDataJSON } from '@/request/method.js'; import { getData, getDataFun, postDataJSON } from '@/request/method.js';
import moment from 'moment'; import moment from 'moment';
import { getToken } from '@/utils/auth.js'; import { getToken } from '@/utils/auth.js';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
const formInline = ref({ const formInline = ref({
eventNameId: '', eventName: '',
keyword: '', keyword: '',
warnType: '', warnType: '',
branchFactoryIds: '', branchFactoryIds: '',
...@@ -737,7 +728,7 @@ const formModel = ref({ ...@@ -737,7 +728,7 @@ const formModel = ref({
const viewDialog = ref({ const viewDialog = ref({
title: '闭环控制分派', title: '闭环控制分派',
show: false, show: false,
width: '50%', width: '45%',
}); });
const viewData = { const viewData = {
...@@ -780,7 +771,7 @@ const warnValueFilter = computed(()=> { ...@@ -780,7 +771,7 @@ const warnValueFilter = computed(()=> {
}); });
const imgUrlList = ref([]); const imgUrlList = ref([]);
const alarmImags = ref([]); const alarmImg = ref([]);
const srcList = ref([]); const srcList = ref([]);
const workTicketNo = ref(''); const workTicketNo = ref('');
...@@ -791,6 +782,7 @@ const rejectReason = ref(''); ...@@ -791,6 +782,7 @@ const rejectReason = ref('');
const rejectDialog = ref({ const rejectDialog = ref({
title: '驳回申请', title: '驳回申请',
show: false, show: false,
width: '35%',
btnGroup: [ btnGroup: [
{ {
attrKey: 'save', attrKey: 'save',
...@@ -830,7 +822,7 @@ const onSearch = ()=> { ...@@ -830,7 +822,7 @@ const onSearch = ()=> {
const onReset =()=> { const onReset =()=> {
currentPage.value = 1; currentPage.value = 1;
pageSize.value = 20; pageSize.value = 20;
formInline.value.eventNameId = ''; formInline.value.eventName = '';
formInline.value.keyword = ''; formInline.value.keyword = '';
formInline.value.branchFactoryIds = ''; formInline.value.branchFactoryIds = '';
formInline.value.deviceType = ''; formInline.value.deviceType = '';
...@@ -840,11 +832,11 @@ const onReset =()=> { ...@@ -840,11 +832,11 @@ const onReset =()=> {
] ]
searchData(); searchData();
} }
const personTag = ref([]);
const handleView = async (data) => { const handleView = async (data) => {
viewDialog.value.title = data.eventName; viewDialog.value.title = data.eventName;
let res = await getDetail(data.workTicketNo);
viewDialog.value.show = true; viewDialog.value.show = true;
/*let res = await getDetail(data.workTicketNo);
personTag.value = []; personTag.value = [];
if (res.handleUsers && res.handleUsers.length > 0) { if (res.handleUsers && res.handleUsers.length > 0) {
res.handleUsers.forEach(item => { res.handleUsers.forEach(item => {
...@@ -856,10 +848,11 @@ const handleView = async (data) => { ...@@ -856,10 +848,11 @@ const handleView = async (data) => {
}); });
}); });
} }
disposeWorkSheetDetail(res);*/ disposeWorkSheetDetail(res);
} }
const dialogReason = ref('');
const dialogMeasure = ref('');
const disposeWorkSheetDetail = (obj)=> { const disposeWorkSheetDetail = (obj)=> {
const { const {
reason, reason,
...@@ -873,6 +866,8 @@ const disposeWorkSheetDetail = (obj)=> { ...@@ -873,6 +866,8 @@ const disposeWorkSheetDetail = (obj)=> {
if (forwards.length > 0) { if (forwards.length > 0) {
let receiveUserItem = forwards.slice(-1)[0]; let receiveUserItem = forwards.slice(-1)[0];
} }
dialogMeasure.value = '';
dialogMeasure.value = '';
srcList.value = []; srcList.value = [];
imgUrlList.value = []; imgUrlList.value = [];
...@@ -884,7 +879,7 @@ const disposeWorkSheetDetail = (obj)=> { ...@@ -884,7 +879,7 @@ const disposeWorkSheetDetail = (obj)=> {
} }
if (alarmImags && alarmImags.length) { if (alarmImags && alarmImags.length) {
for (let item of alarmImags) { for (let item of alarmImags) {
alarmImags.push(item.imageUrl); alarmImg.value.push(item.imageUrl);
} }
} }
if (imgUrl) { if (imgUrl) {
...@@ -1019,9 +1014,8 @@ const getWarnAndTicketConfigMap = ()=> { ...@@ -1019,9 +1014,8 @@ const getWarnAndTicketConfigMap = ()=> {
} }
getDataFun(url,params).then(res => { getDataFun(url,params).then(res => {
if (res && res.code === 1) { if (res && res.code === 1) {
const { ticketEventName, deviceType } = res.data; const { ticketEventName } = res.data;
basicConfiguration.ticketEventName = basicConfiguration.ticketEventName.concat(ticketEventName); basicConfiguration.ticketEventName = basicConfiguration.ticketEventName.concat(ticketEventName);
basicConfiguration.deviceList = deviceType;
} }
}); });
}; };
...@@ -1049,7 +1043,7 @@ const searchData = ()=>{ ...@@ -1049,7 +1043,7 @@ const searchData = ()=>{
const getTableData = ()=> { const getTableData = ()=> {
let keyWord = formInline.value.keyword?.replace(/#/g, '%23'); let keyWord = formInline.value.keyword?.replace(/#/g, '%23');
const params = { const params = {
eventNameId: formInline.value.eventNameId, eventName: formInline.value.eventName,
warnType: formInline.value.warnType, warnType: formInline.value.warnType,
createStartTime: formInline.value.createTime[0], createStartTime: formInline.value.createTime[0],
createEndTime: formInline.value.createTime[1], createEndTime: formInline.value.createTime[1],
...@@ -1059,6 +1053,7 @@ const getTableData = ()=> { ...@@ -1059,6 +1053,7 @@ const getTableData = ()=> {
pageSize: pageSize.value, pageSize: pageSize.value,
handleState: 2, handleState: 2,
belongTo: 1, belongTo: 1,
isDctom: 1,
deviceType: formInline.value.deviceType deviceType: formInline.value.deviceType
} }
tableData.value = []; tableData.value = [];
...@@ -1111,9 +1106,17 @@ const disposeType = (list)=> { ...@@ -1111,9 +1106,17 @@ const disposeType = (list)=> {
} }
} }
const getDeviceType =() => {
const url = '/alarm/getDeviceType';
getData(url).then(res=>{
basicConfiguration.deviceList = res.data;
});
}
onMounted(() => { onMounted(() => {
getBranchTypeList(); getBranchTypeList();
getWarnAndTicketConfigMap(); getWarnAndTicketConfigMap();
getDeviceType();
searchData(); searchData();
}); });
...@@ -1189,10 +1192,440 @@ const handlePaginationChange = (pagination) => { ...@@ -1189,10 +1192,440 @@ const handlePaginationChange = (pagination) => {
top: 6px; top: 6px;
} }
} }
.improve-situation {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 50px;
.improve-situation-item {
width: 310px;
height: 71px;
border-radius: 2px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28px;
font-size: 24px;
font-weight: 500;
color: #ffffff;
line-height: 33px;
&:first-child {
background: linear-gradient(
225deg,
rgba(255, 133, 128, 0.65) 0%,
rgba(255, 58, 71, 0.61) 100%,
#0049fa 100%
);
}
&:last-child {
background: linear-gradient(
225deg,
rgba(128, 255, 178, 0.65) 0%,
rgba(58, 120, 255, 0.61) 100%,
#0049fa 100%
);
}
.road-cleanliness-index {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
.name {
font-size: 14px;
}
}
.star {
display: flex;
align-items: center;
justify-content: center;
span {
margin-right: 5px;
}
}
.value {
padding-right: 30px;
span {
font-size: 14px;
font-weight: 400;
}
}
}
}
.tips-content {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 0px 50px;
.content-item {
width: 50%;
font-size: 14px;
font-weight: 400;
color: #3b3b3b;
line-height: 19px;
min-height: 34px;
display: flex;
.value {
color: #ff7373;
font-size: 15px;
}
}
}
.leged-bg {
position: fixed;
left: 0;
right: 0;
width: 100%;
height: 600px;
background-color: rgba(0, 0, 0, 0.3);
.leged-wrap {
width: 300px;
height: 300px;
background-color: #fff;
}
}
.view-btn { .view-btn {
margin-right: 8px; margin-right: 8px;
cursor: pointer; cursor: pointer;
} }
.form-box {
height: 60vh;
overflow-y: auto;
overflow-x: hidden;
.label-title {
position: relative;
padding-left: 14px;
margin-bottom: 20px;
font-weight: 700;
font-size: 19px;
overflow: hidden;
&::before {
content: "";
width: 4px;
height: 4px;
border-radius: 50%;
background: #1890ff;
position: absolute;
left: 0px;
top: 50%;
transform: translateY(-50%);
}
&::after {
content: "";
width: 100%;
height: 0px;
position: absolute;
border-bottom: dashed 1px rgb(209, 209, 209);
left: 130px;
top: 50%;
transform: translateY(-50%);
}
}
.alarm-content {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 0px 35px;
.content-item {
width: 50%;
font-size: 14px;
font-weight: 500;
color: #3b3b3b;
line-height: 19px;
min-height: 34px;
display: flex;
.name {
text-align: right;
width: 140px;
margin-right: 10px;
}
.change-style {
width: auto;
}
.value {
color: #000000;
flex: 1;
}
.alarm-value {
color: #ff7373;
}
.cur-alarm-value {
color: #086635;
}
.work-status {
color: #e1971d;
}
}
.new-content-item-style {
width: 100%;
height: auto;
}
}
.improve-situation {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 50px;
.improve-situation-item {
width: 310px;
height: 71px;
border-radius: 2px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28px;
font-size: 24px;
font-weight: 500;
color: #ffffff;
line-height: 33px;
&:first-child {
background: linear-gradient(
225deg,
rgba(255, 133, 128, 0.65) 0%,
rgba(255, 58, 71, 0.61) 100%,
#0049fa 100%
);
}
&:last-child {
background: linear-gradient(
225deg,
rgba(128, 255, 178, 0.65) 0%,
rgba(58, 120, 255, 0.61) 100%,
#0049fa 100%
);
}
.road-cleanliness-index {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
.name {
font-size: 14px;
}
}
.star {
display: flex;
align-items: center;
justify-content: center;
span {
margin-right: 5px;
}
}
.value {
padding-right: 30px;
span {
font-size: 14px;
font-weight: 400;
}
}
}
}
.tips-content {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 0px 50px;
.content-item {
width: 50%;
font-size: 14px;
font-weight: 400;
color: #3b3b3b;
line-height: 19px;
min-height: 34px;
display: flex;
.value {
color: #ff7373;
font-size: 15px;
}
}
}
.leged-bg {
position: fixed;
left: 0;
right: 0;
width: 100%;
height: 600px;
background-color: rgba(0, 0, 0, 0.3);
.leged-wrap {
width: 300px;
height: 300px;
background-color: #fff;
}
}
.processing-records {
display: flex;
align-items: center;
// justify-content: space-between;
padding: 0 40px;
position: relative;
&::before {
content: "";
// width: calc(100% - 220px);
height: 6px;
background: #076d4e;
position: absolute;
left: 50%;
top: 48px;
transform: translate(-50%, -50%);
box-sizing: border-box;
}
.processing-records-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.handler {
min-width: 80px;
// max-width: 110px;
padding: 0 5px;
height: 26px;
text-align: center;
background: #bbeedf;
box-shadow: 0px 10px 5px -7px rgba(33, 179, 134, 0.5);
border: 1px solid #0b5a68;
border-radius: 2px;
line-height: 25px;
font-size: 14px;
font-weight: 400;
color: #0b5a68;
position: relative;
margin-bottom: 10px;
text-overflow: ellipsis;
// overflow: hidden;
white-space: nowrap;
&::before {
content: "";
width: 8px;
height: 8px;
background: #bbeedf;
border-left: 1px solid #0b5a68;
border-bottom: 1px solid #0b5a68;
// transform: rotate3d(90deg);
position: absolute;
left: 50%;
transform: rotate(-45deg) translateX(-50%);
bottom: -2px;
}
}
.circle {
width: 22px;
height: 22px;
background: #ffffff;
box-shadow: 0px 2px 4px 0px rgba(33, 176, 179, 0.43);
border: 1px solid #076d4e;
position: relative;
border-radius: 50%;
&::before {
content: "";
width: 8px;
height: 8px;
background: #0b5a68;
border-radius: 4px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.header {
width: 50%;
height: 6px;
background: #076d4e;
position: absolute;
box-sizing: border-box;
}
.footer {
width: 50%;
height: 6px;
left: 50%;
background: #076d4e;
position: absolute;
box-sizing: border-box;
}
.steps-line {
top: 45px;
width: 100%;
position: relative;
}
.step-name {
font-size: 12px;
font-weight: 400;
color: #0b5a68;
line-height: 12px;
margin-top: 8px;
font-weight: 500;
}
.partment {
font-size: 14px;
font-weight: 400;
line-height: 12px;
margin-top: 8px;
}
.handler-time {
text-align: center;
font-size: 12px;
font-weight: 400;
color: #606060;
line-height: 14px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 10px;
padding-right: 10px;
width: 180px;
}
.led-btn {
color: #fff;
}
}
.mb-20 {
margin-bottom: 20px;
}
}
.label-title-content {
width: 90%;
padding-left: 30px;
margin-bottom: 10px;
}
.deal-line-wrap {
overflow: auto;
width: 100%;
}
.qusetion-records {
padding: 5px 20px;
.qusetion-records-item {
text-indent: 10px;
}
}
.demo-image__preview {
margin: 0 50px;
display: flex;
flex-wrap: wrap;
.image-preview {
margin-right: 10px;
margin-bottom: 10px;
}
}
:deep(.el-row) {
margin-bottom: 28px;
}
}
:deep(.el-tag) {
margin-right: 10px;
}
.input-style {
padding-left: 50px;
}
.input-style-text {
padding: 0 50px;
font-size: 14px;
font-weight: 400;
color: #3b3b3b;
line-height: 24px;
}
.default-btn { .default-btn {
width: 85px; width: 85px;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<el-input <el-input
v-model="formInline.deviceName" v-model="formInline.deviceName"
placeholder="请输入仓室名称" placeholder="请输入仓室名称"
style="width: 200px" style="width: 180px"
clearable clearable
/> />
</el-form-item> </el-form-item>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<el-input <el-input
v-model="formInline.deviceName" v-model="formInline.deviceName"
placeholder="请输入除尘器名称" placeholder="请输入除尘器名称"
style="width: 200px" style="width: 180px"
clearable clearable
/> />
</el-form-item> </el-form-item>
...@@ -36,7 +36,11 @@ ...@@ -36,7 +36,11 @@
<el-button type="primary" class="search-btn" @click="onSubmit" <el-button type="primary" class="search-btn" @click="onSubmit"
>查询</el-button >查询</el-button
> >
<el-button type="success" class="add-btn" @click="openDialog()" <el-button
type="success"
style="width: 140px"
class="add-btn"
@click="openDialog()"
>更换周期分析</el-button >更换周期分析</el-button
> >
</el-form-item> </el-form-item>
......
...@@ -59,48 +59,65 @@ ...@@ -59,48 +59,65 @@
</template> </template>
<script setup> <script setup>
import { onMounted, onBeforeUnmount, ref } from "vue"; import { onMounted, onBeforeUnmount, ref, watch } from "vue";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { getLineOption } from "@/utils/chart"; import { getLineOption } from "@/utils/chart";
// 定义坐标点位数据 const props = defineProps({
const spots = ref([ mapList: {
{ type: Array,
id:1, default: () => [],
no: "wp001",
x: 41,
y: 22,
name: "4#除尘器",
status: 0,
description: ["无异常"],
},
{
id:2,
no: "wp001",
x: 45,
y: 70,
name: "站点B",
status: 0,
description: ["运行正常"],
},
{
id:3,
no: "wp001",
x: 77,
y: 36,
name: "3#除尘器",
status: 1,
description: ["三仓室存在轻微泄漏", "三仓室存在轻微泄漏", "三仓室存在轻微泄漏"],
}, },
{ });
id:4,
no: "wp001",
x: 50, watch(
y: 65, () => props.mapList,
name: "2#除尘器", () => {
status: 1, initMap();
description: ["除尘器脉冲阀故障或者提升阀故障"],
}, },
{ deep: true }
);
// 定义坐标点位数据
const spots = ref([
// {
// id:1,
// no: "wp001",
// x: 41,
// y: 22,
// name: "4#除尘器",
// status: 0,
// description: ["无异常"],
// },
// {
// id:2,
// no: "wp001",
// x: 45,
// y: 70,
// name: "站点B",
// status: 0,
// description: ["运行正常"],
// },
// {
// id:3,
// no: "wp001",
// x: 77,
// y: 36,
// name: "3#除尘器",
// status: 1,
// description: ["三仓室存在轻微泄漏", "三仓室存在轻微泄漏", "三仓室存在轻微泄漏"],
// },
// {
// id:4,
// no: "wp001",
// x: 50,
// y: 65,
// name: "2#除尘器",
// status: 1,
// description: ["除尘器脉冲阀故障或者提升阀故障"],
// },
]); ]);
const activeSpot = ref(null); const activeSpot = ref(null);
...@@ -160,7 +177,14 @@ const getStatusText = (status) => { ...@@ -160,7 +177,14 @@ const getStatusText = (status) => {
return statusMap[status] || status; return statusMap[status] || status;
}; };
onMounted(() => {}); const initMap = () => {
console.log(props.mapList, 'props.mapList')
spots.value = props.mapList || [];
}
onMounted(() => {
initMap();
});
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearTimer(); clearTimer();
......
...@@ -28,14 +28,14 @@ ...@@ -28,14 +28,14 @@
</div> </div>
<div class="map-box"> <div class="map-box">
<map-svg></map-svg> <map-svg :mapList="mapList"></map-svg>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount, computed, nextTick } from "vue"; import { ref, onMounted, onBeforeUnmount, computed, nextTick } from "vue";
import { getHealthOverview, getHealthStatistic, getExceptionMonitor } from "@/request/api/dashboard"; import { getHealthOverview, getHealthStatistic, getExceptionMonitor, getDusterAlarm } from "@/request/api/dashboard";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import msgItem from "./components/msg-item.vue"; import msgItem from "./components/msg-item.vue";
import chartLine from "./components/chart-line.vue"; import chartLine from "./components/chart-line.vue";
...@@ -58,6 +58,7 @@ const router = useRouter(); ...@@ -58,6 +58,7 @@ const router = useRouter();
const msgList = ref([ const msgList = ref([
]); ]);
const mapList = ref([]);
const customColorMethod = (percentage) => { const customColorMethod = (percentage) => {
if (percentage < 60) { if (percentage < 60) {
...@@ -76,69 +77,33 @@ const healthOverview = () => { ...@@ -76,69 +77,33 @@ const healthOverview = () => {
pulseValve.value = Number(res.data.pulseValve.split('%')[0]) pulseValve.value = Number(res.data.pulseValve.split('%')[0])
poppetValve.value = Number(res.data.poppetValve.split('%')[0]) poppetValve.value = Number(res.data.poppetValve.split('%')[0])
}) })
// const res = {
// "data": {
// "average": "20%",
// "bag": "10%",
// "pulseValve": "20%",
// "poppetValve": "30%"
// },
// msg: "访问成功",
// success: true,
// code: 1
// }
} }
const healthStatistic = () => { const healthStatistic = () => {
getHealthStatistic().then(res => { getHealthStatistic().then(res => {
chartData.value = res.data; chartData.value = res.data;
}) })
// const res = {
// "data": [
// {
// "date": "2025-05-01",
// "healthDegree": "75"
// },
// {
// "date": "2025-05-02",
// "healthDegree": "68"
// }
// ],
// "msg": "访问成功",
// "success": true,
// code: 1,
// };
}; };
const exceptionMonitor = () => { const exceptionMonitor = () => {
getExceptionMonitor().then(res => { getExceptionMonitor().then(res => {
msgList.value = res.data; msgList.value = res.data;
}) })
// const res = {
// "data": [
// {
// "date": "2025-05-01 10:00",
// "dusterName": "3#除尘器",
// "message": "三仓室存在轻重泄露"
// },
// {
// "date": "2025-05-01 10:00",
// "dusterName": "3#除尘器",
// "message": "三仓室存在轻重泄露"
// }
// ],
// msg: "访问成功",
// success: true,
// code: 1
// }
// msgList.value = res.data;
} }
const handleDusterAlarm = () => {
getDusterAlarm().then(res => {
mapList.value = res.data;
})
}
onMounted(async () => { onMounted(async () => {
healthOverview(); healthOverview();
healthStatistic(); healthStatistic();
exceptionMonitor(); exceptionMonitor();
handleDusterAlarm();
}); });
onBeforeUnmount(() => { }); onBeforeUnmount(() => { });
......
<template> <template>
<el-dialog <el-dialog :model-value="modelValue" title="新增除尘器" width="460px" :close-on-click-modal="false"
:model-value="modelValue" :close-on-press-escape="false" @update:model-value="$emit('update:modelValue', $event)">
title="新增除尘器"
width="460px"
:close-on-click-modal="false"
:close-on-press-escape="false"
@update:model-value="$emit('update:modelValue', $event)"
>
<div class="add-dust-form"> <div class="add-dust-form">
<div class="form-item"> <div class="form-item">
<div class="selector-wrap"> <div class="selector-wrap">
<el-select v-model="formData.dustType" placeholder="除尘器选择" style="width: 238px"> <el-select v-model="formData.dustType" placeholder="除尘器选择" style="width: 238px" filterable remote
<el-option :remote-method="handleSearch" :loading="loading">
v-for="item in dustTypeOptions" <el-option v-for="item in dustTypeOptions" :key="item.deviceNo" :label="item.deviceName"
:key="item.value" :value="item.deviceNo" />
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
<el-button type="primary" size="default" @click="selectDustType">选择</el-button> <el-button type="primary" size="default" @click="selectDustType">选择</el-button>
</div> </div>
...@@ -27,19 +18,15 @@ ...@@ -27,19 +18,15 @@
<el-form-item label="除尘器名称" prop="name"> <el-form-item label="除尘器名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入" /> <el-input v-model="formData.name" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="除尘器编号" prop="code"> <el-form-item label="除尘器编号" prop="code">
<el-input v-model="formData.code" placeholder="请输入" /> <el-input v-model="formData.code" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="所属工序" prop="process"> <el-form-item label="所属工序" prop="process">
<el-select v-model="formData.process" placeholder="工序选择"> <el-select v-model="formData.process" placeholder="工序选择">
<el-option <el-option v-for="item in processOptions" :key="item.productionLineId" :label="item.productionLineName"
v-for="item in processOptions" :value="item.productionLineId" />
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
...@@ -51,17 +38,36 @@ ...@@ -51,17 +38,36 @@
<el-input v-model.number="formData.valveCount" placeholder="请输入" /> <el-input v-model.number="formData.valveCount" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="合理压差范围" prop="pressureRange"> <el-form-item label="合理压差范围">
<div class="range-input"> <div class="range-input">
<el-input v-model.number="formData.pressureMin" placeholder="请输入" /> <el-form-item prop="pressureMin" class="coordinate-item">
<el-input v-model.number="formData.pressureMin" placeholder="请输入" />
</el-form-item>
<span class="separator"></span> <span class="separator"></span>
<el-input v-model.number="formData.pressureMax" placeholder="请输入" /> <el-form-item prop="pressureMax" class="coordinate-item">
<el-input v-model.number="formData.pressureMax" placeholder="请输入" />
</el-form-item>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="服务器IP" prop="serverIp"> <el-form-item label="服务器IP" prop="serverIp" required>
<el-input v-model="formData.serverIp" placeholder="请输入" /> <el-input v-model="formData.serverIp" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="二维图坐标" required>
<div class="coordinate-inputs">
<el-form-item prop="coordinateX" class="coordinate-item">
<el-input v-model.number="formData.coordinateX" placeholder="X坐标">
<template #prefix>X:</template>
</el-input>
</el-form-item>
<el-form-item prop="coordinateY" class="coordinate-item">
<el-input v-model.number="formData.coordinateY" placeholder="Y坐标">
<template #prefix>Y:</template>
</el-input>
</el-form-item>
</div>
</el-form-item>
</el-form> </el-form>
</div> </div>
...@@ -75,29 +81,26 @@ ...@@ -75,29 +81,26 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import { getVisDusterList, getProductionLine } from "@/request/api/dustOverview";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: Boolean, type: Boolean,
default: false default: false
} },
}); });
const emit = defineEmits(['update:modelValue', 'save']); const emit = defineEmits(['update:modelValue', 'save']);
const formRef = ref(null); const formRef = ref(null);
const dustTypeOptions = [ const dustTypeOptions = ref([]);
{ value: 1, label: '除尘器类型1' }, const allDustOptions = ref([]);
{ value: 2, label: '除尘器类型2' }, const processOptions = ref([]);
{ value: 3, label: '除尘器类型3' }
];
const processOptions = [ const lastSearchQuery = ref('');
{ value: 1, label: '转炉' },
{ value: 2, label: '炼铁' }
];
const formData = reactive({ const formData = reactive({
dustType: '', dustType: '',
...@@ -108,7 +111,9 @@ const formData = reactive({ ...@@ -108,7 +111,9 @@ const formData = reactive({
valveCount: null, valveCount: null,
pressureMin: null, pressureMin: null,
pressureMax: null, pressureMax: null,
serverIp: '' serverIp: '',
coordinateX: null,
coordinateY: null
}); });
const rules = { const rules = {
...@@ -125,45 +130,124 @@ const rules = { ...@@ -125,45 +130,124 @@ const rules = {
], ],
pressureMin: [ pressureMin: [
{ required: true, message: '请输入最小压差', trigger: 'blur' }, { required: true, message: '请输入最小压差', trigger: 'blur' },
{ type: 'number', message: '必须为数字', trigger: 'blur' } { type: 'number', min: 1, message: '最小压差必须大于0', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value && formData.pressureMax && value >= formData.pressureMax) {
callback(new Error('必须小于最大压差'));
} else {
callback();
}
},
trigger: 'blur'
}
], ],
pressureMax: [ pressureMax: [
{ required: true, message: '请输入最大压差', trigger: 'blur' }, { required: true, message: '请输入最大压差', trigger: 'blur' },
{ type: 'number', message: '必须为数字', trigger: 'blur' } { type: 'number', min: 0, message: '最大压差必须大于0', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value && formData.pressureMin && value <= formData.pressureMin) {
callback(new Error('必须大于最小压差'));
} else {
callback();
}
},
trigger: 'blur'
}
], ],
serverIp: [ serverIp: [
{ required: true, message: '请输入服务器IP', trigger: 'blur' }, { required: true, message: '请输入服务器IP', trigger: 'blur' },
{ pattern: /^(\d{1,3}\.){3}\d{1,3}$/, message: 'IP地址格式不正确', trigger: 'blur' } { pattern: /^(\d{1,3}\.){3}\d{1,3}$/, message: 'IP地址格式不正确', trigger: 'blur' }
],
coordinateX: [
{ required: true, message: '请输入X坐标', trigger: 'blur' },
{ type: 'number', message: 'X坐标必须为数字', trigger: 'blur' }
],
coordinateY: [
{ required: true, message: '请输入Y坐标', trigger: 'blur' },
{ type: 'number', message: 'Y坐标必须为数字', trigger: 'blur' }
] ]
}; };
const selectDustType = () => { const loading = ref(false);
// 这里可以根据选择的除尘器类型预填充表单数据
// 如果有预设模板数据,可以在这里设置 const initDustOptions = () => {
console.log('Selected dust type:', formData.dustType); loading.value = true;
getVisDusterList().then(res => {
dustTypeOptions.value = res.data;
allDustOptions.value = res.data;
loading.value = false;
}).catch(() => {
loading.value = false;
});
}; };
const handleSearch = (query) => {
if (query === lastSearchQuery.value) {
return;
}
lastSearchQuery.value = query;
if (!query) {
dustTypeOptions.value = allDustOptions.value;
return;
}
loading.value = true;
const params = {
deviceName: query
};
getVisDusterList(params).then(res => {
dustTypeOptions.value = res.data;
loading.value = false;
}).catch(() => {
loading.value = false;
});
};
const productionLine = () => {
getProductionLine().then(res => {
processOptions.value = res.data;
})
}
onMounted(() => {
productionLine();
initDustOptions();
});
const selectDustType = () => {
const item = dustTypeOptions.value.find(item => item.deviceNo === formData.dustType);
formData.name = item.deviceName;
formData.code = item.deviceNo;
formData.process = item.productionLineId;
// 校验表单
formRef.value.validate((valid) => {
});
};
const submitForm = () => { const submitForm = () => {
if (!formRef.value) return; if (!formRef.value) return;
formRef.value.validate((valid) => { formRef.value.validate((valid) => {
if (valid) { if (valid) {
// 组装压差范围 // 组装压差范围
const pressureRange = `${formData.pressureMin}${formData.pressureMax}`; const pressureRange = `${formData.pressureMin}${formData.pressureMax}`;
// 准备提交的数据 // 准备提交的数据
const submitData = { const submitData = {
dustType: formData.dustType,
deviceName: formData.name,
deviceNo: formData.code, deviceNo: formData.code,
process: formData.process, deviceName: formData.name,
healthScore: formData.chamberCount, // 仓室数量保存在healthScore productionLineId: formData.process,
health2Score: formData.valveCount, // 电磁阀数量保存在health2Score compartNum: formData.chamberCount,
lastAlarmTime: pressureRange, // 合理压差范围保存在lastAlarmTime字段 valveNum: formData.valveCount,
serverIp: formData.serverIp, serviceIp: formData.serverIp,
// 生成默认的状态矩阵 pressureDiffLow: formData.pressureMin,
status: generateDefaultStatus(formData.chamberCount) pressureDiffHigh: formData.pressureMax,
x: formData.coordinateX,
y: formData.coordinateY,
}; };
// 发送数据到父组件处理保存逻辑 // 发送数据到父组件处理保存逻辑
emit('save', submitData); emit('save', submitData);
emit('update:modelValue', false); emit('update:modelValue', false);
...@@ -183,33 +267,11 @@ const cancel = () => { ...@@ -183,33 +267,11 @@ const cancel = () => {
formData.process = ''; formData.process = '';
formData.chamberCount = null; formData.chamberCount = null;
formData.valveCount = null; formData.valveCount = null;
formData.coordinateX = null;
formData.coordinateY = null;
emit('update:modelValue', false); emit('update:modelValue', false);
}; };
// 生成默认的状态矩阵
const generateDefaultStatus = (totalChambers) => {
// 默认状态:正常(status=1),每排最多5个仓室
const rows = Math.ceil(totalChambers / 5);
const result = [];
let chamberIndex = 1;
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
const row = [];
const chambersInRow = Math.min(5, totalChambers - rowIndex * 5);
for (let i = 0; i < chambersInRow; i++) {
row.push({
index: chamberIndex++,
status: 1, // 正常状态
count: 1 // 默认阀门数量
});
}
result.push(row);
}
return result;
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -220,7 +282,7 @@ const generateDefaultStatus = (totalChambers) => { ...@@ -220,7 +282,7 @@ const generateDefaultStatus = (totalChambers) => {
margin-bottom: 20px; margin-bottom: 20px;
padding: 0 0 0 50px; padding: 0 0 0 50px;
box-sizing: border-box; box-sizing: border-box;
.number-badge { .number-badge {
width: 24px; width: 24px;
height: 24px; height: 24px;
...@@ -232,7 +294,7 @@ const generateDefaultStatus = (totalChambers) => { ...@@ -232,7 +294,7 @@ const generateDefaultStatus = (totalChambers) => {
font-weight: bold; font-weight: bold;
margin-right: 10px; margin-right: 10px;
} }
.selector-wrap { .selector-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -240,26 +302,26 @@ const generateDefaultStatus = (totalChambers) => { ...@@ -240,26 +302,26 @@ const generateDefaultStatus = (totalChambers) => {
flex: 1; flex: 1;
} }
} }
.form-content { .form-content {
padding: 0 30px; padding: 0 30px;
.range-input { .range-input {
display: flex; display: flex;
align-items: center; align-items: center;
.separator { .separator {
margin: 0 5px; margin: 0 5px;
color: #606266; color: #606266;
} }
} }
} }
.form-footer { .form-footer {
margin-top: 20px; margin-top: 20px;
display: flex; display: flex;
justify-content: center; justify-content: center;
.el-button { .el-button {
width: 120px; width: 120px;
} }
...@@ -278,4 +340,18 @@ const generateDefaultStatus = (totalChambers) => { ...@@ -278,4 +340,18 @@ const generateDefaultStatus = (totalChambers) => {
:deep(.el-select) { :deep(.el-select) {
width: 100%; width: 100%;
} }
</style>
\ No newline at end of file .coordinate-inputs {
display: flex;
gap: 10px;
.coordinate-item {
flex: 1;
margin-bottom: 0;
:deep(.el-input__prefix) {
color: #606266;
}
}
}
</style>
\ No newline at end of file
...@@ -33,14 +33,20 @@ ...@@ -33,14 +33,20 @@
<el-select <el-select
v-model="formInline.region" v-model="formInline.region"
placeholder="请选择工序" placeholder="请选择工序"
style="width: 120px" style="width: 180px"
clearable filterable
:filter-method="filterProductionLine"
> >
<el-option
key="all"
label="全部"
value="all"
/>
<el-option <el-option
v-for="item in options" v-for="item in productionLineFiltered"
:key="item.value" :key="item.productionLineId"
:label="item.label" :label="item.productionLineName"
:value="item.value" :value="item.productionLineId"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
...@@ -54,7 +60,7 @@ ...@@ -54,7 +60,7 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="default" class="default-btn" @click="onSubmit" <el-button type="default" class="default-btn" @click="refreshData"
>重置</el-button >重置</el-button
> >
<el-button type="primary" class="search-btn" @click="onSubmit" <el-button type="primary" class="search-btn" @click="onSubmit"
...@@ -83,20 +89,20 @@ ...@@ -83,20 +89,20 @@
<template #index="{ $index }"> <template #index="{ $index }">
{{ getIndex($index) }} {{ getIndex($index) }}
</template> </template>
<template #healthScore="{ row }"> <template #compartNum="{ row }">
<span class="health-score" @click="handleHealthScoreClick(row)">{{ <span class="health-score" @click="handleHealthScoreClick(row)">{{
row.healthScore row.compartNum
}}</span> }}</span>
</template> </template>
<template #health2Score="{ row }"> <template #valveNum="{ row }">
<span class="health-score" @click="handleHealth2ScoreClick(row)">{{ <span class="health-score" @click="handlevalveNumClick(row)">{{
row.health2Score row.valveNum
}}</span> }}</span>
</template> </template>
<template #status="{ row }"> <template #compartHealthList="{ row }">
<div class="status-matrix"> <div class="status-matrix" v-if="row.compartHealthList.length > 0">
<div <div
v-for="(row, rowIndex) in row.status" v-for="(row, rowIndex) in row.compartHealthList"
:key="rowIndex" :key="rowIndex"
class="matrix-row" class="matrix-row"
> >
...@@ -105,18 +111,25 @@ ...@@ -105,18 +111,25 @@
:key="colIndex" :key="colIndex"
class="status-dot" class="status-dot"
:class="{ :class="{
'status-normal': status.status === 1, 'status-normal': status.healthStatus === 1,
'status-warning': status.status === 2, 'status-warning': status.healthStatus === 2,
'status-error': status.status === 3, 'status-error': status.healthStatus === 3,
}" }"
></div> ></div>
</div> </div>
</div> </div>
<div v-else>-</div>
</template>
<template #healthPercent="{ row }">
<span :style="{ color: getHealthScoreColor(row.healthPercent) }">
{{ row.healthPercent }}
</span>
</template> </template>
<template #alarmCount="{ row }"> <template #pressureDiffLow="{ row }">
<span :style="{ color: getHealthScoreColor(row.alarmCount) }"> <span>
{{ row.alarmCount }} {{ row.pressureDiffLow }}{{ row.pressureDiffHigh }}
</span> </span>
</template> </template>
...@@ -153,8 +166,8 @@ ...@@ -153,8 +166,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount, computed } from "vue"; import { ref, onMounted, onBeforeUnmount, computed, watch } from "vue";
import { getDusterLeakNum, getHealthPercent, getCloseLoopNum } from "@/request/api/dustOverview"; import { getDusterLeakNum, getHealthPercent, getCloseLoopNum, getProductionLine, getDusterList, postAddDuster, postUpdateDuster } from "@/request/api/dustOverview";
import CommonTable from "@/components/commonTable/index.vue"; import CommonTable from "@/components/commonTable/index.vue";
import RoomSettingDialog from "./components/roomSettingDialog.vue"; import RoomSettingDialog from "./components/roomSettingDialog.vue";
import ValveSettingDialog from "./components/valveSettingDialog.vue"; import ValveSettingDialog from "./components/valveSettingDialog.vue";
...@@ -162,7 +175,7 @@ import AddDustCollectorDialog from "./components/addDustCollectorDialog.vue"; ...@@ -162,7 +175,7 @@ import AddDustCollectorDialog from "./components/addDustCollectorDialog.vue";
const formInline = ref({ const formInline = ref({
deviceName: "", deviceName: "",
region: 1, region: 'all',
}); });
const currentPage = ref(1); const currentPage = ref(1);
...@@ -171,16 +184,8 @@ const dusterLeakNum = ref(0); ...@@ -171,16 +184,8 @@ const dusterLeakNum = ref(0);
const healthPercent = ref('100%'); const healthPercent = ref('100%');
const closeLoopNum = ref(0); const closeLoopNum = ref(0);
const options = ref([ const productionLine = ref([]);
{ const productionLineFiltered = ref([]); // 用于存储过滤后的工序
value: 1,
label: "转炉",
},
{
value: 2,
label: "炼铁",
},
]);
const tableColumns = ref([ const tableColumns = ref([
{ {
...@@ -199,32 +204,32 @@ const tableColumns = ref([ ...@@ -199,32 +204,32 @@ const tableColumns = ref([
width: "12%", width: "12%",
}, },
{ {
prop: "process", prop: "productionLine",
label: "所属工序", label: "所属工序",
width: "5%", width: "5%",
}, },
{ {
prop: "healthScore", prop: "compartNum",
label: "仓室数量", label: "仓室数量",
width: "8%", width: "8%",
}, },
{ {
prop: "health2Score", prop: "valveNum",
label: "电磁阀数量", label: "电磁阀数量",
width: "8%", width: "8%",
}, },
{ {
prop: "status", prop: "compartHealthList",
label: "仓室健康状态", label: "仓室健康状态",
width: "25%", width: "25%",
}, },
{ {
prop: "alarmCount", prop: "healthPercent",
label: "健康度", label: "健康度",
width: "5%", width: "5%",
}, },
{ {
prop: "lastAlarmTime", prop: "pressureDiffLow",
label: "合理压差范围", label: "合理压差范围",
width: "10%", width: "10%",
}, },
...@@ -235,216 +240,21 @@ const tableColumns = ref([ ...@@ -235,216 +240,21 @@ const tableColumns = ref([
}, },
]); ]);
const tableData = [ const tableData = ref([]);
{
deviceName: "1#除尘器", watch(productionLine, (newVal) => {
deviceNo: "1234567890", productionLineFiltered.value = newVal;
process: "转炉", });
healthScore: 10,
health2Score: 11, const filterProductionLine = (query) => {
status: [ if (!query) {
[ productionLineFiltered.value = productionLine.value;
{ } else {
index: 1, productionLineFiltered.value = productionLine.value.filter(item =>
status: 1, item.productionLineName.toLowerCase().includes(query.toLowerCase())
count: 1, );
}, }
{ };
index: 2,
status: 2,
count: 2,
},
{
index: 3,
status: 1,
count: 1,
},
{
index: 4,
status: 1,
count: 1,
},
{
index: 5,
status: 3,
count: 1,
},
],
[
{
index: 6,
status: 1,
count: 1,
},
{
index: 7,
status: 1,
count: 1,
},
{
index: 8,
status: 1,
count: 1,
},
{
index: 9,
status: 1,
count: 1,
},
{
index: 10,
status: 2,
count: 1,
},
],
],
alarmCount: "98%",
lastAlarmTime: "-",
location: "一号转炉东侧",
},
{
deviceName: "2#除尘器",
deviceNo: "1234567890",
process: "转炉",
healthScore: 10,
health2Score: 11,
status: [
[
{
index: 1,
status: 1,
count: 1,
},
{
index: 2,
status: 2,
count: 2,
},
{
index: 3,
status: 1,
count: 1,
},
{
index: 4,
status: 1,
count: 1,
},
{
index: 5,
status: 3,
count: 1,
},
],
[
{
index: 6,
status: 1,
count: 1,
},
{
index: 7,
status: 1,
count: 1,
},
{
index: 8,
status: 1,
count: 1,
},
{
index: 9,
status: 1,
count: 1,
},
{
index: 10,
status: 2,
count: 1,
},
],
],
alarmCount: "45%",
lastAlarmTime: "100~3000",
location: "二号转炉西侧",
},
{
deviceName: "3#除尘器",
deviceNo: "1234567890",
process: "炼铁",
healthScore: 12,
health2Score: 13,
status: [
[
{
index: 1,
status: 1,
count: 1,
},
{
index: 2,
status: 2,
count: 2,
},
{
index: 3,
status: 1,
count: 1,
},
{
index: 4,
status: 1,
count: 1,
},
{
index: 5,
status: 3,
count: 1,
},
],
[
{
index: 6,
status: 1,
count: 1,
},
{
index: 7,
status: 1,
count: 1,
},
{
index: 8,
status: 1,
count: 1,
},
{
index: 9,
status: 1,
count: 1,
},
{
index: 10,
status: 2,
count: 1,
},
{
index: 11,
status: 1,
count: 1,
},
{
index: 12,
status: 2,
count: 1,
},
],
],
alarmCount: "78%",
lastAlarmTime: "100~3000",
location: "炼铁区域北侧",
},
];
const getStatusType = (status) => { const getStatusType = (status) => {
const statusMap = { const statusMap = {
...@@ -456,7 +266,8 @@ const getStatusType = (status) => { ...@@ -456,7 +266,8 @@ const getStatusType = (status) => {
}; };
const getHealthScoreColor = (score) => { const getHealthScoreColor = (score) => {
const value = parseInt(score); // 去除百分号
const value = parseInt(score.replace('%', ''));
if (value >= 90) return "#67C23A"; if (value >= 90) return "#67C23A";
if (value >= 70) return "#E6A23C"; if (value >= 70) return "#E6A23C";
return "#F56C6C"; return "#F56C6C";
...@@ -481,7 +292,9 @@ const handlePaginationChange = (pagination) => { ...@@ -481,7 +292,9 @@ const handlePaginationChange = (pagination) => {
}; };
const onSubmit = () => { const onSubmit = () => {
console.log("submit!", formInline.value); currentPage.value = 1;
pageSize.value = 10;
getData();
}; };
// 仓室设置相关 // 仓室设置相关
...@@ -545,12 +358,12 @@ const handleRoomSettingConfirm = (distributionData) => { ...@@ -545,12 +358,12 @@ const handleRoomSettingConfirm = (distributionData) => {
}; };
// 点击电磁阀数量时打开弹窗 // 点击电磁阀数量时打开弹窗
const handleHealth2ScoreClick = (row) => { const handleValveNumClick = (row) => {
// 创建一个扁平化的状态数组用于电磁阀设置 // 创建一个扁平化的状态数组用于电磁阀设置
currentEditingRow.value = JSON.parse(JSON.stringify(row)); currentEditingRow.value = JSON.parse(JSON.stringify(row));
const flattenedStatus = row.status.flat().map(item => ({...item})); const flattenedStatus = row.status.flat().map(item => ({...item}));
currentEditingRow.value.status = flattenedStatus; currentEditingRow.value.status = flattenedStatus;
valveForm.value.total = row.health2Score; valveForm.value.total = row.valveNum;
valveSettingVisible.value = true; valveSettingVisible.value = true;
}; };
...@@ -560,7 +373,7 @@ const handleValveSettingConfirm = (updatedStatusData) => { ...@@ -560,7 +373,7 @@ const handleValveSettingConfirm = (updatedStatusData) => {
// 更新总数 // 更新总数
const originalRow = tableData.find(item => item === currentEditingRow.value); const originalRow = tableData.find(item => item === currentEditingRow.value);
if (originalRow) { if (originalRow) {
originalRow.health2Score = valveForm.value.total; originalRow.valveNum = valveForm.value.total;
// 更新各个仓室的电磁阀数量 // 更新各个仓室的电磁阀数量
const flatStatusMap = new Map(); const flatStatusMap = new Map();
...@@ -588,19 +401,38 @@ const handleAddDustCollector = () => { ...@@ -588,19 +401,38 @@ const handleAddDustCollector = () => {
// 保存新增除尘器 // 保存新增除尘器
const handleSaveDustCollector = (data) => { const handleSaveDustCollector = (data) => {
if (data.id) {
postUpdateDuster(data).then(res => {
if (res.code == 1) {
ElMessage.success('更新除尘器成功');
isAddDustCollectorVisible.value = false;
refreshData();
} else {
ElMessage.error(res.message);
}
}).catch(err => {
ElMessage.error(err.message);
})
} else {
postAddDuster(data).then(res => {
if (res.code == 1) {
ElMessage.success('新增除尘器成功');
isAddDustCollectorVisible.value = false;
refreshData();
} else {
ElMessage.error(res.message);
}
}).catch(err => {
ElMessage.error(err.message);
})
}
console.log("保存新增除尘器数据:", data); console.log("保存新增除尘器数据:", data);
// 添加到表格数据中
tableData.push({
...data,
alarmCount: "100%", // 设置默认健康度
location: "", // 可以根据需要设置默认位置
});
// 这里可以调用API进行保存 // 这里可以调用API进行保存
// await api.addDustCollector(data); // await api.addDustCollector(data);
// 关闭弹窗
isAddDustCollectorVisible.value = false;
}; };
...@@ -623,10 +455,50 @@ const IcloseLoopNum = () => { ...@@ -623,10 +455,50 @@ const IcloseLoopNum = () => {
}) })
} }
const IproductionLine = () => {
getProductionLine().then(res => {
productionLine.value = res.data || [];
// 默认显示全部
productionLineFiltered.value = res.data || [];
})
}
const getData = () => {
const params = {
pageNo: currentPage.value,
pageSize: pageSize.value,
productionLineId: formInline.value.region === 'all' ? '' : formInline.value.region,
keyword: formInline.value.deviceName,
}
getDusterList(params).then(res => {
console.log(res);
if (res.code == 1) {
tableData.value = res.data.records || [];
// total.value = res.data.total || 0;
} else {
ElMessage.error(res.message);
}
})
}
const refreshData = () => {
currentPage.value = 1;
pageSize.value = 10;
formInline.value = {
region: '',
deviceName: '',
}
getData();
}
onMounted(async () => { onMounted(async () => {
IdusterLeakNum(); IdusterLeakNum();
IhealthPercent(); IhealthPercent();
IcloseLoopNum(); IcloseLoopNum();
IproductionLine();
getData();
}); });
onBeforeUnmount(() => {}); onBeforeUnmount(() => {});
......
<template>
<div class="page-container collectorList">
<div class="content-box">
<div class="search">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="项目名称">
<el-select v-model="formInline.name" style="width: 200px">
<el-option
v-for="i in nameList.list"
:key="i"
:label="`${i.label}`"
:value="i.value"
/>
</el-select>
</el-form-item>
<el-form-item label="设备类别">
<el-select v-model="formInline.type" style="width: 200px">
<el-option
v-for="i in typeList.list"
:key="i"
:label="`${i.label}`"
:value="i.value"
/>
</el-select>
</el-form-item>
<el-form-item label="原因分类">
<el-select v-model="formInline.reason" style="width: 200px">
<el-option
v-for="i in reasonList.list"
:key="i"
:label="`${i.label}`"
:value="i.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="default" class="default-btn" @click="onSubmit"
>重置</el-button
>
<el-button type="primary" class="search-btn" @click="onSubmit"
>查询</el-button
>
</el-form-item>
</el-form>
</div>
<div class="table-box">
<common-table
:data="tableData.list"
:columns="tableColumns"
:default-page-size="10"
@pagination-change="handlePaginationChange"
:pagination-texts="{
total: '共',
sizeChange: '条/页',
prev: '前一页',
next: '后一页',
jumper: '跳至',
}"
>
<template #index="{ $index }">
{{ getIndex($index) }}
</template>
<template #deviceName="{ row }">
<span class="health-score" @dblclick="openDialog(row.deviceName)">{{
row.deviceName
}}</span>
</template>
<!-- <template #operation="{ row }">
<span class="view-btn" @click="handleView(row)">详情</span>
<span class="edit-btn" @click="handleEdit(row)">编辑</span>
</template> -->
</common-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed, reactive } from "vue";
import CommonTable from "@/components/commonTable/index.vue";
const formInline = ref({
eventName: "",
deviceName: "",
position: "",
type: "",
date: "",
warnType: "3",
});
const currentPage = ref(1);
const pageSize = ref(10);
const tableColumns = ref([
{
prop: "index",
label: "序号",
width: "5%",
},
{
prop: "deviceName",
label: "项目名称",
width: "7%",
},
{
prop: "compart",
label: "设备编号",
width: "7%",
},
{
prop: "position",
label: "设备类型",
width: "7%",
},
{
prop: "changeDateRemind",
label: "设备名称",
width: "7%",
},
{
prop: "changeDate",
label: "设备信号编号",
width: "7%",
},
{
prop: "changePeo",
label: "设备所在位置",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "挂起开始时间",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "结束时间",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "原因分类",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "原因描述",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "创建时间",
width: "7%",
},
{
prop: "ownerdeviceName",
label: "创建人",
width: "7%",
},
{
prop: "lastAlarmTime",
label: "操作",
width: "8%",
},
]);
const tableData = reactive({
list: [
{
deviceName: "1#除尘器",
compart: "1234567890",
position: "转炉",
changeDateRemind: "xx",
changeDate: "xx",
changePeo: "xx",
ownerdeviceName: "xx",
lastAlarmTime: "xx",
changeRound: "xx",
},
],
});
const nameList = reactive({
list: [],
});
const getNameList = () => {
nameList.list = [
{
label: "1#除尘器",
value: "11111",
},
{
label: "2#除尘器",
value: "22222",
},
{
label: "3#除尘器",
value: "333333",
},
];
};
const typeList = reactive({
list: [],
});
const getTypeList = () => {
typeList.list = [
{
label: "1#除尘器",
value: "11111",
},
{
label: "2#除尘器",
value: "22222",
},
{
label: "3#除尘器",
value: "333333",
},
];
};
const reasonList = reactive({
list: [],
});
const getReasonList = () => {
reasonList.list = [
{
label: "1#除尘器",
value: "11111",
},
{
label: "2#除尘器",
value: "22222",
},
{
label: "3#除尘器",
value: "333333",
},
];
};
const getIndex = (index) => {
return (currentPage.value - 1) * pageSize.value + index + 1;
};
const handlePaginationChange = (pagination) => {
currentPage.value = pagination.currentPage;
pageSize.value = pagination.pageSize;
console.log("分页变化", pagination);
};
const onSubmit = () => {
console.log("submit!", formInline.value);
};
onMounted(async () => {
getNameList();
getTypeList();
getReasonList();
});
onBeforeUnmount(() => {});
</script>
<style lang="scss" scoped>
.collectorList {
width: 100%;
height: calc(100% - 14px);
box-sizing: border-box;
:deep(.el-input--small) {
width: 100%;
}
.content-box {
margin-top: 24px;
.search {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-box {
width: 100%;
height: calc(100vh - 400px);
}
}
.default-btn {
width: 85px;
}
.search-btn {
width: 85px;
background: #2182a0;
border: 1px solid #2182a0;
}
.add-btn {
width: 85px;
}
.health-score {
color: #027ffc;
cursor: pointer;
display: block;
width: 100%;
}
.status-matrix {
width: fit-content;
display: flex;
padding: 10px;
box-sizing: border-box;
flex-direction: column;
align-items: flex-start;
gap: 6px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.matrix-row {
display: flex;
gap: 6px;
justify-content: flex-start;
}
.status-dot {
width: 14px;
height: 14px;
border-radius: 50%;
&:hover {
cursor: pointer;
transform: scale(1.2);
}
}
.status-normal {
background-color: #67c23a; // 绿色
}
.status-warning {
background-color: #e6a23c; // 橙色
}
.status-error {
background-color: #f56c6c; // 红色
}
}
.view-btn {
margin-right: 8px;
}
.dialog-footer {
display: flex;
justify-content: center;
gap: 12px;
}
:deep(.el-dialog__body) {
padding: 20px;
}
.distribution-table {
margin-top: 20px;
border-top: 1px solid #ebeef5;
padding-top: 20px;
}
.table-title {
font-size: 14px;
color: #2182a0;
margin-bottom: 16px;
font-weight: 500;
}
:deep(.el-input-number.el-input-number--small) {
width: 130px;
}
:deep(.distribution-table .el-table--border .el-table__cell) {
border-right: 1px solid #ebeef5 !important;
}
.valve-setting {
.setting-row {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 20px;
.input-group {
display: flex;
align-items: center;
gap: 8px;
span {
white-space: nowrap;
color: #606266;
}
}
}
}
.valve-distribution-grid {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
background: #f5f7fa;
border-radius: 4px;
.valve-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.valve-cell {
width: 41px;
background: white;
padding: 4px;
border-radius: 4px;
text-align: center;
border: 1px solid #dcdfe6;
.cell-index {
font-size: 12px;
color: #909399;
margin-bottom: 8px;
}
.cell-value {
:deep(.el-input-number) {
width: 100px;
}
}
}
}
.readonly-value {
font-size: 14px;
color: #606266;
line-height: 32px;
padding: 0 12px;
}
.distribution-warning {
display: inline-block;
font-size: 13px;
margin-left: 12px;
padding: 2px 8px;
border-radius: 4px;
&.warning-more {
color: #e6a23c;
background-color: #fdf6ec;
}
&.warning-less {
color: #f56c6c;
background-color: #fef0f0;
}
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment