S.规则设置逻辑和拆分更新,boxApi方法调用
This commit is contained in:
parent
1c0a51ed5e
commit
11ea95b902
|
@ -0,0 +1,365 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 打开弹窗按钮 -->
|
||||
<!-- <el-button type="primary" @click="openDialog">打开设置弹窗</el-button> -->
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<!-- <el-dialog title="设置规则" v-model="dialogVisible" width="50%" @close="resetDialog"> -->
|
||||
<el-dialog v-model="localVisible" width="50%" :modal="false" @close="handleClose">
|
||||
<!-- 显示摄像头基本信息 -->
|
||||
<div v-if="CameraDialog.id" class="camera-title">
|
||||
<p><strong>摄像头名称:</strong>{{ CameraDialog.name }} <strong> 通道号: </strong>{{ CameraDialog.id }}
|
||||
</p>
|
||||
<!-- <p><strong>摄像头状态:</strong>{{ CameraDialog.status }}</p> -->
|
||||
<!-- <img :src="CameraDialog.snapshot" alt="Snapshot" style="max-width: 100%; margin-bottom: 20px" /> -->
|
||||
</div>
|
||||
<el-radio-group v-model="CameraDialog.mode" @change="handleGlobalModeChange" style="margin-bottom: 20px">
|
||||
<el-radio label="on">ON</el-radio>
|
||||
<el-radio label="off">OFF</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
|
||||
<div v-for="(rule, index) in CameraDialog.rules" :key="rule.id" class="rule-block">
|
||||
<h3>{{ rule.name }} (模式: {{ rule.mode }})</h3>
|
||||
<el-radio-group v-model="rule.mode" :disabled="CameraDialog.mode === 'off'" @change="handleRuleModeChange(rule)">
|
||||
<el-radio label="on">ON</el-radio>
|
||||
<el-radio label="off">OFF</el-radio>
|
||||
<el-radio label="schedule">时间段</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<div v-if="rule.mode === 'schedule'">
|
||||
|
||||
<el-select v-model="rule.schedule.type" placeholder="请选择" style="margin: 10px 0">
|
||||
<el-option label="每日" value="daily"></el-option>
|
||||
</el-select>
|
||||
|
||||
|
||||
<div v-for="(time, timeIndex) in rule.schedule.time_slots" :key="timeIndex" class="time-period">
|
||||
<el-time-picker v-model="rule.schedule.time_slots[timeIndex][0]" format="HH:mm" value-format="HH:mm"
|
||||
placeholder="Start Time" @change="validateTime(rule.schedule.time_slots, timeIndex)" />
|
||||
<el-time-picker v-model="rule.schedule.time_slots[timeIndex][1]" format="HH:mm" value-format="HH:mm"
|
||||
placeholder="End Time" @change="validateTime(rule.schedule.time_slots, timeIndex)" />
|
||||
<el-button type="danger" @click="removeTimeSlot(rule.schedule.time_slots, timeIndex)">删除</el-button>
|
||||
|
||||
|
||||
<p v-if="!rule.schedule.time_slots[timeIndex][0] || !rule.schedule.time_slots[timeIndex][1]"
|
||||
style="color: red; margin-top: 5px">
|
||||
*
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<el-button type="primary" @click="addTimeSlot(rule.schedule.time_slots)">新增时间段</el-button>
|
||||
<p v-if="!rule.schedule.time_slots.length" style="color: red; margin-top: 10px">
|
||||
请至少添加一个时间段!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗底部操作 -->
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="success" @click="saveRules">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { BoxApi } from "@/utils/boxApi.ts";
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
cameraData: Object, // 父组件传递过来的摄像头数据
|
||||
visible: Boolean, // 父组件传递的弹窗状态
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "save-result"]);
|
||||
|
||||
// API 实例
|
||||
const apiInstance = new BoxApi();
|
||||
|
||||
const cameraDataZ = ref({});
|
||||
const localVisible = ref(props.visible);
|
||||
|
||||
const cameraData = ref({}); // 原始摄像头数据
|
||||
const CameraDialog = ref({}); // 镜像对象,用于格式化后的数据
|
||||
|
||||
// 弹窗控制
|
||||
// const dialogVisible = ref(false);
|
||||
|
||||
// 打开弹窗
|
||||
// const openDialog = async () => {
|
||||
// try {
|
||||
// const token = localStorage.getItem("alertToken");
|
||||
// const cameraId = 1;
|
||||
// const camera = await apiInstance.getCameraById(token, cameraId);
|
||||
// cameraData.value = camera;
|
||||
|
||||
// console.log("摄像头数据:", cameraData.value);
|
||||
|
||||
// formatCameraData();
|
||||
// dialogVisible.value = true;
|
||||
// } catch (error) {
|
||||
// console.error("获取摄像头规则失败:", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
localVisible.value = newVal;
|
||||
// console.log("newVal:", newVal);
|
||||
if (newVal) {
|
||||
// cameraDataZ.value = JSON.parse(JSON.stringify(newVal));
|
||||
Object.assign(cameraDataZ.value, JSON.parse(JSON.stringify(props.cameraData)));
|
||||
console.log("cameraDataZ:", cameraDataZ.value);
|
||||
formatCameraData(cameraDataZ.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => props.cameraData,
|
||||
// (newVal) => {
|
||||
// console.log("父组件传递的 cameraData:", newVal);
|
||||
// },
|
||||
// { immediate: true } // 立即触发以检查初始值
|
||||
// );
|
||||
|
||||
// watch(
|
||||
// () => props.visible,
|
||||
// (newVal) => {
|
||||
// console.log("父组件传递的 visible 状态:", newVal);
|
||||
// },
|
||||
// { immediate: true }
|
||||
// );
|
||||
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
};
|
||||
|
||||
|
||||
// 格式化 cameraData 到 CameraDialog
|
||||
const formatCameraData = () => {
|
||||
CameraDialog.value = {
|
||||
id: cameraDataZ.value.id,
|
||||
name: cameraDataZ.value.name,
|
||||
status: cameraDataZ.value.status,
|
||||
mode: cameraDataZ.value.mode,
|
||||
// snapshot: cameraData.value.snapshot,
|
||||
rules: cameraDataZ.value.rules.map((rule) => ({
|
||||
id: rule.id,
|
||||
name: rule.name,
|
||||
mode: rule.mode,
|
||||
schedule: {
|
||||
type: rule.schedule?.type || "",
|
||||
time_slots: rule.schedule?.time_slots
|
||||
? rule.schedule.time_slots.map(([start, end]) => [
|
||||
start !== undefined ? convertMinutesToTime(start) : "00:00",
|
||||
end !== undefined ? convertMinutesToTime(end) : "00:00",
|
||||
])
|
||||
: [],
|
||||
},
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
const handleGlobalModeChange = () => {
|
||||
if (CameraDialog.value.mode === "off") {
|
||||
// 全局模式为 off,所有规则的 mode 变为 off
|
||||
CameraDialog.value.rules.forEach((rule) => {
|
||||
rule.mode = "off";
|
||||
});
|
||||
} else if (CameraDialog.value.mode === "on") {
|
||||
// 全局模式为 on,规则保持原有状态
|
||||
CameraDialog.value.rules.forEach((rule) => {
|
||||
if (rule.mode === "schedule") {
|
||||
rule.schedule.type = "daily"; // 自动设置为 daily
|
||||
rule.schedule.time_slots = []; // 清空时间段
|
||||
} else if (rule.mode === "on" || rule.mode === "off") {
|
||||
rule.schedule.type = ""; // 清空 type
|
||||
rule.schedule.time_slots = []; // 清空时间段
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleRuleModeChange = (rule) => {
|
||||
if (rule.mode === "schedule") {
|
||||
rule.schedule.type = "daily"; // 自动选择 daily
|
||||
rule.schedule.time_slots = []; // 清空时间段
|
||||
} else {
|
||||
// 非 schedule 模式,清空 schedule 配置
|
||||
rule.schedule.type = ""; // 清空 type
|
||||
rule.schedule.time_slots = []; // 清空时间段
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleModeChange = (rule) => {
|
||||
if (rule.mode === "schedule") {
|
||||
rule.schedule.type = "daily";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 验证时间段
|
||||
const validateTime = (timeSlots, index) => {
|
||||
const [startTime, endTime] = timeSlots[index];
|
||||
|
||||
if (!startTime || !endTime) {
|
||||
ElMessage.error("请填写完整时间段");
|
||||
return;
|
||||
}
|
||||
|
||||
if (endTime <= startTime) {
|
||||
ElMessage.error("开始时间必须小于结束时间");
|
||||
timeSlots[index][1] = "00:00"; // 恢复为默认值
|
||||
}
|
||||
|
||||
if (endTime && startTime >= endTime) {
|
||||
ElMessage.error("开始时间和结束时间不合理");
|
||||
timeSlots[index][1] = "";
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < timeSlots.length; i++) {
|
||||
if (
|
||||
i !== index &&
|
||||
timeSlots[i][0] &&
|
||||
timeSlots[i][1] &&
|
||||
startTime &&
|
||||
endTime &&
|
||||
!(
|
||||
endTime <= timeSlots[i][0] ||
|
||||
startTime >= timeSlots[i][1]
|
||||
)
|
||||
) {
|
||||
ElMessage.error("时间段重叠,请重新选择");
|
||||
timeSlots[index][0] = "";
|
||||
timeSlots[index][1] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 添加时间段
|
||||
const addTimeSlot = (timeSlots) => {
|
||||
timeSlots.push([]);
|
||||
};
|
||||
|
||||
// 删除时间段
|
||||
const removeTimeSlot = (timeSlots, index) => {
|
||||
timeSlots.splice(index, 1);
|
||||
};
|
||||
|
||||
// 转换分钟数为时间字符串
|
||||
const convertMinutesToTime = (minutes) => {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
return `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
|
||||
};
|
||||
|
||||
// 转换时间为分钟数
|
||||
const convertTimeToMinutes = (timeString) => {
|
||||
const [hours, minutes] = timeString.split(":").map(Number);
|
||||
return hours * 60 + minutes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 保存规则并反向格式化
|
||||
const saveRules = async() => {
|
||||
let invalidSchedule = false;
|
||||
|
||||
// 遍历所有规则,校验 schedule 模式的完整性
|
||||
CameraDialog.value.rules.forEach((rule) => {
|
||||
if (rule.mode === "schedule") {
|
||||
if (rule.schedule.type && rule.schedule.time_slots.length === 0) {
|
||||
// 提示用户添加时间段
|
||||
ElMessage.error(`规则 "${rule.name}" 的时间段不能为空,请添加至少一个时间段`);
|
||||
invalidSchedule = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果校验失败,阻止保存
|
||||
if (invalidSchedule) return;
|
||||
|
||||
// 构造 cameraUpdate 数据
|
||||
const cameraUpdate = {
|
||||
id: CameraDialog.value.id,
|
||||
name: CameraDialog.value.name,
|
||||
mode: CameraDialog.value.mode,
|
||||
// rules: CameraDialog.value.rules.map((rule) => ({
|
||||
// id: rule.id,
|
||||
// name: rule.name,
|
||||
// mode: rule.mode,
|
||||
// })),
|
||||
};
|
||||
console.log("页面的cameraUpdate》》》》》》》》》》》:", cameraUpdate);
|
||||
|
||||
// 构造 ruleUpdate 数据
|
||||
const ruleUpdate = CameraDialog.value.rules.map((rule) => ({
|
||||
id: rule.id,
|
||||
name: rule.name,
|
||||
mode: CameraDialog.value.mode === "off" ? "off" : rule.mode,
|
||||
schedule: rule.mode === "schedule" ? {
|
||||
type: rule.schedule.type,
|
||||
time_slots: rule.schedule.time_slots.map(([start, end]) => [
|
||||
convertTimeToMinutes(start),
|
||||
convertTimeToMinutes(end),
|
||||
]),
|
||||
} : {}, // 非 schedule 模式,schedule 为空对象
|
||||
}));
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('alertToken');
|
||||
// 假设 API 分别处理 camera 和 rules 更新
|
||||
await apiInstance.updateCamera(token, cameraUpdate.id, cameraUpdate); // 更新摄像头信息
|
||||
await apiInstance.updateRule(token, ruleUpdate); // 更新规则信息
|
||||
// ElMessage.success("规则保存成功");
|
||||
emit("save-result", { success: true, message: "规则保存成功" });
|
||||
emit("update:visible", false);
|
||||
// dialogVisible.value = false;
|
||||
} catch (error) {
|
||||
console.error("保存失败:", error);
|
||||
// ElMessage.error("保存失败,请重试");
|
||||
emit("save-result", { success: false, message: "规则保存失败,请重试" });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const closeDialog = () => {
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.time-period {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.rule-block {
|
||||
border: 1px solid #ddd;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
/* text-align: right; */
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.camera-title{
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue