diff --git a/public/config.js b/public/config.js
index 901178a..5119a4c 100644
--- a/public/config.js
+++ b/public/config.js
@@ -3,4 +3,17 @@
* @Date: 2025-09-26 16:33:30
* @Description:
*/
-window.CustomMqttUrl = 'ws://111.229.30.246:4199/mqtt'
\ No newline at end of file
+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' },
+]
\ No newline at end of file
diff --git a/src/router/index.js b/src/router/index.js
index f25df1f..1333e19 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -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,
diff --git a/src/views/components/dialogEle.vue b/src/views/components/dialogEle.vue
index b3c11a8..0cb7964 100644
--- a/src/views/components/dialogEle.vue
+++ b/src/views/components/dialogEle.vue
@@ -68,9 +68,32 @@
- {{ item.IotAgreementHostPoint.point_name }}:
-
- {{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
+
+ {{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
+
+
+ -
+
+
+ 设定
+
+
+
@@ -139,30 +162,6 @@
停止
-
- - {{ item.IotAgreementHostPoint.point_name }}:
- -
-
-
- 设定
-
-
-
@@ -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 });
diff --git a/src/views/equipment/wastewater.vue b/src/views/equipment/wastewater.vue
index 980193c..67f148e 100644
--- a/src/views/equipment/wastewater.vue
+++ b/src/views/equipment/wastewater.vue
@@ -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, {
diff --git a/src/views/linkConfig/sensorConfig.vue b/src/views/linkConfig/sensorConfig.vue
index 9ee5fdc..b20dacd 100644
--- a/src/views/linkConfig/sensorConfig.vue
+++ b/src/views/linkConfig/sensorConfig.vue
@@ -22,11 +22,11 @@
:model="sensor"
:rules="thresholdRules"
ref="formRefs"
- label-width="100px"
+ label-width="80px"
class="threshold-form"
>
-
+
-
+
+
+
+
+
+
@@ -302,4 +321,8 @@ onMounted(() => {
background-color: #66b1ff;
border-color: #66b1ff;
}
+
+::v-deep .sp-label .el-form-item__label {
+ width: 120px !important;
+}
diff --git a/src/views/plan/shiyan.vue b/src/views/plan/shiyan.vue
index 621f787..ab89f9c 100644
--- a/src/views/plan/shiyan.vue
+++ b/src/views/plan/shiyan.vue
@@ -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);
+ }
}
}
});
diff --git a/vite.config.js b/vite.config.js
index 0272c3c..17fa5b0 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -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/