Merge branch 'dunhuang-dev' of http://192.168.34.160:8023/admin/zhgdyun into dunhuang-cs

This commit is contained in:
Rain_ 2025-11-17 11:06:54 +08:00
commit 678f084a34
3 changed files with 304 additions and 260 deletions

View File

@ -113,12 +113,13 @@ import {
getHikPtzControlApi,
setHikPtzControlApi,
} from "@/assets/js/api/equipmentCenter/cameraList";
import { Message } from "element-ui";
export default {
name: "DraggableGauge",
name: 'DraggableGauge',
props: {
value: {
type: Number,
default: 50,
default: 10,
},
size: {
type: Number,
@ -160,7 +161,6 @@ export default {
data() {
return {
currentValue: this.value,
canvas: null,
ctx: null,
isDragging: false,
controlInfo: {
@ -168,55 +168,25 @@ export default {
opType: "",
},
videoInfo: {},
//
DEVICE_TYPE_BALL: 2, //
VIDEO_TYPE_ISC: 3, // ISC
SUCCESS_CODE: 200, //
GAP_ANGLE: 90, //
INDICATOR_COLOR: "#2758C0", //
};
},
mounted() {
this.initCanvas();
this.drawGauge();
this.addEventListeners();
},
beforeDestroy() {
this.removeEventListeners();
},
methods: {
controlVideoMouse(opType, action) {
if (this.videoInfo.deviceType != 2) {
this.$message.warning("该设备不是球机,不支持此操作");
return false;
}
this.controlInfo.opType = opType;
if (action == 0) {
this.controlInfo.videoFlag = true;
}
const json = {
itemId: this.videoInfo.itemId,
opType: opType,
action: action,
opSize: this.currentValue,
opCode: 1,
};
setHikPtzControlApi(json)
.then((res) => {
if (res.code == 200) {
// Message.success("");
}
})
.finally(() => {
if (action == 1) {
this.controlInfo.videoFlag = false;
}
});
},
initCanvas() {
this.canvas = this.$refs.canvas;
this.ctx = this.canvas.getContext("2d");
const canvas = this.$refs.canvas;
if (!canvas) return;
this.ctx = canvas.getContext("2d");
// canvas
const dpr = window.devicePixelRatio || 1;
this.canvas.width = this.size * dpr;
this.canvas.height = this.size * dpr;
this.canvas.style.width = `${this.size}px`;
this.canvas.style.height = `${this.size}px`;
canvas.width = this.size * dpr;
canvas.height = this.size * dpr;
canvas.style.width = `${this.size}px`;
canvas.style.height = `${this.size}px`;
this.ctx.scale(dpr, dpr);
},
drawGauge() {
@ -225,15 +195,13 @@ export default {
const center = this.size / 2;
const radius = center - this.lineWidth / 2;
const startAngle = Math.PI / 2 + Math.PI / 4;
const endAngle =
startAngle + ((2 * Math.PI - Math.PI / 2) * this.currentValue) / 100;
const endAngle = startAngle + ((2 * Math.PI - Math.PI / 2) * this.currentValue) / 100;
//
this.ctx.clearRect(0, 0, this.size, this.size);
// 线
//
this.ctx.beginPath();
this.ctx.setLineDash([5, 3]); // 线5px线3px
this.ctx.setLineDash([5, 3]);
this.ctx.arc(
center,
center,
@ -246,25 +214,15 @@ export default {
this.ctx.lineWidth = this.lineWidth;
this.ctx.stroke();
// 线
//
this.ctx.beginPath();
this.ctx.setLineDash([5, 3]); // 线5px线3px
this.ctx.setLineDash([5, 3]);
this.ctx.arc(center, center, radius, startAngle, endAngle);
this.ctx.strokeStyle = this.progressColor;
this.ctx.lineWidth = this.lineWidth;
this.ctx.stroke();
// //
// const indicatorRadius = this.lineWidth * 1.5;
// const indicatorX = center + radius * Math.cos(endAngle);
// const indicatorY = center + radius * Math.sin(endAngle);
// this.ctx.beginPath();
// this.ctx.setLineDash([]); // 线
// this.ctx.arc(indicatorX, indicatorY, indicatorRadius, 0, 2 * Math.PI);
// this.ctx.fillStyle = this.progressColor;
// this.ctx.fill();
//
//
const indicatorWidth = this.lineWidth;
const indicatorHeight = this.lineWidth * 3;
const indicatorX = center + radius * Math.cos(endAngle);
@ -272,7 +230,7 @@ export default {
this.ctx.save();
this.ctx.translate(indicatorX, indicatorY);
this.ctx.rotate(endAngle + Math.PI / 2); // 使线
this.ctx.rotate(endAngle + Math.PI / 2);
this.ctx.beginPath();
this.ctx.setLineDash([]);
@ -282,22 +240,63 @@ export default {
indicatorWidth,
indicatorHeight
);
this.ctx.fillStyle = "#2758C0";
this.ctx.fillStyle = this.INDICATOR_COLOR;
this.ctx.fill();
this.ctx.restore();
},
addEventListeners() {
this.canvas.addEventListener("mousedown", this.startDrag);
this.canvas.addEventListener("touchstart", this.startDrag);
controlVideoMouse(opType, action) {
if (this.videoInfo.deviceType !== this.DEVICE_TYPE_BALL) {
Message.warning("该设备不是球机,不支持此操作");
return false;
}
this.controlInfo.opType = opType;
if (action === 0) {
this.controlInfo.videoFlag = true;
}
const json = {
itemId: this.videoInfo.itemId,
opType: opType,
action: action,
opSize: this.currentValue,
opCode: 1,
};
setHikPtzControlApi(json)
.then((res) => {
if (res.code === this.SUCCESS_CODE) {
//
}
})
.catch((error) => {
console.error("视频控制失败:", error);
Message.error("视频控制失败,请稍后重试");
})
.finally(() => {
if (action === 1) {
this.controlInfo.videoFlag = false;
}
});
},
removeEventListeners() {
this.canvas.removeEventListener("mousedown", this.startDrag);
this.canvas.removeEventListener("touchstart", this.startDrag);
document.removeEventListener("mousemove", this.handleDrag);
document.removeEventListener("mouseup", this.stopDrag);
document.removeEventListener("touchmove", this.handleDrag);
document.removeEventListener("touchend", this.stopDrag);
controlVideoFn_isc(opType) {
const json = {
itemId: this.videoInfo.itemId,
opType: opType,
opSize: this.currentValue,
opCode: 1,
};
getHikPtzControlApi(json)
.then((res) => {
if (res.code === this.SUCCESS_CODE) {
Message.success("控制成功");
}
})
.catch((error) => {
console.error("ISC视频控制失败:", error);
Message.error("视频控制失败,请稍后重试");
})
.finally(() => {
this.controlInfo.videoFlag = false;
});
},
startDrag(e) {
this.isDragging = true;
@ -305,93 +304,103 @@ export default {
document.addEventListener("mouseup", this.stopDrag);
document.addEventListener("touchmove", this.handleDrag);
document.addEventListener("touchend", this.stopDrag);
this.handleDrag(e); //
this.handleDrag(e);
},
handleDrag(e) {
if (!this.isDragging) return;
if (!this.isDragging || !this.$refs.canvas) return;
const rect = this.canvas.getBoundingClientRect();
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
const rect = this.$refs.canvas.getBoundingClientRect();
//
const clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches[0] && e.touches[0].clientX);
const clientY = e.clientY !== undefined ? e.clientY : (e.touches && e.touches[0] && e.touches[0].clientY);
if (clientX === undefined || clientY === undefined) return;
// canvas
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const x = clientX - centerX;
const y = clientY - centerY;
// (0-360)
let angle = Math.atan2(y, x) * (180 / Math.PI);
angle = (angle + 180) % 360; //
//
let angle = Math.atan2(y, x);
// 0-10090
const gapAngle = 90; //
const usableAngle = 360 - gapAngle;
let value = Math.round((angle * 100) / usableAngle);
if (angle > usableAngle) value = 100; //
this.currentValue = Math.min(100, Math.max(0, value));
// Math.PI / 2 + Math.PI / 4 = 135° ()
const startAngle = Math.PI / 2 + Math.PI / 4;
// 135° + 270° = 405° = 45° (0°)
const endAngle = startAngle + (2 * Math.PI - Math.PI / 2);
// 270° (360° - 90°)
const usableAngle = 2 * Math.PI - Math.PI / 2;
// 0-2π
if (angle < 0) {
angle += 2 * Math.PI;
}
//
let relativeAngle;
// 0-2π
const endAngleNormalized = endAngle % (2 * Math.PI); // 45° = π/4
//
// 1 startAngle 2π 135° 360°
if (angle >= startAngle && angle <= 2 * Math.PI) {
relativeAngle = angle - startAngle;
//
if (relativeAngle > usableAngle) {
relativeAngle = usableAngle;
}
}
// 2 0 endAngleNormalized 0° 45°0°
else if (angle >= 0 && angle <= endAngleNormalized) {
// 0°2π
relativeAngle = (angle + 2 * Math.PI) - startAngle;
//
if (relativeAngle > usableAngle) {
relativeAngle = usableAngle;
}
// 0
if (relativeAngle < 0) {
relativeAngle = 0;
}
}
// 345° 135°
else {
//
//
const distToStart = Math.abs(angle - startAngle);
const distToEnd = Math.min(
Math.abs(angle - endAngleNormalized),
Math.abs(angle + 2 * Math.PI - endAngleNormalized)
);
if (distToStart < distToEnd) {
relativeAngle = 0; // 0%
} else {
relativeAngle = usableAngle; // 100%
}
}
// 0-100
const value = Math.round((relativeAngle / usableAngle) * 100);
this.currentValue = Math.min(this.max, Math.max(this.min, value));
//
this.drawGauge();
this.$emit("input", this.currentValue);
this.$emit("change", this.currentValue);
if (e.cancelable && e.type.includes("touch")) {
if (e.cancelable && e.type && e.type.includes("touch")) {
e.preventDefault();
}
},
stopDrag() {
if (!this.isDragging) return;
this.isDragging = false;
document.removeEventListener("mousemove", this.handleDrag);
document.removeEventListener("mouseup", this.stopDrag);
document.removeEventListener("touchmove", this.handleDrag);
document.removeEventListener("touchend", this.stopDrag);
},
controlVideoFn(pan, tilt, zoom, opType) {
this.controlInfo.opType = opType;
if (this.controlInfo.videoFlag) {
this.$message.warning("不要重复点击");
return;
}
if (this.videoInfo.deviceType != 2) {
this.$message.warning("该设备不是球机,不支持此操作");
return false;
}
switch (this.videoInfo.videoType) {
case 3:
this.controlInfo.videoFlag = true;
this.controlVideoFn_isc(opType);
break;
// case 4:
// this.controlInfo.videoFlag = true;
// this.controlVideoFn_dh(pan, tilt, zoom)
// break;
default:
this.$message.warning("暂不支持");
break;
}
},
controlVideoFn_isc(opType) {
let json = {
// cameraId: this.videoInfo.deviceSerial,
itemId: this.videoInfo.itemId,
opType: opType,
opSize: this.currentValue,
opCode: 1,
};
getHikPtzControlApi({
...json,
})
.then((res) => {
if (res.code == 200) {
this.$message.success("控制成功");
}
})
.finally(() => {
this.controlInfo.videoFlag = false;
});
},
},
watch: {
value(newVal) {
@ -403,16 +412,40 @@ export default {
this.videoInfo = newVal;
},
deep: true,
immediate: true,
immediate: true
}
},
mounted() {
if (!this.$refs.canvas) return;
this.initCanvas();
this.drawGauge();
this.$refs.canvas.addEventListener("mousedown", this.startDrag);
this.$refs.canvas.addEventListener("touchstart", this.startDrag);
},
beforeDestroy() {
//
if (this.isDragging) {
this.stopDrag();
}
// canvas
if (this.$refs.canvas) {
this.$refs.canvas.removeEventListener("mousedown", this.startDrag);
this.$refs.canvas.removeEventListener("touchstart", this.startDrag);
}
// document
document.removeEventListener("mousemove", this.handleDrag);
document.removeEventListener("mouseup", this.stopDrag);
document.removeEventListener("touchmove", this.handleDrag);
document.removeEventListener("touchend", this.stopDrag);
}
};
</script>
<style scoped lang="less">
.gauge-canvas {
margin-bottom: 28px;
position: absolute;
position: absolute
}
#content {
margin: auto;

View File

@ -111,7 +111,6 @@ import {
setHikPtzControlApi,
} from "@/assets/js/api/equipmentCenter/cameraList";
import { Message } from "element-ui";
import { active } from "sortablejs";
const props = defineProps({
value: {
@ -168,9 +167,16 @@ const controlInfo = ref({
});
const videoInfo = ref({});
//
const DEVICE_TYPE_BALL = 2; //
const VIDEO_TYPE_ISC = 3; // ISC
const SUCCESS_CODE = 200; //
const GAP_ANGLE = 90; //
const INDICATOR_COLOR = "#2758C0"; //
//
const initCanvas = () => {
// canvas.value = canvas.value;
if (!canvas.value) return;
ctx.value = canvas.value.getContext("2d");
const dpr = window.devicePixelRatio || 1;
@ -233,18 +239,18 @@ const drawGauge = () => {
indicatorWidth,
indicatorHeight
);
ctx.value.fillStyle = "#2758C0";
ctx.value.fillStyle = INDICATOR_COLOR;
ctx.value.fill();
ctx.value.restore();
};
const controlVideoMouse = (opType, action) => {
if (videoInfo.value.deviceType != 2) {
if (videoInfo.value.deviceType !== DEVICE_TYPE_BALL) {
Message.warning("该设备不是球机,不支持此操作");
return false;
}
controlInfo.value.opType = opType;
if (action == 0) {
if (action === 0) {
controlInfo.value.videoFlag = true;
}
const json = {
@ -256,36 +262,41 @@ const controlVideoMouse = (opType, action) => {
};
setHikPtzControlApi(json)
.then((res) => {
if (res.code == 200) {
// Message.success("");
if (res.code === SUCCESS_CODE) {
//
}
})
.catch((error) => {
console.error("视频控制失败:", error);
Message.error("视频控制失败,请稍后重试");
})
.finally(() => {
if (action == 1) {
if (action === 1) {
controlInfo.value.videoFlag = false;
}
});
};
const controlVideoFn = (pan, tilt, zoom, opType) => {
controlInfo.value.opType = opType;
if (controlInfo.value.videoFlag) {
Message.warning("不要重复点击");
return;
}
if (videoInfo.value.deviceType != 2) {
Message.warning("该设备不是球机,不支持此操作");
return false;
}
switch (videoInfo.value.videoType) {
case 3:
controlInfo.value.videoFlag = true;
controlVideoFn_isc(opType);
break;
default:
Message.warning("暂不支持");
break;
}
};
// 使
// const controlVideoFn = (opType) => {
// controlInfo.value.opType = opType;
// if (controlInfo.value.videoFlag) {
// Message.warning("");
// return;
// }
// if (videoInfo.value.deviceType !== DEVICE_TYPE_BALL) {
// Message.warning("");
// return false;
// }
// switch (videoInfo.value.videoType) {
// case VIDEO_TYPE_ISC:
// controlInfo.value.videoFlag = true;
// controlVideoFn_isc(opType);
// break;
// default:
// Message.warning("");
// break;
// }
// };
const controlVideoFn_isc = (opType) => {
const json = {
@ -296,10 +307,14 @@ const controlVideoFn_isc = (opType) => {
};
getHikPtzControlApi(json)
.then((res) => {
if (res.code == 200) {
if (res.code === SUCCESS_CODE) {
Message.success("控制成功");
}
})
.catch((error) => {
console.error("ISC视频控制失败:", error);
Message.error("视频控制失败,请稍后重试");
})
.finally(() => {
controlInfo.value.videoFlag = false;
});
@ -316,25 +331,83 @@ const startDrag = (e) => {
};
const handleDrag = (e) => {
if (!isDragging.value) return;
if (!isDragging.value || !canvas.value) return;
const rect = canvas.value.getBoundingClientRect();
const clientX = e.clientX || e.touches[0].clientX;
const clientY = e.clientY || e.touches[0].clientY;
//
const clientX = e.clientX ?? (e.touches?.[0]?.clientX);
const clientY = e.clientY ?? (e.touches?.[0]?.clientY);
if (clientX === undefined || clientY === undefined) return;
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const x = clientX - centerX;
const y = clientY - centerY;
let angle = Math.atan2(y, x) * (180 / Math.PI);
angle = (angle + 180) % 360;
//
let angle = Math.atan2(y, x);
const gapAngle = 90;
const usableAngle = 360 - gapAngle;
let value = Math.round((angle * 100) / usableAngle);
if (angle > usableAngle) value = 100;
currentValue.value = Math.min(100, Math.max(0, value));
// Math.PI / 2 + Math.PI / 4 = 135° ()
const startAngle = Math.PI / 2 + Math.PI / 4;
// 135° + 270° = 405° = 45° (0°)
const endAngle = startAngle + (2 * Math.PI - Math.PI / 2);
// 270° (360° - 90°)
const usableAngle = 2 * Math.PI - Math.PI / 2;
// 0-2π
if (angle < 0) {
angle += 2 * Math.PI;
}
//
let relativeAngle;
// 0-2π
const endAngleNormalized = endAngle % (2 * Math.PI); // 45° = π/4
//
// 1 startAngle 2π 135° 360°
if (angle >= startAngle && angle <= 2 * Math.PI) {
relativeAngle = angle - startAngle;
//
if (relativeAngle > usableAngle) {
relativeAngle = usableAngle;
}
}
// 2 0 endAngleNormalized 0° 45°0°
else if (angle >= 0 && angle <= endAngleNormalized) {
// 0°2π
relativeAngle = (angle + 2 * Math.PI) - startAngle;
//
if (relativeAngle > usableAngle) {
relativeAngle = usableAngle;
}
// 0
if (relativeAngle < 0) {
relativeAngle = 0;
}
}
// 345° 135°
else {
//
//
const distToStart = Math.abs(angle - startAngle);
const distToEnd = Math.min(
Math.abs(angle - endAngleNormalized),
Math.abs(angle + 2 * Math.PI - endAngleNormalized)
);
if (distToStart < distToEnd) {
relativeAngle = 0; // 0%
} else {
relativeAngle = usableAngle; // 100%
}
}
// 0-100
const value = Math.round((relativeAngle / usableAngle) * 100);
currentValue.value = Math.min(props.max, Math.max(props.min, value));
drawGauge();
emit("input", currentValue.value);
@ -346,6 +419,7 @@ const handleDrag = (e) => {
};
const stopDrag = () => {
if (!isDragging.value) return;
isDragging.value = false;
document.removeEventListener("mousemove", handleDrag);
document.removeEventListener("mouseup", stopDrag);
@ -355,6 +429,7 @@ const stopDrag = () => {
//
onMounted(() => {
if (!canvas.value) return;
initCanvas();
drawGauge();
canvas.value.addEventListener("mousedown", startDrag);
@ -362,8 +437,16 @@ onMounted(() => {
});
onBeforeUnmount(() => {
//
if (isDragging.value) {
stopDrag();
}
// canvas
if (canvas.value) {
canvas.value.removeEventListener("mousedown", startDrag);
canvas.value.removeEventListener("touchstart", startDrag);
}
// document
document.removeEventListener("mousemove", handleDrag);
document.removeEventListener("mouseup", stopDrag);
document.removeEventListener("touchmove", handleDrag);
@ -392,10 +475,7 @@ watch(
margin-bottom: 28px;
position: absolute;
}
#content {
margin: auto;
width: 200px;
}
.draggable-gauge-container {
position: relative;
user-select: none;
@ -408,73 +488,6 @@ watch(
}
}
// Element UI
.gauge-wrapper {
width: 260px;
height: 260px;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 30px;
z-index: 5;
}
.gauge-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
transform: rotate(90deg);
}
.gauge-svg {
transform: rotate(-135deg); // SVG使
}
.gauge-background {
opacity: 0.2;
}
.gauge-progress {
stroke-linecap: round; //
}
.gauge-indicator {
cursor: pointer;
transition: all 0.2s ease;
// &:hover {
// transform: scale(1.1);
// }
// &:active {
// transform: scale(0.95);
// }
}
.gauge-value-display {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
pointer-events: none;
z-index: 4;
.value-text {
font-weight: bold;
line-height: 1;
margin-bottom: 4px;
}
.title-text {
opacity: 0.8;
line-height: 1;
}
}
.container-bottom {
margin-top: 6px;
width: 183px;
@ -490,10 +503,7 @@ watch(
background-size: 100% 100%;
background-repeat: no-repeat;
}
.video-icon2_1 {
height: 13px;
background-image: url("~@/assets/images/videoSurveillance/video-icon2_1.png");
}
// .video-icon2_1 使
}
.container-box {
width: 159px;

View File

@ -984,6 +984,7 @@ export default {
...row,
projectSn: this.$store.state.projectSn,
isEnabled: row.isEnabled == 1 ? 0 : 1,
devSn: this.currentGroupInfo.devSn,
}).then((res) => {
if (res.code == 200) {
this.$message.success(this.$t("message.projectInfo.saveSuccess"));