feat/平面图拖拽判断精度优化,设定温度问题修复

This commit is contained in:
季万俊 2025-12-25 15:07:37 +08:00
parent 0c44fe5ec3
commit 3c5cd8016a
7 changed files with 292 additions and 147 deletions

View File

@ -4,3 +4,16 @@
* @Description: * @Description:
*/ */
window.CustomMqttUrl = 'ws://111.229.30.246:4199/mqtt' window.CustomMqttUrl = 'ws://111.229.30.246:4199/mqtt'
// 区域配置
window.ShiYanRegionConfig = [
{ area: 1, x: 0, y: 420, name: "9栋3单元", code: '0101' },
{ area: 2, x: 0, y: 220, name: "1栋2单元", code: '0102' },
{ area: 3, x: 450, y: 410, name: "2栋1单元", code: '0201' },
{ area: 4, x: 450, y: 200, name: "2栋2单元", code: '0202' },
{ area: 5, x: 1100, y: 430, name: "3栋1单元", code: '0301' },
{ area: 6, x: 1100, y: 220, name: "3栋2单元", code: '0302' },
{ area: 7, x: 100, y: 0, name: "4栋1单元", code: '0401' },
{ area: 8, x: 800, y: 0, name: "4栋2单元", code: '0402' },
{ area: 9, x: 200, y: 600, name: "广场", code: 'ground' },
]

View File

@ -602,48 +602,48 @@ export const constantRoutes = [
// ] // ]
// }, // },
{ // {
name: "Security", // name: "Security",
alwaysShow: true, // alwaysShow: true,
component: Layout, // component: Layout,
hidden: false, // hidden: false,
name: "Security", // name: "Security",
path: "/Security", // path: "/Security",
redirect: "noRedirect", // redirect: "noRedirect",
meta: { // meta: {
icon: "afxt", // icon: "afxt",
link: null, // link: null,
noCache: false, // noCache: false,
title: "安防系统", // title: "安防系统",
}, // },
children: [ // children: [
{ // {
component: () => import('@/views/Security/videoSurveillance'), // component: () => import('@/views/Security/videoSurveillance'),
hidden: false, // hidden: false,
name: "videoSurveillance", // name: "videoSurveillance",
path: "videoSurveillance", // path: "videoSurveillance",
meta: { // meta: {
icon: "spjk", // icon: "spjk",
link: null, // link: null,
noCache: false, // noCache: false,
title: "视频监控", // title: "视频监控",
}, // },
}, // },
{ // {
component: () => import('@/views/Security/doorControl'), // component: () => import('@/views/Security/doorControl'),
hidden: false, // hidden: false,
name: "doorControl", // name: "doorControl",
path: "doorControl", // path: "doorControl",
meta: { // meta: {
icon: "afmj", // icon: "afmj",
link: null, // link: null,
noCache: false, // noCache: false,
title: "门禁", // title: "门禁",
}, // },
}, // },
] // ]
}, // },
// { // {
// path: '', // path: '',
// component: Layout, // component: Layout,

View File

@ -68,7 +68,30 @@
<dl v-if="(item.IotAgreementHostPoint.register_type == '保持寄存器' && item.IotAgreementHostPoint.point_name.includes('控制') == false) || item.IotAgreementHostPoint.register_type == '输入寄存器'"> <dl v-if="(item.IotAgreementHostPoint.register_type == '保持寄存器' && item.IotAgreementHostPoint.point_name.includes('控制') == false) || item.IotAgreementHostPoint.register_type == '输入寄存器'">
<dt>{{ item.IotAgreementHostPoint.point_name }}:</dt> <dt>{{ item.IotAgreementHostPoint.point_name }}:</dt>
<dd> <dd>
<span>
{{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }} {{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
</span>
</dd>
</dl>
<dl v-if="props.TypeId == 82 && item.IotAgreementHostPoint.point_name == '设定温度' && item.IotAgreementHostPoint.register_type == '保持寄存器' ">
<dd>
<el-input-number
v-model="temperatureInputValues[item.IotAgreementHostPoint.id]"
:min="10"
:max="35"
:style="0.5"
:precision="2"
style="width: 110px;"
></el-input-number>
<el-button
type="primary"
style="margin-left: 10px;"
@click="
handleTemperatureConfirm(item, temperatureInputValues[item.IotAgreementHostPoint.id])
"
>
设定
</el-button>
</dd> </dd>
</dl> </dl>
</template> </template>
@ -139,30 +162,6 @@
<el-button type="primary" @click="topicControl(item, 0)">停止</el-button> <el-button type="primary" @click="topicControl(item, 0)">停止</el-button>
</dd> </dd>
</dl> </dl>
<dl v-if="props.TypeId === 82 && item.IotAgreementHostPoint.point_name.includes('设定温度') && item.IotAgreementHostPoint.register_type == '保持寄存器' ">
<dt>{{ item.IotAgreementHostPoint.point_name }}:</dt>
<dd>
<el-input-number
v-model="item.IotAgreementHostPoint.status"
:min="10"
:max="35"
:style="0.5"
:precision="2"
size="small"
style="width: 100px;"
></el-input-number>
<el-button
type="primary"
size="small"
style="margin-left: 10px;"
@click="
handleTemperatureConfirm(item, item.IotAgreementHostPoint.status)
"
>
设定
</el-button>
</dd>
</dl>
</template> </template>
</div> </div>
@ -233,22 +232,57 @@ const loading = ref(false);
let timmer = null; let timmer = null;
const toggle = ref(false); const toggle = ref(false);
// MQTT
// 使 point_id key
const temperatureInputValues = reactive({});
watch(dialogVisible, (newVal, oldVal) => { watch(dialogVisible, (newVal, oldVal) => {
if (newVal) { if (newVal) {
nextTick(() => { nextTick(() => {
getDeviceInfo(props.id); getDeviceInfo(props.id);
//
if (EquipmentData && EquipmentData.length > 0) {
initTemperatureInputValues(EquipmentData);
}
}); });
} else { } else {
clearTimeout(timmer); clearTimeout(timmer);
} }
}); });
//
const initTemperatureInputValues = (equipmentData) => {
if (!equipmentData || !Array.isArray(equipmentData)) return;
equipmentData.forEach((equipment) => {
if (equipment.Data && Array.isArray(equipment.Data)) {
equipment.Data.forEach((item) => {
const point = item.IotAgreementHostPoint;
//
if (point &&
props.TypeId === 82 &&
point.point_name &&
point.point_name.includes('设定温度') &&
point.register_type === '保持寄存器') {
const pointId = point.id;
//
if (!(pointId in temperatureInputValues)) {
temperatureInputValues[pointId] = point.status || 0;
}
}
});
}
});
};
// props.extra // props.extra
watch(() => props.extra, (newExtra) => { watch(() => props.extra, (newExtra) => {
if (newExtra && dialogVisible.value) { if (newExtra && dialogVisible.value) {
// EquipmentData // EquipmentData
if (EquipmentData.length === 0 || !EquipmentData[0] || EquipmentData[0].DeviceId !== newExtra.DeviceId) { if (EquipmentData.length === 0 || !EquipmentData[0] || EquipmentData[0].DeviceId !== newExtra.DeviceId) {
EquipmentData = [newExtra]; EquipmentData = [newExtra];
//
initTemperatureInputValues(EquipmentData);
} else { } else {
// Data // Data
if (newExtra.Data && Array.isArray(newExtra.Data) && EquipmentData[0].Data) { if (newExtra.Data && Array.isArray(newExtra.Data) && EquipmentData[0].Data) {
@ -309,6 +343,8 @@ onMounted(async () => {
nextTick(() => { nextTick(() => {
EquipmentData = [props.extra]; EquipmentData = [props.extra];
console.log(EquipmentData, "===> EquipmentData"); console.log(EquipmentData, "===> EquipmentData");
//
initTemperatureInputValues(EquipmentData);
isRefresh.value = true; isRefresh.value = true;
}); });
}); });
@ -437,6 +473,20 @@ const getControlTopic = () => {
return window.getControlTopic ? window.getControlTopic() : 'shiyan/control'; return window.getControlTopic ? window.getControlTopic() : 'shiyan/control';
}; };
// userId
const getUserId = () => {
try {
const userInfo = localStorage.getItem('APP_USER_INFO');
if (userInfo) {
const user = JSON.parse(userInfo);
return user?.userId || user?.user_id || user?.id || '';
}
} catch (err) {
console.warn('读取用户信息失败', err);
}
return '';
};
// topicControl MQTT // topicControl MQTT
const topicControl = async (pointData = null, Value = true) => { const topicControl = async (pointData = null, Value = true) => {
const client = getMqttClient(); const client = getMqttClient();
@ -448,11 +498,15 @@ const topicControl = async (pointData = null, Value = true) => {
// GUID // GUID
const guid = generateGuid(); const guid = generateGuid();
// userId
const userId = getUserId();
// 使 // 使
const controlData = { const controlData = {
id: guid, id: guid,
point_id: pointData.IotAgreementHostPoint.id, point_id: pointData.IotAgreementHostPoint.id,
value: Value, //线 true false 1 0 value: Value, //线 true false 1 0
userId: userId,
}; };
// control_topic // control_topic
@ -479,11 +533,15 @@ const spTopicControl = async (pointData = null) => {
// GUID使 GUID // GUID使 GUID
const guid = generateGuid(); const guid = generateGuid();
// userId
const userId = getUserId();
// true // true
const controlDataTrue = { const controlDataTrue = {
id: guid, id: guid,
point_id: pointId, point_id: pointId,
value: true, value: true,
userId: userId,
}; };
await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 }); await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 });
@ -502,6 +560,7 @@ const spTopicControl = async (pointData = null) => {
id: guid, id: guid,
point_id: pointId, point_id: pointId,
value: false, value: false,
userId: userId,
}; };
await clientAgain.mqttPublish(controlTopic, controlDataFalse, { qos: 1 }); await clientAgain.mqttPublish(controlTopic, controlDataFalse, { qos: 1 });

View File

@ -831,6 +831,20 @@ export default {
: "shiyan_control"; : "shiyan_control";
}; };
// userId
const getUserId = () => {
try {
const userInfo = localStorage.getItem('APP_USER_INFO');
if (userInfo) {
const user = JSON.parse(userInfo);
return user?.userId || user?.user_id || user?.id || '';
}
} catch (err) {
console.warn('读取用户信息失败', err);
}
return '';
};
// topicControl MQTT // topicControl MQTT
const topicControl = async (pointData = null, Value = true, skipConfirm = false) => { const topicControl = async (pointData = null, Value = true, skipConfirm = false) => {
console.log(Value,"Value"); console.log(Value,"Value");
@ -855,11 +869,15 @@ export default {
// GUID // GUID
const guid = generateGuid(); const guid = generateGuid();
// userId
const userId = getUserId();
// //
const controlData = { const controlData = {
id: guid, id: guid,
point_id: pointData.IotAgreementHostPoint.id, point_id: pointData.IotAgreementHostPoint.id,
value: Value, //线 true false 1 0 value: Value, //线 true false 1 0
userId: userId,
}; };
// control_topic // control_topic
@ -987,11 +1005,15 @@ export default {
// GUID使 GUID // GUID使 GUID
const guid = generateGuid(); const guid = generateGuid();
// userId
const userId = getUserId();
// true // true
const controlDataTrue = { const controlDataTrue = {
id: guid, id: guid,
point_id: pointId, point_id: pointId,
value: true, value: true,
userId: userId,
}; };
await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 }); await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 });
@ -1010,6 +1032,7 @@ export default {
id: guid, id: guid,
point_id: pointId, point_id: pointId,
value: false, value: false,
userId: userId,
}; };
await clientAgain.mqttPublish(controlTopic, controlDataFalse, { await clientAgain.mqttPublish(controlTopic, controlDataFalse, {

View File

@ -22,11 +22,11 @@
:model="sensor" :model="sensor"
:rules="thresholdRules" :rules="thresholdRules"
ref="formRefs" ref="formRefs"
label-width="100px" label-width="80px"
class="threshold-form" class="threshold-form"
> >
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="7">
<el-form-item <el-form-item
label="限值一" label="限值一"
prop="upper_threshold" prop="upper_threshold"
@ -36,12 +36,13 @@
:min="0" :min="0"
:max="1000" :max="1000"
:precision="2" :precision="2"
controls-position="right"
style="width: 100%" style="width: 100%"
:placeholder="`请输入上限阈值${sensor.unit}`" :placeholder="`请输入上限阈值${sensor.unit}`"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="7">
<el-form-item <el-form-item
label="限值二" label="限值二"
prop="lower_threshold" prop="lower_threshold"
@ -51,11 +52,29 @@
:min="0" :min="0"
:max="1000" :max="1000"
:precision="2" :precision="2"
controls-position="right"
style="width: 100%" style="width: 100%"
:placeholder="`请输入下限阈值${sensor.unit}`" :placeholder="`请输入下限阈值${sensor.unit}`"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10">
<el-form-item
label="采集频率(分钟)"
prop="lower_threshold"
class="sp-label"
>
<el-input-number
v-model="sensor.history_data_frequency"
:min="1"
:max="1000"
:precision="2"
controls-position="right"
style="width: 100%"
:placeholder="`请输入采集频率`"
/>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-form-item> <el-form-item>
@ -302,4 +321,8 @@ onMounted(() => {
background-color: #66b1ff; background-color: #66b1ff;
border-color: #66b1ff; border-color: #66b1ff;
} }
::v-deep .sp-label .el-form-item__label {
width: 120px !important;
}
</style> </style>

View File

@ -148,7 +148,7 @@ import { getArea } from "@/api/area.js";
import { getDeviceType, getDevices, updateDevice } from "@/api/device.js"; import { getDeviceType, getDevices, updateDevice } from "@/api/device.js";
import { ElMessage, ElNotification } from "element-plus"; import { ElMessage, ElNotification } from "element-plus";
import dialogEle from "./../components/dialogEle.vue"; import dialogEle from "./../components/dialogEle.vue";
import { ref, onMounted, onUnmounted, reactive, nextTick, provide } from "vue"; import { ref, onMounted, onUnmounted, reactive, nextTick, provide, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { shiyan_typesDictionary } from "../../utils/equipmentType"; // import { shiyan_typesDictionary } from "../../utils/equipmentType"; //
import videoEle from "./../components/videoEle.vue"; import videoEle from "./../components/videoEle.vue";
@ -301,17 +301,20 @@ const deviceList = ref([]);
let StandardC = 948; // let StandardC = 948; //
let BL = ref(0); // / let BL = ref(0); // /
const region = ref([ // 使
{ area: 1, x: 0, x_b: 0, y: 450, name: "1栋1单元" }, const region = ref(
{ area: 2, x: 0, x_b: 0, y: 240, name: "1栋2单元" }, window.ShiYanRegionConfig || [
{ area: 3, x: 450, x_b: 0, y: 410, name: "2栋1单元" }, { area: 1, x: 0, y: 450, name: "1栋1单元", code: '0101' },
{ area: 4, x: 450, x_b: 0, y: 200, name: "2栋2单元" }, { area: 2, x: 0, y: 240, name: "1栋2单元", code: '0102' },
{ area: 5, x: 1100, x_b: 0, y: 430, name: "3栋1单元" }, { area: 3, x: 450, y: 410, name: "2栋1单元", code: '0201' },
{ area: 6, x: 1100, x_b: 0, y: 220, name: "3栋2单元" }, { area: 4, x: 450, y: 200, name: "2栋2单元", code: '0202' },
{ area: 7, x: 100, x_b: 0, y: 0, name: "4栋1单元" }, { area: 5, x: 1100, y: 430, name: "3栋1单元", code: '0301' },
{ area: 8, x: 800, x_b: 0, y: 0, name: "4栋2单元" }, { area: 6, x: 1100, y: 220, name: "3栋2单元", code: '0302' },
{ area: 9, x: 200, x_b: 0, y: 600, name: "广场" }, { area: 7, x: 100, y: 0, name: "4栋1单元", code: '0401' },
]); { area: 8, x: 800, y: 0, name: "4栋2单元", code: '0402' },
{ area: 9, x: 200, y: 600, name: "广场", code: 'ground' },
]
);
// //
const imgAspectRatio = ref(1); const imgAspectRatio = ref(1);
@ -699,17 +702,23 @@ const editFun = () => {
} }
}; };
// code region label
const getLabelByCode = (code) => {
const matchedRegion = region.value.find((r) => r.code === code);
return matchedRegion ? matchedRegion.name : '';
};
const rects = reactive([ const rects = reactive([
{ {
code: "0401", code: "0401",
y: 10, y: 10,
label: "4栋1单元", label: getLabelByCode("0401"),
height: 220, height: 220,
}, },
{ {
code: "0402", code: "0402",
y: 10, y: 10,
label: "4栋2单元", label: getLabelByCode("0402"),
height: 220, height: 220,
}, },
]); ]);
@ -718,17 +727,17 @@ const rects1 = reactive([
{ {
code: "0102", code: "0102",
y: 240, y: 240,
label: "1栋2单元", label: getLabelByCode("0102"),
}, },
{ {
code: "0202", code: "0202",
y: 240, y: 240,
label: "2栋2单元", label: getLabelByCode("0202"),
}, },
{ {
code: "0302", code: "0302",
y: 240, y: 240,
label: "3栋2单元", label: getLabelByCode("0302"),
}, },
]); ]);
@ -736,17 +745,17 @@ const rects2 = reactive([
{ {
code: "0101", code: "0101",
y: 430, y: 430,
label: "1栋1单元", label: getLabelByCode("0101"),
}, },
{ {
code: "0201", code: "0201",
y: 430, y: 430,
label: "2栋1单元", label: getLabelByCode("0201"),
}, },
{ {
code: "0301", code: "0301",
y: 430, y: 430,
label: "3栋1单元", label: getLabelByCode("0301"),
}, },
]); ]);
@ -754,10 +763,35 @@ const rect_ground = reactive([
{ {
code: "ground", code: "ground",
y: 620, y: 620,
label: "广场", label: getLabelByCode("ground"),
}, },
]); ]);
// region rects label
const updateRectsLabels = () => {
rects.forEach((rect) => {
rect.label = getLabelByCode(rect.code);
});
rects1.forEach((rect) => {
rect.label = getLabelByCode(rect.code);
});
rects2.forEach((rect) => {
rect.label = getLabelByCode(rect.code);
});
rect_ground.forEach((rect) => {
rect.label = getLabelByCode(rect.code);
});
};
// region
watch(
() => region.value,
() => {
updateRectsLabels();
},
{ deep: true, immediate: true }
);
let s_w = 0.8; let s_w = 0.8;
const getDeviceTypeFun = async () => { const getDeviceTypeFun = async () => {
@ -791,21 +825,17 @@ const getDevicesFun = async () => {
devicesByRegion[regionName].push(item); devicesByRegion[regionName].push(item);
}); });
// 2) region_name region
deviceList.value = list.map((item) => { deviceList.value = list.map((item) => {
const regionName = item.region_name || ""; const regionName = item.region_name || "";
// region name
const matchedRegion = region.value.find((r) => r.name === regionName); const matchedRegion = region.value.find((r) => r.name === regionName);
let finalX = item.x ?? 300; let finalX = item.x ?? 300;
let finalY = item.y ?? 300; let finalY = item.y ?? 300;
if (matchedRegion) { if (matchedRegion) {
// region使 region x y
finalX = matchedRegion.x; finalX = matchedRegion.x;
finalY = matchedRegion.y + 50; finalY = matchedRegion.y + 50;
// region
const regionDevices = devicesByRegion[regionName] || []; const regionDevices = devicesByRegion[regionName] || [];
const deviceIndex = regionDevices.findIndex((d) => { const deviceIndex = regionDevices.findIndex((d) => {
// 使使 DeviceId使 // 使使 DeviceId使
@ -1743,20 +1773,20 @@ const handleMouseMove = (e) => {
let newActiveMarker = { target: "" }; let newActiveMarker = { target: "" };
points.forEach((point) => { points.forEach((point) => {
if (!point.path) { // 使 scale
point.path = new Path2D(); if (point.TypeId == SELECT_ACTION_TYPE.value || SELECT_ACTION_TYPE.value == "") {
point.path.arc( const pointX = point.x * BL.value;
point.x * BL.value, const pointY = point.y * BL.value;
point.y * BL.value, // pointSize * 0.2 * BL
pointSize.value * BL.value, // (pointSize * scale * 0.2 * BL) / scale = pointSize * 0.2 * BL
0, const detectRadius = pointSize.value * 0.2 * BL.value;
Math.PI * 2 const distance = Math.sqrt(
Math.pow(originalX - pointX, 2) + Math.pow(originalY - pointY, 2)
); );
} if (distance <= detectRadius) {
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
newActiveMarker = point; newActiveMarker = point;
} }
}
}); });
if ( if (
@ -1788,18 +1818,15 @@ const startDrag = (e) => {
if (isEdit.value) { if (isEdit.value) {
points.forEach((point) => { points.forEach((point) => {
if (!point.path) { if (point.TypeId == SELECT_ACTION_TYPE.value || SELECT_ACTION_TYPE.value == "") {
point.path = new Path2D(); const pointX = point.x * BL.value;
point.path.arc( const pointY = point.y * BL.value;
point.x * BL.value, // pointSize * 0.2 * BL
point.y * BL.value, const detectRadius = pointSize.value * 0.2 * BL.value;
pointSize.value * BL.value, const distance = Math.sqrt(
0, Math.pow(originalX - pointX, 2) + Math.pow(originalY - pointY, 2)
Math.PI * 2
); );
} if (distance <= detectRadius) {
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
dragging.value = "point"; dragging.value = "point";
currentPoint = point; currentPoint = point;
startPointX.value = point.x * BL.value; startPointX.value = point.x * BL.value;
@ -1808,6 +1835,7 @@ const startDrag = (e) => {
startDragY.value = mouseY; startDragY.value = mouseY;
return; return;
} }
}
}); });
} }
@ -1846,8 +1874,9 @@ const endDrag = (type) => {
currentPoint.y * BL.value, currentPoint.y * BL.value,
pointSize.value * BL.value, pointSize.value * BL.value,
0, 0,
Math.PI * 2 2 * Math.PI
); );
currentPoint.path.closePath();
} }
}; };
@ -1915,18 +1944,15 @@ const handleCanvasClick = (e) => {
let clickedPoint = false; let clickedPoint = false;
points.forEach((point) => { points.forEach((point) => {
if (!point.path) { if (point.TypeId == SELECT_ACTION_TYPE.value || SELECT_ACTION_TYPE.value == "") {
point.path = new Path2D(); const pointX = point.x * BL.value;
point.path.arc( const pointY = point.y * BL.value;
point.x * BL.value, // pointSize * 0.2 * BL
point.y * BL.value, const detectRadius = pointSize.value * 0.2 * BL.value;
pointSize.value * BL.value, const distance = Math.sqrt(
0, Math.pow(originalX - pointX, 2) + Math.pow(originalY - pointY, 2)
Math.PI * 2
); );
} if (distance <= detectRadius) {
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
clickedPoint = true; clickedPoint = true;
if (point.target == "camera") { if (point.target == "camera") {
selectPoint(point); selectPoint(point);
@ -1937,6 +1963,7 @@ const handleCanvasClick = (e) => {
selectPoint(point); selectPoint(point);
} }
} }
}
}); });
if (!clickedPoint) { if (!clickedPoint) {

View File

@ -7,7 +7,7 @@ import { defineConfig, loadEnv } from 'vite'
import path from 'path' import path from 'path'
import createVitePlugins from './vite/plugins' import createVitePlugins from './vite/plugins'
const baseUrl = 'http://325ccefb.r3.cpolar.top' const baseUrl = 'http://172.16.1.165:18080'
// https://vitejs.dev/config/ // https://vitejs.dev/config/