Commit ebcf087e authored by liuzhaoh's avatar liuzhaoh

解决冲突

parents cc98dce3 dc39c40b
......@@ -4,6 +4,7 @@
ref="tableRef"
:data="currentPageData"
v-bind="$attrs"
:resizable="false"
border
:height="tableHeight"
>
......@@ -221,6 +222,8 @@ watch(
width: 100% !important;
}
.el-table__header th { user-select: none; }
.el-table {
// 设置表头样式
th.el-table__cell {
......
import request from "../index.js";
export function getMonitorRealtime(params) {
return request({
url: "/api/duster/monitor/chamber",
method: "get",
params,
});
}
export function getMonitorToday(params) {
return request({
url: "/api/duster/monitor/curve",
method: "get",
params,
});
}
export function getMonitorList(params) {
return request({
url: "/api/duster/monitor/list",
method: "get",
params,
});
}
......@@ -4,6 +4,12 @@ import Layout from '../layout/index.vue'
// 检查路由是否在授权菜单中的函数
const checkRoutePermission = (route, menuList) => {
// bag-monitor 路由不需要权限验证
if (route.path === '/bag-monitor') {
return true;
}
// 检查当前路由
const hasPermission = menuList.some(menu =>
menu.name === route.meta?.title &&
......
......@@ -5,7 +5,7 @@ import NProgress from 'nprogress'
import 'nprogress/nprogress.css' // progress bar style
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
const whiteList = ['/login', '/auth-redirect', '/bag-monitor'] // no redirect whitelist
router.beforeEach(async (to, from, next) => {
const store = useUsersStore()
const hasToken = getToken('TOKEN')
......@@ -50,19 +50,6 @@ router.beforeEach(async (to, from, next) => {
}
} else {
try {
// debugger
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
// const roles = await store.getInfo()
// generate accessible routes map based on roles
// const menuLimitsObj = await store.menuLimitsObj
// const accessRoutes = await store.dispatch('permission/generateRoutes', { roles, menuLimitsObj })
// console.log("accessRoutes",accessRoutes)
// dynamically add accessible routes
// router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
// next({ ...to, replace: true })
next()
} catch (error) {
console.log(error)
......
......@@ -132,6 +132,7 @@ export const getBagMonitoringChartOption = (xData = [], seriesData = []) => ({
top: "3%",
containLabel: true,
},
// x轴的文字去除年月日
xAxis: {
type: "category",
boundaryGap: false,
......@@ -145,6 +146,9 @@ export const getBagMonitoringChartOption = (xData = [], seriesData = []) => ({
fontSize: 12,
interval: "auto",
rotate: 0,
formatter: function (value) {
return value.split(' ')[1];
}
},
axisTick: {
show: false,
......@@ -154,8 +158,8 @@ export const getBagMonitoringChartOption = (xData = [], seriesData = []) => ({
yAxis: {
type: "value",
min: 0,
max: 600,
interval: 200,
// max: 600,
// interval: 200,
axisLabel: {
color: "rgba(0,0,0,0.6)",
formatter: "{value}",
......
......@@ -150,6 +150,8 @@ import { useRoute, useRouter } from "vue-router";
import { getDataFun, postDataJSON } from "@/request/method.js";
import moment from "moment";
const route = useRoute();
const router = useRouter();
const formInline = ref({
eventName: "",
......@@ -157,9 +159,20 @@ const formInline = ref({
dusterName: "",
deviceType: "",
suspendFlag: "2",
date: "",
date: route.query.startTime
? [
moment(new Date(route.query.startTime).getTime()).format(
"YYYY-MM-DD HH:mm:ss"
),
moment(new Date(route.query.endTime).getTime()).format(
"YYYY-MM-DD HH:mm:ss"
),
]
: [],
});
const currentPage = ref(1);
const pageSize = ref(20);
const equDialog = ref(false);
......
......@@ -46,8 +46,8 @@
/>
</el-form-item>
<el-form-item>
<el-button class="default-btn" @click="onSearch">搜索</el-button>
<el-button type="primary" class="default-btn" @click="onReset">重置</el-button>
<el-button type="primary" class="default-btn" @click="onSearch">搜索</el-button>
<el-button class="default-btn" @click="onReset">重置</el-button>
</el-form-item>
</el-form>
<div class="table-box">
......
......@@ -46,6 +46,7 @@
<span class="label">描述:</span>
<div class="value">
<span class="value-item" v-for="(item, index) in spot.description" :key="index">{{ item }}</span>
<span class="value-item" v-if="spot.description.length === 0">暂无</span>
</div>
</div>
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
class="healthy-progress-bar h-full transition-all duration-500 ease-out bg-gradient-to-r from-secondary to-green-400 diagonal-pattern diagonal-pattern-animation"
></div>
<div class="justify-between items-center mb-2 healthy-text-position">
<span class="font-semibold">健康度</span>
<span class="font-semibold">健康度:</span>
<span id="square-progress-value" class="text-lg font-bold"> 45%</span>
</div>
</div>
......
<template>
<div class="title layout1">
<span class="warn-title">{{ title }}</span>
<span class="jump-icon">>></span>
<span class="warn-title">告警</span>
<!-- <span class="jump-icon">>></span> -->
</div>
<div class="content">
<div class="item" v-for="item in listInfo" :key="item">
......@@ -45,12 +45,15 @@ const props = defineProps({
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
margin-bottom: 5px;
padding: 4px 0px 4px 2px;
box-shadow: rgba(53,58,62,0.08) 0px 1px 10px 0px,rgba(53,58,62,0.08) 0px 2px 4px 0px;
box-shadow: rgba(53,58,62,0.04) 0px 1px 10px 0px,rgba(53,58,62,0.04) 0px 2px 4px 0px;
font-size: 14px;
color: #333;
img {
width: 20px;
height: auto;
margin-right: 10px;
}
}
}
......
......@@ -83,6 +83,7 @@
}"
v-for="item in detailObj.compartHealthList[0]"
:key="item"
@click="handleStatusDotClick()"
></div>
</div>
<div class="part">
......@@ -131,6 +132,7 @@
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import * as echarts from "echarts";
import { getDataFun } from "@/request/method.js";
import { useUsersStore } from "@/pinia/user.js";
......@@ -138,6 +140,7 @@ import moment from "moment";
import warnCom from "./components/warn.vue";
import healthyCom from "./components/healthyProgress.vue";
import { getLineOption2, getGaugeOption } from "@/utils/chart";
const userStore = useUsersStore();
const form = reactive({
dusterNo: "",
......@@ -179,6 +182,8 @@ const option = {
},
],
};
const router = useRouter();
const route = useRoute();
const chartInstance = reactive({});
const chartData = reactive([{}, {}, {}]);
const initChart = (instance, option, domEl) => {
......@@ -304,7 +309,7 @@ const getDusterNameEnum = () => {
.then((res) => {
dusterList.value = (res && res.data) || [];
// 判断除尘器名称是否有值
form.dusterNo = dusterList.value[0].dusterNo;
form.dusterNo = route.query.dusterNo || dusterList.value[0].dusterNo;
})
.catch(() => {
dusterList.value = [];
......@@ -583,6 +588,16 @@ const dusterName = computed(() => {
return dusterList.value.find((item) => item.dusterNo == form.dusterNo)
?.dusterName;
});
const handleStatusDotClick = () => {
router.push({
path: "/bag-monitor",
query: {
dusterNo: form.dusterNo,
dusterName: dusterName.value,
}
});
};
</script>
<style lang="scss" scoped>
$borderColor: #bbbdc391;
......@@ -627,7 +642,7 @@ $borderColor: #bbbdc391;
.part1 {
width: 100%;
height: 6vh;
height: 5vh;
border-radius: 6px;
border: 1px solid rgba(13, 15, 18, 0.1);
box-shadow: 0px 3px 6px 0px rgba(13, 15, 18, 0.1);
......@@ -642,7 +657,7 @@ $borderColor: #bbbdc391;
.part2 {
margin-top: 10px;
width: 100%;
height: calc(57vh - 10px);
height: calc(58vh - 10px);
border-radius: 6px;
border: 1px solid rgba(13, 15, 18, 0.1);
box-shadow: 0px 3px 6px 0px rgba(13, 15, 18, 0.1);
......
<template>
<el-dialog :model-value="modelValue" :title="editData ? '编辑除尘器' : '新增除尘器'" width="460px" :close-on-click-modal="false"
:close-on-press-escape="false" @update:model-value="$emit('update:modelValue', $event)">
<el-dialog :model-value="modelValue" :title="editData ? '编辑除尘器' : '新增除尘器'" width="500px" :close-on-click-modal="false"
:close-on-press-escape="false" @update:model-value="cancel">
<div class="add-dust-form">
<div class="form-item">
<div class="selector-wrap">
......@@ -14,7 +14,7 @@
</div>
<div class="form-content">
<el-form ref="formRef" :model="formData" label-width="100px" :rules="rules">
<el-form ref="formRef" :model="formData" label-width="120px" :rules="rules">
<el-form-item label="除尘器名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入" />
</el-form-item>
......@@ -38,7 +38,7 @@
<el-input v-model.number="formData.valveCount" placeholder="请输入" />
</el-form-item>
<el-form-item label="合理压差范围">
<el-form-item label="合理压差范围" required>
<div class="range-input">
<el-form-item prop="pressureMin" class="coordinate-item">
<el-input v-model.number="formData.pressureMin" placeholder="请输入" />
......@@ -119,26 +119,12 @@ const formData = reactive({
coordinateY: null
});
// 监听editData变化,初始化表单数据
watch(() => props.editData, (newVal) => {
if (newVal) {
formData.name = newVal.deviceName;
formData.code = newVal.deviceNo;
formData.process = newVal.productionLineId;
formData.chamberCount = Number(newVal.compartNum);
formData.valveCount = Number(newVal.valveNum);
formData.pressureMin = Number(newVal.pressureDiffLow);
formData.pressureMax = Number(newVal.pressureDiffHigh);
formData.serverIp = newVal.serviceIp;
formData.coordinateX = Number(newVal.x);
formData.coordinateY = Number(newVal.y);
}
}, { immediate: true });
const rules = {
name: [{ required: true, message: '请输入除尘器名称', trigger: 'blur' }],
code: [{ required: true, message: '请输入除尘器编号', trigger: 'blur' }],
process: [{ required: true, message: '请选择所属工序', trigger: 'change' }],
process: [{ required: true, message: '请选择所属工序', trigger: 'blur' }],
chamberCount: [
{ required: true, message: '请输入仓室数量', trigger: 'blur' },
{ type: 'number', min: 1, message: '仓室数量必须大于0', trigger: 'blur' }
......@@ -149,7 +135,7 @@ const rules = {
],
pressureMin: [
{ required: true, message: '请输入最小压差', trigger: 'blur' },
{ type: 'number', min: 1, message: '最小压差必须大于0', trigger: 'blur' },
{ type: 'number', min: 0, message: '最小压差不能小于0', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value && formData.pressureMax && value >= formData.pressureMax) {
......@@ -163,7 +149,7 @@ const rules = {
],
pressureMax: [
{ required: true, message: '请输入最大压差', trigger: 'blur' },
{ type: 'number', min: 0, message: '最大压差必须大于0', trigger: 'blur' },
{ type: 'number', min: 0, message: '最大压差不能小于0', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value && formData.pressureMin && value <= formData.pressureMin) {
......@@ -236,7 +222,6 @@ const productionLine = () => {
onMounted(() => {
productionLine();
initDustOptions();
});
const selectDustType = () => {
......@@ -270,7 +255,6 @@ const submitForm = () => {
if (props.editData) {
submitData.id = props.editData.id;
}
// 发送数据到父组件处理保存逻辑
emit('save', submitData);
// emit('update:modelValue', false);
......@@ -279,10 +263,8 @@ const submitForm = () => {
}
});
};
const cancel = () => {
const resetForm = () => {
// 重置表单状态和数据
formRef.value.resetFields();
formData.dustType = '';
formData.name = '';
formData.code = '';
......@@ -294,9 +276,38 @@ const cancel = () => {
formData.serverIp = '';
formData.coordinateX = null;
formData.coordinateY = null;
emit('update:modelValue', false);
}
const cancel = () => {
resetForm();
formRef.value.resetFields();
emit('cancel', {});
};
// 监听editData变化,初始化表单数据
watch(() => props.editData, (newVal) => {
if (newVal) {
formData.name = newVal.deviceName;
formData.code = newVal.deviceNo;
formData.process = newVal.productionLineId;
formData.chamberCount = Number(newVal.compartNum);
formData.valveCount = Number(newVal.valveNum);
formData.pressureMin = Number(newVal.pressureDiffLow);
formData.pressureMax = Number(newVal.pressureDiffHigh);
formData.serverIp = newVal.serviceIp;
formData.coordinateX = Number(newVal.x);
formData.coordinateY = Number(newVal.y);
} else {
resetForm();
}
}, { immediate: true });
watch(() => props.modelValue, (newVal) => {
if (newVal === false) {
resetForm();
}
}, { immediate: true });
</script>
<style lang="scss" scoped>
......@@ -343,7 +354,7 @@ const cancel = () => {
}
.form-footer {
margin-top: 20px;
margin-top: 30px;
display: flex;
justify-content: center;
......
......@@ -48,6 +48,7 @@
style="width: 100%"
size="small"
border
:resizable="false"
>
<el-table-column prop="compartPositionRow" label="排" width="180">
<template #default="{ row }">
......
......@@ -5,7 +5,7 @@
width="800px"
:close-on-click-modal="false"
:close-on-press-escape="false"
@update:model-value="$emit('update:modelValue', $event)"
@update:model-value="cancel"
>
<div class="valve-setting">
<div class="setting-row">
......@@ -37,6 +37,7 @@
:min="0"
controls-position="right"
style="width: 120px"
@change="handleValveNumChange"
:class="{ 'is-error': errorMessage }"
/>
</div>
......@@ -47,6 +48,7 @@
:min="0"
controls-position="right"
style="width: 120px"
@change="handleBagNumChange"
/>
</div>
</div>
......@@ -57,14 +59,14 @@
{{ errorMessage }}
</div>
<div>
<!-- <div>
<el-button
type="primary"
class="save-btn"
@click="handleSave"
:disabled="!!errorMessage || valveForm.valveNum === null || valveForm.bagNum === null"
>设置</el-button>
</div>
</div> -->
</div>
<!-- 分布表格 -->
......@@ -93,7 +95,7 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="$emit('update:modelValue', false)">取消</el-button>
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="handleConfirm" :disabled="!!errorMessage">
保存
</el-button>
......@@ -119,7 +121,7 @@ const emit = defineEmits(["update:modelValue", "confirm"]);
const valveForm = ref({
total: 0,
rows: 0,
frontCompartNo: 0,
frontCompartNo: null,
valveNum: 0,
bagNum: 0
});
......@@ -174,14 +176,25 @@ const initializeState = () => {
}
};
const resetForm = () => {
statusData.value = [];
valveForm.value.frontCompartNo = null;
valveForm.value.valveNum = 0;
valveForm.value.bagNum = 0;
}
const getAllocation = (params) => {
getValveAllocation(params).then(res => {
if (res.code === 1 && res.data.valveList.length > 0) {
statusData.value = res.data.valveList;
valveForm.value.frontCompartNo = statusData.value[0].frontCompartNo;
valveForm.value.valveNum = statusData.value[0].valveNum;
valveForm.value.bagNum = statusData.value[0].bagNum;
}
if (res.code === 1) {
if (res.data.valveList.length > 0) {
statusData.value = res.data.valveList;
valveForm.value.frontCompartNo = statusData.value[0].frontCompartNo;
valveForm.value.valveNum = statusData.value[0].valveNum;
valveForm.value.bagNum = statusData.value[0].bagNum;
} else {
resetForm();
}
}
})
}
......@@ -197,6 +210,45 @@ const handleRoomChange = (roomIndex) => {
}
};
// 监听电磁阀数量变化
const handleValveNumChange = () => {
// 验证是否超出限制
const validation = validateValveCount.value;
if (!validation.valid) {
errorMessage.value = validation.message;
return;
}
// 保存当前选中仓室的电磁阀分布数量
const selectedRoom = statusData.value.find(cell => cell.frontCompartNo === valveForm.value.frontCompartNo);
if (selectedRoom) {
selectedRoom.valveNum = valveForm.value.valveNum;
selectedRoom.bagNum = valveForm.value.bagNum;
// 更新错误信息
errorMessage.value = "";
}
}
// 监听布袋数量变化
const handleBagNumChange = () => {
// 验证是否超出限制
const validation = validateValveCount.value;
if (!validation.valid) {
errorMessage.value = validation.message;
return;
}
// 保存当前选中仓室的电磁阀分布数量
const selectedRoom = statusData.value.find(cell => cell.frontCompartNo === valveForm.value.frontCompartNo);
if (selectedRoom) {
selectedRoom.valveNum = valveForm.value.valveNum;
selectedRoom.bagNum = valveForm.value.bagNum;
// 更新错误信息
errorMessage.value = "";
}
}
watch(() => props.modelValue, (newVal) => {
if (newVal) {
initializeState();
......@@ -251,7 +303,6 @@ const handleSave = () => {
const handleConfirm = () => {
// 最终确认时再次验证总数是否符合要求
console.log(statusData.value);
const totalValves = statusData.value.reduce((sum, cell) => sum + cell.valveNum, 0);
if (totalValves > valveForm.value.total) {
errorMessage.value = `电磁阀总数超出限制 ${totalValves - valveForm.value.total} 个,请调整后再提交`;
......@@ -261,6 +312,11 @@ const handleConfirm = () => {
emit("confirm", statusData.value);
// emit("update:modelValue", false);
};
const cancel = () => {
resetForm();
emit("update:modelValue", false);
}
</script>
<style lang="scss" scoped>
......@@ -334,6 +390,7 @@ const handleConfirm = () => {
display: flex;
flex-direction: column;
gap: 8px;
min-height: 152px;
padding: 12px;
background: #f5f7fa;
border-radius: 4px;
......@@ -345,7 +402,7 @@ const handleConfirm = () => {
}
.valve-cell {
width: 41px;
min-width: 41px;
background: white;
padding: 4px 8px;
border-radius: 4px;
......@@ -368,7 +425,7 @@ const handleConfirm = () => {
.cell-value {
display: flex;
justify-content: center;
align-items: end;
align-items: baseline;
font-size: 16px;
color: #606266;
span {
......
<template>
<div class="page-container dust-container">
<div class="header">
<div class="item-box">
<div class="item-box crusor-click" @click="handleDusterLeakNumClick">
<img src="@/assets/icons/warn.png" alt="dust" />
<div class="title">
<span>泄漏告警(条)</span>
......@@ -17,7 +17,7 @@
</div>
</div>
<div class="item-box">
<div class="item-box crusor-click" @click="handleCloseLoopNumClick">
<img src="@/assets/icons/close.png" alt="dust" />
<div class="title">
<span>闭环(条)</span>
......@@ -102,18 +102,19 @@
<template #compartHealthList="{ row }">
<div class="status-matrix" v-if="row.compartHealthList.length > 0">
<div
v-for="(row, rowIndex) in row.compartHealthList"
v-for="(childRow, rowIndex) in row.compartHealthList"
:key="rowIndex"
class="matrix-row"
>
<div
v-for="(status, colIndex) in row"
v-for="(status, colIndex) in childRow"
:key="colIndex"
class="status-dot"
@click="handleStatusDotClick(row, colIndex)"
:class="{
'status-normal': status.healthStatus === 1,
'status-warning': status.healthStatus === 2,
'status-error': status.healthStatus === 3,
'status-warning': status.healthStatus === 3,
'status-error': status.healthStatus === 2,
}"
></div>
</div>
......@@ -158,6 +159,7 @@
v-model="isAddDustCollectorVisible"
:edit-data="currentEditingDustCollector"
@save="handleSaveDustCollector"
@cancel="handleCancel"
/>
</div>
</template>
......@@ -175,12 +177,15 @@ import {
postAddCompartAllocation,
postAddValveInfo,
} from "@/request/api/dustOverview";
import { useRouter } from "vue-router";
import { getToken } from "@/utils/auth";
import CommonTable from "@/components/commonTable/index.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import RoomSettingDialog from "./components/roomSettingDialog.vue";
import ValveSettingDialog from "./components/valveSettingDialog.vue";
import AddDustCollectorDialog from "./components/addDustCollectorDialog.vue";
import moment from "moment";
const router = useRouter();
const formInline = ref({
deviceName: "",
......@@ -280,19 +285,10 @@ const filterProductionLine = (query) => {
}
};
const getStatusType = (status) => {
const statusMap = {
正常运行: "success",
轻微异常: "warning",
故障: "danger",
};
return statusMap[status] || "info";
};
const getHealthScoreColor = (score) => {
// 去除百分号
const value = parseInt(score.replace("%", ""));
if (value >= 90) return "#67C23A";
if (value == 100) return "#67C23A";
if (value >= 70) return "#E6A23C";
return "#F56C6C";
};
......@@ -302,7 +298,12 @@ const getIndex = (index) => {
};
const handleView = (row) => {
console.log("查看详情", row);
router.push({
path: "/monitor",
query: {
dusterNo: row.deviceNo,
},
});
};
const handleEdit = (row) => {
......@@ -357,6 +358,34 @@ const handleValveNumClick = (row) => {
}
};
const handleStatusDotClick = (row, colIndex) => {
router.push({
path: "/bag-monitor",
query: {
dusterNo: row.deviceNo,
dusterName: row.deviceName,
}
});
};
const handleDusterLeakNumClick = () => {
router.push({
path: "/alerts",
query: {
startTime: moment().format("YYYY-MM-DD HH:mm:ss"),
endTime: moment().subtract(24, 'hours').format("YYYY-MM-DD HH:mm:ss"),
},
});
};
const handleCloseLoopNumClick = () => {
router.push({
path: "/my-loop/myAgency",
});
};
// 确认电磁阀设置
const handleValveSettingConfirm = (updatedStatusData) => {
const list = updatedStatusData.map((item) => {
......@@ -388,6 +417,10 @@ const setValveInfo = (data) => {
});
};
const handleCancel = () => {
isAddDustCollectorVisible.value = false;
currentEditingDustCollector.value = null;
};
// 保存新增或编辑除尘器
const handleSaveDustCollector = (data) => {
if (data.id) {
......@@ -412,6 +445,7 @@ const handleSaveDustCollector = (data) => {
.then((res) => {
if (res.code == 1) {
ElMessage.success("新增除尘器成功");
currentEditingDustCollector.value = null;
isAddDustCollectorVisible.value = false;
refreshData();
} else {
......@@ -540,6 +574,13 @@ onBeforeUnmount(() => {});
margin-top: 10px;
}
}
.crusor-click {
cursor: pointer;
transition: box-shadow 0.3s ease; // 添加过渡动画
&:hover {
box-shadow: 0px 1.33px 16px 0px rgba(83, 100, 170, 0.5);
}
}
}
.content-box {
margin-top: 24px;
......@@ -736,4 +777,14 @@ onBeforeUnmount(() => {});
}
}
}
:deep(.el-table) {
.el-table__column-resize-proxy {
display: none !important;
}
.el-table__header th {
user-select: none;
}
}
</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