feat/平面图拖拽判断精度优化,设定温度问题修复
This commit is contained in:
parent
0c44fe5ec3
commit
3c5cd8016a
|
|
@ -4,3 +4,16 @@
|
|||
* @Description:
|
||||
*/
|
||||
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",
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -68,7 +68,30 @@
|
|||
<dl v-if="(item.IotAgreementHostPoint.register_type == '保持寄存器' && item.IotAgreementHostPoint.point_name.includes('控制') == false) || item.IotAgreementHostPoint.register_type == '输入寄存器'">
|
||||
<dt>{{ item.IotAgreementHostPoint.point_name }}:</dt>
|
||||
<dd>
|
||||
<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>
|
||||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -987,11 +1005,15 @@ 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, {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,20 +1773,20 @@ 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)) {
|
||||
if (distance <= detectRadius) {
|
||||
newActiveMarker = point;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
|
|
@ -1788,18 +1818,15 @@ 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)) {
|
||||
if (distance <= detectRadius) {
|
||||
dragging.value = "point";
|
||||
currentPoint = point;
|
||||
startPointX.value = point.x * BL.value;
|
||||
|
|
@ -1808,6 +1835,7 @@ const startDrag = (e) => {
|
|||
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,18 +1944,15 @@ 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)) {
|
||||
if (distance <= detectRadius) {
|
||||
clickedPoint = true;
|
||||
if (point.target == "camera") {
|
||||
selectPoint(point);
|
||||
|
|
@ -1937,6 +1963,7 @@ const handleCanvasClick = (e) => {
|
|||
selectPoint(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!clickedPoint) {
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
Loading…
Reference in New Issue