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

@ -3,4 +3,17 @@
* @Date: 2025-09-26 16:33:30
* @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",
alwaysShow: true,
component: Layout,
hidden: false,
name: "Security",
path: "/Security",
redirect: "noRedirect",
meta: {
icon: "afxt",
link: null,
noCache: false,
title: "安防系统",
},
children: [
{
component: () => import('@/views/Security/videoSurveillance'),
hidden: false,
name: "videoSurveillance",
path: "videoSurveillance",
meta: {
icon: "spjk",
link: null,
noCache: false,
title: "视频监控",
},
},
{
component: () => import('@/views/Security/doorControl'),
hidden: false,
name: "doorControl",
path: "doorControl",
meta: {
icon: "afmj",
link: null,
noCache: false,
title: "门禁",
},
},
]
// {
// name: "Security",
// alwaysShow: true,
// component: Layout,
// hidden: false,
// name: "Security",
// path: "/Security",
// redirect: "noRedirect",
// meta: {
// icon: "afxt",
// link: null,
// noCache: false,
// title: "安防系统",
// },
// children: [
// {
// component: () => import('@/views/Security/videoSurveillance'),
// hidden: false,
// name: "videoSurveillance",
// path: "videoSurveillance",
// meta: {
// icon: "spjk",
// link: null,
// noCache: false,
// title: "视频监控",
// },
// },
// {
// component: () => import('@/views/Security/doorControl'),
// hidden: false,
// name: "doorControl",
// path: "doorControl",
// meta: {
// icon: "afmj",
// link: null,
// noCache: false,
// title: "门禁",
// },
// },
// ]
},
// },
// {
// path: '',
// component: Layout,

View File

@ -68,9 +68,32 @@
<dl v-if="(item.IotAgreementHostPoint.register_type == '保持寄存器' && item.IotAgreementHostPoint.point_name.includes('控制') == false) || item.IotAgreementHostPoint.register_type == '输入寄存器'">
<dt>{{ item.IotAgreementHostPoint.point_name }}:</dt>
<dd>
{{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
<span>
{{ 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>
</dl>
</template>
</div>
@ -139,30 +162,6 @@
<el-button type="primary" @click="topicControl(item, 0)">停止</el-button>
</dd>
</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>
</div>
@ -233,22 +232,57 @@ const loading = ref(false);
let timmer = null;
const toggle = ref(false);
// MQTT
// 使 point_id key
const temperatureInputValues = reactive({});
watch(dialogVisible, (newVal, oldVal) => {
if (newVal) {
nextTick(() => {
getDeviceInfo(props.id);
//
if (EquipmentData && EquipmentData.length > 0) {
initTemperatureInputValues(EquipmentData);
}
});
} else {
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
watch(() => props.extra, (newExtra) => {
if (newExtra && dialogVisible.value) {
// EquipmentData
if (EquipmentData.length === 0 || !EquipmentData[0] || EquipmentData[0].DeviceId !== newExtra.DeviceId) {
EquipmentData = [newExtra];
//
initTemperatureInputValues(EquipmentData);
} else {
// Data
if (newExtra.Data && Array.isArray(newExtra.Data) && EquipmentData[0].Data) {
@ -309,6 +343,8 @@ onMounted(async () => {
nextTick(() => {
EquipmentData = [props.extra];
console.log(EquipmentData, "===> EquipmentData");
//
initTemperatureInputValues(EquipmentData);
isRefresh.value = true;
});
});
@ -437,6 +473,20 @@ const getControlTopic = () => {
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
const topicControl = async (pointData = null, Value = true) => {
const client = getMqttClient();
@ -448,11 +498,15 @@ const topicControl = async (pointData = null, Value = true) => {
// GUID
const guid = generateGuid();
// userId
const userId = getUserId();
// 使
const controlData = {
id: guid,
point_id: pointData.IotAgreementHostPoint.id,
value: Value, //线 true false 1 0
userId: userId,
};
// control_topic
@ -479,11 +533,15 @@ const spTopicControl = async (pointData = null) => {
// GUID使 GUID
const guid = generateGuid();
// userId
const userId = getUserId();
// true
const controlDataTrue = {
id: guid,
point_id: pointId,
value: true,
userId: userId,
};
await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 });
@ -502,6 +560,7 @@ const spTopicControl = async (pointData = null) => {
id: guid,
point_id: pointId,
value: false,
userId: userId,
};
await clientAgain.mqttPublish(controlTopic, controlDataFalse, { qos: 1 });

View File

@ -831,6 +831,20 @@ export default {
: "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
const topicControl = async (pointData = null, Value = true, skipConfirm = false) => {
console.log(Value,"Value");
@ -855,11 +869,15 @@ export default {
// GUID
const guid = generateGuid();
// userId
const userId = getUserId();
//
const controlData = {
id: guid,
point_id: pointData.IotAgreementHostPoint.id,
value: Value, //线 true false 1 0
userId: userId,
};
// control_topic
@ -986,12 +1004,16 @@ export default {
// GUID使 GUID
const guid = generateGuid();
// userId
const userId = getUserId();
// true
const controlDataTrue = {
id: guid,
point_id: pointId,
value: true,
userId: userId,
};
await client.mqttPublish(controlTopic, controlDataTrue, { qos: 1 });
@ -1010,6 +1032,7 @@ export default {
id: guid,
point_id: pointId,
value: false,
userId: userId,
};
await clientAgain.mqttPublish(controlTopic, controlDataFalse, {

View File

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

View File

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

View File

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