feat/平面图拖拽判断精度优化,设定温度问题修复
This commit is contained in:
parent
0c44fe5ec3
commit
3c5cd8016a
|
|
@ -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' },
|
||||||
|
]
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -68,9 +68,32 @@
|
||||||
<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>
|
||||||
{{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
|
<span>
|
||||||
|
{{ formatStatusValue(item.IotAgreementHostPoint.status, props.TypeId) }} {{ item.IotAgreementHostPoint.unit }}
|
||||||
|
</span>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -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 });
|
||||||
|
|
|
||||||
|
|
@ -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, {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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,19 +1773,19 @@ 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) {
|
||||||
|
newActiveMarker = point;
|
||||||
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
|
}
|
||||||
newActiveMarker = point;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1788,25 +1818,23 @@ 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) {
|
||||||
|
dragging.value = "point";
|
||||||
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
|
currentPoint = point;
|
||||||
dragging.value = "point";
|
startPointX.value = point.x * BL.value;
|
||||||
currentPoint = point;
|
startPointY.value = point.y * BL.value;
|
||||||
startPointX.value = point.x * BL.value;
|
startDragX.value = mouseX;
|
||||||
startPointY.value = point.y * BL.value;
|
startDragY.value = mouseY;
|
||||||
startDragX.value = mouseX;
|
return;
|
||||||
startDragY.value = mouseY;
|
}
|
||||||
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,26 +1944,24 @@ 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) {
|
||||||
|
clickedPoint = true;
|
||||||
if (ctx.value.isPointInPath(point.path, originalX, originalY)) {
|
if (point.target == "camera") {
|
||||||
clickedPoint = true;
|
selectPoint(point);
|
||||||
if (point.target == "camera") {
|
selectedPointId.value = null;
|
||||||
selectPoint(point);
|
} else {
|
||||||
selectedPointId.value = null;
|
// currentPointX.value = point.x;
|
||||||
} else {
|
// currentPointY.value = point.y;
|
||||||
// currentPointX.value = point.x;
|
selectPoint(point);
|
||||||
// currentPointY.value = point.y;
|
}
|
||||||
selectPoint(point);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue