Commit 5668c8d1 authored by Cai Wei's avatar Cai Wei

feat(*): 除尘器总览页面

parent 3ced2d5b
......@@ -10,4 +10,17 @@
box-shadow: 0px 3px 6px 0px rgba(13,15,18,0.10);
padding: 1rem;
box-sizing: border-box;
}
.view-btn {
color: #2182a0 !important;
}
.edit-btn {
color: #2182a0 !important;
}
.el-button--primary {
background-color: #2182a0 !important;
border-color: #2182a0 !important;
}
\ No newline at end of file
......@@ -83,10 +83,35 @@
<template #index="{ $index }">
{{ getIndex($index) }}
</template>
<template #healthScore="{ row }">
<span class="health-score" @click="handleHealthScoreClick(row)">{{
row.healthScore
}}</span>
</template>
<template #health2Score="{ row }">
<span class="health-score" @click="handleHealth2ScoreClick(row)">{{
row.health2Score
}}</span>
</template>
<template #status="{ row }">
<el-tag :type="getStatusType(row.status)" effect="light">
{{ row.status }}
</el-tag>
<div class="status-matrix">
<div
v-for="(row, rowIndex) in row.status"
:key="rowIndex"
class="matrix-row"
>
<div
v-for="(status, colIndex) in row"
:key="colIndex"
class="status-dot"
:class="{
'status-normal': status.status === 1,
'status-warning': status.status === 2,
'status-error': status.status === 3,
}"
></div>
</div>
</div>
</template>
<template #alarmCount="{ row }">
......@@ -96,21 +121,174 @@
</template>
<template #operation="{ row }">
<el-button type="primary" link @click="handleView(row)">
详情
</el-button>
<el-button type="primary" link @click="handleEdit(row)">
编辑
</el-button>
<span class="view-btn" @click="handleView(row)">详情</span>
<span class="edit-btn" @click="handleEdit(row)">编辑</span>
</template>
</common-table>
</div>
</div>
<!-- 仓室数量设置弹窗 -->
<el-dialog
v-model="roomSettingVisible"
title="仓室数量设置"
width="500px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form :model="roomForm" label-width="120px">
<el-form-item label="仓室数量">
<!-- <span class="readonly-value">{{ roomForm.totalRooms }}</span> -->
<el-input
v-model="roomForm.totalRooms"
controls-position="right"
style="width: 150px"
disabled
/>
</el-form-item>
<el-form-item label="仓室分几排">
<el-input-number
v-model="roomForm.rows"
:min="1"
:max="20"
controls-position="right"
@change="handleRowsChange"
/>
</el-form-item>
</el-form>
<!-- 分布表格 -->
<div class="distribution-table">
<div class="table-title">
仓室数量分布
<div
v-if="distributionDiff !== 0"
:class="[
'distribution-warning',
distributionDiff > 0 ? 'warning-less' : 'warning-less',
]"
>
当前仓室总数{{ distributionDiff > 0 ? "大于" : "小于" }}默认仓室数量
{{ Math.abs(distributionDiff) }} 个,请修改。
</div>
</div>
<el-table
:data="distributionData"
style="width: 100%"
size="small"
border
>
<el-table-column prop="row" label="排" width="180" />
<el-table-column prop="count" label="仓数量">
<template #default="{ row }">
<el-input-number
v-model="row.count"
:min="1"
:max="50"
controls-position="right"
size="small"
@change="handleDistributionChange"
/>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="roomSettingVisible = false">取消</el-button>
<el-button type="primary" @click="handleRoomSettingConfirm">
确认
</el-button>
</span>
</template>
</el-dialog>
<!-- 电磁阀数量设置弹窗 -->
<el-dialog
v-model="valveSettingVisible"
title="电磁阀数量设置"
width="800px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="valve-setting">
<div class="setting-row">
<div class="input-group">
<span>电磁阀总数量:</span>
<el-input v-model="valveForm.total" style="width: 120px" disabled />
</div>
<el-button type="primary" @click="handleAverageDistribute"
>平均分布生成</el-button
>
</div>
<div class="table-title">仓室脉冲阀数量分布</div>
<div class="setting-row">
<div class="input-group">
<span>仓室编号:</span>
<el-select v-model="valveForm.roomNo" style="width: 120px">
<el-option
v-for="i in roomForm.rows"
:key="i"
:label="`${i}`"
:value="i"
/>
</el-select>
</div>
<div class="input-group">
<span>电磁阀分布数量:</span>
<el-input-number
v-model="valveForm.valveCount"
:min="1"
controls-position="right"
style="width: 120px"
/>
</div>
<div class="input-group">
<span>布阀数量:</span>
<el-input-number
v-model="valveForm.distribution"
:min="1"
controls-position="right"
style="width: 120px"
/>
</div>
</div>
</div>
<!-- 分布表格 -->
<div class="distribution-table">
<div class="table-title">仓室脉冲阀数量分布</div>
<div class="valve-distribution-grid">
<div class="valve-row">
<div
v-for="(cell, colIndex) in currentEditingRow?.status"
:key="colIndex"
class="valve-cell"
>
<div class="cell-index">{{ cell.index }}仓</div>
<div class="cell-value">
{{ currentEditingRow.status[colIndex].count }}
</div>
</div>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="valveSettingVisible = false">取消</el-button>
<el-button type="primary" @click="handleValveSettingConfirm">
保存
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { ref, onMounted, onBeforeUnmount, computed } from "vue";
import CommonTable from "@/components/commonTable/index.vue";
const formInline = ref({
......@@ -141,12 +319,12 @@ const tableColumns = ref([
{
prop: "deviceName",
label: "除尘器名称",
width: "15%",
width: "12%",
},
{
prop: "deviceName",
prop: "deviceNo",
label: "除尘器编号",
width: "15%",
width: "12%",
},
{
prop: "process",
......@@ -156,12 +334,12 @@ const tableColumns = ref([
{
prop: "healthScore",
label: "仓室数量",
width: "5%",
width: "8%",
},
{
prop: "health2Score",
label: "电磁阀数量",
width: "5%",
width: "8%",
},
{
prop: "status",
......@@ -188,30 +366,208 @@ const tableColumns = ref([
const tableData = [
{
deviceName: "1#除尘器",
deviceNo: "1234567890",
process: "转炉",
healthScore: 24,
health2Score: 120,
status: "正常运行",
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: "98%",
lastAlarmTime: "-",
location: "一号转炉东侧",
},
{
deviceName: "2#除尘器",
deviceNo: "1234567890",
process: "转炉",
healthScore: 24,
health2Score: 120,
status: "故障",
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: 24,
health2Score: 120,
status: "轻微异常",
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: "炼铁区域北侧",
......@@ -256,6 +612,139 @@ const onSubmit = () => {
console.log("submit!", formInline.value);
};
// 仓室设置相关
const roomSettingVisible = ref(false);
const roomForm = ref({
totalRooms: 0,
rows: 0,
});
const currentEditingRow = ref(null);
// 分布数据
const distributionData = ref([]);
// 计算分布差异
const distributionDiff = computed(() => {
const total = distributionData.value.reduce(
(sum, item) => sum + item.count,
0
);
return total - roomForm.value.totalRooms;
});
// 处理行数变化
const handleRowsChange = (value) => {
const total = roomForm.value.totalRooms;
if (!total || !value) return;
// 计算每行的基础数量(向下取整)和余数
const baseValue = Math.floor(total / value);
const remainder = total % value;
// 生成分布数据
distributionData.value = Array.from({ length: value }, (_, index) => {
const isLast = index === value - 1;
const count = isLast
? baseValue + remainder // 最后一项加上余数
: baseValue;
return {
row: `第${index + 1}排`,
count,
};
});
};
// 处理分布数量变化
const handleDistributionChange = () => {
// 移除自动更新总数的逻辑,保持总数不变
// const total = distributionData.value.reduce(
// (sum, item) => sum + item.count,
// 0
// );
// roomForm.value.totalRooms = total;
};
// 修改打开弹窗的处理函数
const handleHealthScoreClick = (row) => {
currentEditingRow.value = row;
console.log(currentEditingRow.value.status);
roomForm.value.totalRooms = row.healthScore;
roomForm.value.rows = row.status.length;
// 初始化分布数据
distributionData.value = row.status.map((item, index) => {
return {
row: `第${index + 1}排`,
count: item.length,
};
});
roomSettingVisible.value = true;
};
// 确认设置
const handleRoomSettingConfirm = () => {
if (currentEditingRow.value) {
currentEditingRow.value.healthScore = roomForm.value.totalRooms;
// 这里可以添加更新状态矩阵的逻辑
}
roomSettingVisible.value = false;
};
// 电磁阀设置相关
const valveSettingVisible = ref(false);
const valveForm = ref({
total: 120,
roomNo: 1,
valveCount: 5,
distribution: 30,
});
// 点击电磁阀数量时打开弹窗
const handleHealth2ScoreClick = (row) => {
currentEditingRow.value = JSON.parse(JSON.stringify(row));
currentEditingRow.value.status = currentEditingRow.value.status.flat();
valveForm.value.total = row.health2Score;
valveSettingVisible.value = true;
};
// 平均分布生成
const handleAverageDistribute = () => {
if (!currentEditingRow.value?.status) return;
const status = currentEditingRow.value.status;
const total = Number(valveForm.value.total) || 0;
// 计算总仓室数
const totalRooms = status.reduce((sum, row) => sum + row.length, 0);
if (totalRooms === 0 || total === 0) return;
// 计算基础平均值(向下取整)和余数
const baseValue = Math.floor(total / totalRooms);
const remainder = total % totalRooms;
// 先将所有仓室设置为基础值
status.forEach((row, rowIndex) => {
row.forEach((_, colIndex) => {
currentEditingRow.value.status[rowIndex][colIndex] = baseValue;
});
});
// 如果有余数,将其加到最后一个仓室
if (remainder > 0) {
const lastRow = status.length - 1;
const lastCol = status[lastRow].length - 1;
currentEditingRow.value.status[lastRow][lastCol] += remainder;
}
};
// 确认设置
const handleValveSettingConfirm = () => {
if (currentEditingRow.value) {
currentEditingRow.value.health2Score = valveForm.value.total;
}
valveSettingVisible.value = false;
};
onMounted(async () => {});
onBeforeUnmount(() => {});
......@@ -336,5 +825,169 @@ onBeforeUnmount(() => {});
.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