diff --git a/frontend/src/pages/ROIEditor.tsx b/frontend/src/pages/ROIEditor.tsx index 5213d45..0f9c089 100644 --- a/frontend/src/pages/ROIEditor.tsx +++ b/frontend/src/pages/ROIEditor.tsx @@ -37,12 +37,38 @@ const ROIEditor: React.FC = () => { const [selectedROI, setSelectedROI] = useState(null); const [drawerVisible, setDrawerVisible] = useState(false); const [form] = Form.useForm(); + const [workingHoursList, setWorkingHoursList] = useState<{start: dayjs.Dayjs | null, end: dayjs.Dayjs | null}[]>([]); const [isDrawing, setIsDrawing] = useState(false); const [tempPoints, setTempPoints] = useState([]); const [backgroundImage, setBackgroundImage] = useState(null); const stageRef = useRef(null); + const addWorkingHours = () => { + setWorkingHoursList([...workingHoursList, { start: null, end: null }]); + }; + + const removeWorkingHours = (index: number) => { + const newList = workingHoursList.filter((_, i) => i !== index); + setWorkingHoursList(newList); + }; + + const updateWorkingHours = (index: number, field: 'start' | 'end', value: dayjs.Dayjs | null) => { + const newList = [...workingHoursList]; + newList[index] = { ...newList[index], [field]: value }; + setWorkingHoursList(newList); + }; + + const updateWorkingHoursRange = (index: number, start: dayjs.Dayjs | null, end: dayjs.Dayjs | null) => { + setWorkingHoursList(prev => { + const newList = [...prev]; + if (newList[index]) { + newList[index] = { start, end }; + } + return newList; + }); + }; + const fetchCameras = async () => { try { const res = await axios.get('/api/cameras?enabled_only=true'); @@ -103,10 +129,12 @@ const ROIEditor: React.FC = () => { const handleSaveROI = async (values: any) => { if (!selectedCamera || !selectedROI) return; try { - const workingHours = values.working_hours?.map((item: any) => ({ - start: [item.start.hour(), item.start.minute()], - end: [item.end.hour(), item.end.minute()], - })); + const workingHours = workingHoursList + .filter(item => item.start && item.end) + .map(item => ({ + start: [item.start!.hour(), item.start!.minute()], + end: [item.end!.hour(), item.end!.minute()], + })); await axios.put(`/api/camera/${selectedCamera}/roi/${selectedROI.id}`, { name: values.name, @@ -119,6 +147,7 @@ const ROIEditor: React.FC = () => { }); message.success('保存成功'); setDrawerVisible(false); + setWorkingHoursList([]); fetchROIs(); } catch (err: any) { message.error(`保存失败: ${err.response?.data?.detail || '未知错误'}`); @@ -226,11 +255,11 @@ const ROIEditor: React.FC = () => { threshold_sec: roi.threshold_sec, confirm_sec: roi.confirm_sec, enabled: roi.enabled, - working_hours: roi.working_hours?.map((wh: WorkingHours) => ({ - start: dayjs().hour(wh.start[0]).minute(wh.start[1]), - end: dayjs().hour(wh.end[0]).minute(wh.end[1]), - })), }); + setWorkingHoursList(roi.working_hours?.map((wh: WorkingHours) => ({ + start: wh.start ? dayjs().hour(wh.start[0]).minute(wh.start[1]) : null, + end: wh.end ? dayjs().hour(wh.end[0]).minute(wh.end[1]) : null, + })) || []); setDrawerVisible(true); }} onMouseEnter={(e) => { @@ -387,11 +416,11 @@ const ROIEditor: React.FC = () => { threshold_sec: roi.threshold_sec, confirm_sec: roi.confirm_sec, enabled: roi.enabled, - working_hours: roi.working_hours?.map((wh: WorkingHours) => ({ - start: dayjs().hour(wh.start[0]).minute(wh.start[1]), - end: dayjs().hour(wh.end[0]).minute(wh.end[1]), - })), }); + setWorkingHoursList(roi.working_hours?.map((wh: WorkingHours) => ({ + start: wh.start ? dayjs().hour(wh.start[0]).minute(wh.start[1]) : null, + end: wh.end ? dayjs().hour(wh.end[0]).minute(wh.end[1]) : null, + })) || []); setDrawerVisible(true); }} > @@ -426,6 +455,7 @@ const ROIEditor: React.FC = () => { onClose={() => { setDrawerVisible(false); setSelectedROI(null); + setWorkingHoursList([]); }} width={400} > @@ -458,33 +488,35 @@ const ROIEditor: React.FC = () => { 工作时间配置(可选) - - {(fields, { add, remove }) => ( -
- {fields.map((field, index) => ( - - - - - - - ))} - -
- )} -
+ + ))} + + 不配置工作时间则使用系统全局设置 @@ -501,6 +533,7 @@ const ROIEditor: React.FC = () => {