diff --git a/jjb.config.js b/jjb.config.js index 523d972..84b4170 100644 --- a/jjb.config.js +++ b/jjb.config.js @@ -9,8 +9,8 @@ module.exports = { // 应用后端分支名称,部署上线需要 javaGitBranch: "", // 接口服务地址 - // API_HOST: "https://gbs-gateway.qhdsafety.com", - API_HOST: "http://192.168.10.45:80", + API_HOST: "https://gbs-gateway.qhdsafety.com", + // API_HOST: "http://192.168.10.45:80", // API_HOST: "http://192.168.20.100:30140", }, production: { diff --git a/package.json b/package.json index 087f53b..41d6f71 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,11 @@ "ahooks": "^3.9.5", "antd": "^5.27.6", "dayjs": "^1.11.7", + "echarts": "^6.0.0", "lodash-es": "^4.17.21", "react": "^18.2.0", "react-dom": "^18.2.0", - "zy-react-library": "^1.2.20" + "zy-react-library": "^1.2.39" }, "devDependencies": { "@antfu/eslint-config": "^5.4.1", diff --git a/src/api/AlarmInfo/index.js b/src/api/AlarmInfo/index.js index 06907be..bda4bdd 100644 --- a/src/api/AlarmInfo/index.js +++ b/src/api/AlarmInfo/index.js @@ -2,3 +2,4 @@ import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; export const dcsAlarmInfoList = declareRequest("dcsAlarmInfoLoading", "Post > @/iotalarm/alarmRecord/list"); export const thresholdAlarmInfoList = declareRequest("thresholdAlarmInfoLoading", "Post > @/iotalarm/alarmRecord/list"); +export const thresholdAlarmInfoInfo = declareRequest("thresholdAlarmInfoLoading", "Get > /iotalarm/alarmRecord/{id}"); diff --git a/src/api/AlarmRecord/index.js b/src/api/AlarmRecord/index.js index 9bce607..6464743 100644 --- a/src/api/AlarmRecord/index.js +++ b/src/api/AlarmRecord/index.js @@ -6,5 +6,5 @@ export const alarmRecordList = declareRequest( ); export const alarmRecordInfo = declareRequest( "alarmRecordLoading", - `Get > @/iotalarm/alarmRecord/{id}`, + `Get > /iotalarm/alarmRecord/{id}`, ); diff --git a/src/api/DeviceRegion/index.js b/src/api/DeviceRegion/index.js index 2d11d41..e1e2415 100644 --- a/src/api/DeviceRegion/index.js +++ b/src/api/DeviceRegion/index.js @@ -1,9 +1,9 @@ import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; export const deviceRegionList = declareRequest("deviceRegionLoading", "Post > @/iotalarm/deviceRegion/list"); -export const deviceRegionFireRegionList = declareRequest("deviceRegionLoading", "Get > @/fireCheck/fireRegion/listAll"); +export const deviceRegionFireRegionList = declareRequest("deviceRegionLoading", "Get > /fireCheck/fireRegion/listAll"); export const deviceRegionSaveOrUpdate = declareRequest("deviceRegionLoading", "Post > @/iotalarm/deviceRegion/saveOrUpdate"); export const deviceRegionBindSensor = declareRequest("deviceRegionLoading", "Post > @/iotalarm/deviceRegion/bindSensor"); export const deviceRegionUnbindSensor = declareRequest("deviceRegionLoading", "Post > @/iotalarm/deviceRegion/unbindSensor"); export const deviceRegionManager = declareRequest("deviceRegionLoading", "Put > @/iotalarm/deviceRegion/manager"); -export const deviceRegionInfo = declareRequest("deviceRegionLoading", "Get > @/iotalarm/deviceRegion/{id}"); +export const deviceRegionInfo = declareRequest("deviceRegionLoading", "Get > /iotalarm/deviceRegion/{id}"); diff --git a/src/api/SensorDevice/index.js b/src/api/SensorDevice/index.js index eeef711..7a22c9f 100644 --- a/src/api/SensorDevice/index.js +++ b/src/api/SensorDevice/index.js @@ -1,9 +1,10 @@ import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; export const sensorDeviceList = declareRequest("sensorDeviceLoading", "Post > @/iotalarm/sensorDevice/list"); -export const sensorDeviceInfo = declareRequest("sensorDeviceLoading", "Get > @/iotalarm/sensorDevice/{id}"); +export const sensorDeviceInfo = declareRequest("sensorDeviceLoading", "Get > /iotalarm/sensorDevice/{id}"); export const sensorDeviceSave = declareRequest("sensorDeviceLoading", "Post > @/iotalarm/sensorDevice/save"); -export const sensorDeviceEdit = declareRequest("sensorDeviceLoading", "Put > @/iotalarm/sensorDevice/edit"); +export const sensorDeviceEdit = declareRequest("sensorDeviceLoading", "Post > @/iotalarm/sensorDevice/edit"); export const sensorDeviceStatus = declareRequest("sensorDeviceLoading", "Put > @/iotalarm/sensorDevice/status"); export const sensorDeviceThreshold = declareRequest("sensorDeviceLoading", "Put > @/iotalarm/sensorDevice/threshold"); -export const sensorDeviceRemove = declareRequest("sensorDeviceLoading", "Delete > @/iotalarm/sensorDevice/{id}"); +export const sensorDeviceRemove = declareRequest("sensorDeviceLoading", "Post > @/iotalarm/sensorDevice/{id}"); +export const sensorDevicelistBySensorDevice = declareRequest("sensorDeviceLoading", "Post > @/iotalarm/alarmRecord/listBySensorDevice"); diff --git a/src/api/SensorType/index.js b/src/api/SensorType/index.js index dc8173c..2220263 100644 --- a/src/api/SensorType/index.js +++ b/src/api/SensorType/index.js @@ -1,7 +1,7 @@ import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; export const sensorTypeList = declareRequest("sensorTypeLoading", "Post > @/iotalarm/sensorType/list"); -export const sensorTypeInfo = declareRequest("sensorTypeLoading", "Get > @/iotalarm/sensorType/{id}"); +export const sensorTypeInfo = declareRequest("sensorTypeLoading", "Get > /iotalarm/sensorType/{id}"); export const sensorTypeSave = declareRequest("sensorTypeLoading", "Post > @/iotalarm/sensorType/save"); -export const sensorTypeEdit = declareRequest("sensorTypeLoading", "Put > @/iotalarm/sensorType/edit"); -export const sensorTypeRemove = declareRequest("sensorTypeLoading", "Delete > @/iotalarm/sensorType/{id}"); +export const sensorTypeEdit = declareRequest("sensorTypeLoading", "Post > @/iotalarm/sensorType/edit"); +export const sensorTypeRemove = declareRequest("sensorTypeLoading", "Post > @/iotalarm/sensorType/{id}"); diff --git a/src/components/AlarmAssign/List/components/AssignModal/index.js b/src/components/AlarmAssign/List/components/AssignModal/index.js index cf2735c..ae98aca 100644 --- a/src/components/AlarmAssign/List/components/AssignModal/index.js +++ b/src/components/AlarmAssign/List/components/AssignModal/index.js @@ -1,37 +1,102 @@ -import { Form, Modal } from "antd"; -import { useEffect } from "react"; +import { Col, Descriptions, Divider, Form, message, Modal, Row, Select } from "antd"; +import dayjs from "dayjs"; +import { useEffect, useRef, useState } from "react"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; import PersonnelSelect from "zy-react-library/components/Select/Personnel/Gwj"; +import useGetUserInfo from "zy-react-library/hooks/useGetUserInfo"; +import { getLabelName } from "zy-react-library/utils"; +import BaiduMap from "~/components/BaiduMap"; +import { DISPOSAL_STATIS, SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; +import { renderAlarmCurrentValue } from "~/utils/alarm"; function AssignModal(props) { const [form] = Form.useForm(); + const [detail, setDetail] = useState({}); + const [submitting, setSubmitting] = useState(false); + const [corpinfoId, setCorpinfoId] = useState(null); + const { getUserInfo } = useGetUserInfo(); + const alarmLevelName = useRef(null); + const alarmTypeName = useRef(null); + const disposeStatus = Form.useWatch("disposeStatus", form); useEffect(() => { if (!props.open) { return; } + form.resetFields(); - }, [form, props.open]); + setDetail({}); + + if (!props.isBatch && props.alarmId && props.alarmRecordInfo) { + props.alarmRecordInfo({ id: props.alarmId }).then((res) => { + if (res?.success) { + setDetail(res.data || {}); + } + }); + } + }, [form, props.open, props.isBatch, props.alarmId]); + + useEffect(() => { + getUserInfo().then((data) => { + setCorpinfoId(data.corpinfoId); + }); + }, [getUserInfo]); + + useEffect(() => { + if (disposeStatus !== 1) { + return; + } + + form.setFieldsValue({ + alarmType: undefined, + alarmLevel: undefined, + disposeUserId: undefined, + }); + }, [disposeStatus, form]); const handleCancel = () => { form.resetFields(); + setDetail({}); props.onCancel(); }; const handleSubmit = async (values) => { - if (props.isBatch) { - await props.alarmBatchAssign({ - ids: props.alarmIds, - disposeUserId: values.disposeUserId, - }); + if (submitting) { + return; } - else { - await props.alarmAssign({ - id: props.alarmId, - disposeUserId: values.disposeUserId, - }); + + setSubmitting(true); + values.alarmLevelName = alarmLevelName.current; + values.alarmTypeName = alarmTypeName.current; + values.status = values.disposeStatus === 1 ? 40 : 20; + + try { + let res; + if (props.isBatch) { + values.ids = props.alarmIds; + res = await props.alarmAssign(values); + } else { + values.ids = [props.alarmId]; + res = await props.alarmAssign(values); + } + + if (res?.success) { + handleCancel(); + props.getData(); + message.success("处置成功"); + } + } finally { + setSubmitting(false); } - handleCancel(); - props.getData(); + }; + + const formatTime = (value) => { + if (!value) { + return "-"; + } + + const time = dayjs(value); + return time.isValid() ? time.format("YYYY-MM-DD HH:mm:ss") : value; }; return ( @@ -41,17 +106,125 @@ function AssignModal(props) { title={props.isBatch ? "批量分配" : "分配处置"} onCancel={handleCancel} onOk={form.submit} - confirmLoading={props.loading} - width={640} + confirmLoading={props.loading || submitting} + maskClosable={false} + width={1200} > -
- - - + {!props.isBatch && ( + <> + 报警信息 + + {detail.sensorCode || "-"} + {detail.sensorName || "-"} + {detail.sensorTypeName || "-"} + + {getLabelName({ status: detail.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-"} + + {renderAlarmCurrentValue(detail)} + {detail.unitName || "-"} + {detail.thresholdHighHigh || "-"} + {detail.thresholdHigh || "-"} + {detail.thresholdLowLow || "-"} + {detail.thresholdLow || "-"} + {detail.alarmNo || "-"} + {formatTime(detail.alarmTime)} + + {detail.alarmDesc || detail.deviceSourceDesc || "-"} + + + {detail.longitude && detail.latitude + ? ( + + ) + : "暂无定位信息"} + + + + )} + + 处置分配 + + + + + ({ + value: item.bianma, + label: item.name, + }))} + placeholder="请选择报警处置" + disabled + /> + + + ({ + value: item.bianma, + label: item.name, + }))} + placeholder="请选择报警级别" + disabled + /> + + + + + + + ); +} + +export default DetailModal; diff --git a/src/components/AlarmRecord/List/index.js b/src/components/AlarmRecord/List/index.js index 4fbb9b1..8b93b8f 100644 --- a/src/components/AlarmRecord/List/index.js +++ b/src/components/AlarmRecord/List/index.js @@ -5,75 +5,55 @@ import Search from "zy-react-library/components/Search"; import Table from "zy-react-library/components/Table"; import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender"; import useTable from "zy-react-library/hooks/useTable"; +import { getLabelName } from "zy-react-library/utils"; import { ALARM_STATUS_OPTIONS } from "~/enumerate/constant"; +import { renderAlarmCurrentValue } from "~/utils/alarm"; import AlarmRecordView from "../View"; function AlarmRecordList(props) { const [form] = Form.useForm(); const [detailOpen, setDetailOpen] = useState(false); const [currentId, setCurrentId] = useState(""); - const { tableProps, getData } = useTable(props["alarmRecordList"], { form }); + const { tableProps, getData } = useTable(props.alarmRecordList, { + form, + transform: formData => ({ + ...formData, + alarmTimeStart: formData.alarmTime?.[0], + alarmTimeEnd: formData.alarmTime?.[1], + disposeTimeStart: formData.disposeTime?.[0], + disposeTimeEnd: formData.disposeTime?.[1], + }), + }); const handleViewDetail = (record) => { setCurrentId(record.id); setDetailOpen(true); }; - const handleSearch = (values) => { - getData({ - sensorName: values.sensorName, - disposeUserName: values.disposeUserName, - status: values.status, - alarmTimeStart: values.alarmTime?.[0]?.format?.("YYYY-MM-DD HH:mm:ss"), - alarmTimeEnd: values.alarmTime?.[1]?.format?.("YYYY-MM-DD HH:mm:ss"), - disposeTimeStart: values.disposeTime?.[0]?.format?.("YYYY-MM-DD HH:mm:ss"), - disposeTimeEnd: values.disposeTime?.[1]?.format?.("YYYY-MM-DD HH:mm:ss"), - }); - }; - - const renderCurrentValue = (_, record) => { - if (record.currentValue == null || record.currentValue === "") { - return "-"; - } - const suffix = record.compareFlag === "UP" ? " 上升" : record.compareFlag === "DOWN" ? " 下降" : ""; - const unit = record.unitName ? ` ${record.unitName}` : ""; - return `${record.currentValue}${unit}${suffix}`; - }; - - const renderAlarmStatus = (_, record) => { - if (record.status === 30) { - return "已消警"; - } - if (record.status === 40) { - return "误报"; - } - return "报警中"; - }; - return ( renderAlarmCurrentValue(record) }, + { title: "报警级别", dataIndex: "alarmLevelName" }, + { title: "报警类型", dataIndex: "alarmTypeName" }, { title: "处置人", dataIndex: "disposeUserName", @@ -93,17 +73,16 @@ function AlarmRecordList(props) { { title: "处置时间", dataIndex: "disposeTime" }, { title: "报警状态", - render: renderAlarmStatus, + dataIndex: "status", + render: (_, record) => getLabelName({ status: record.status, list: ALARM_STATUS_OPTIONS }), }, { title: "操作", width: 100, + hidden: !props.permission("bjjlgl-info"), render: (_, record) => ( - @@ -116,6 +95,7 @@ function AlarmRecordList(props) { { setDetailOpen(false); diff --git a/src/components/AlarmRecord/View/index.js b/src/components/AlarmRecord/View/index.js index cd22ec3..c6ed89d 100644 --- a/src/components/AlarmRecord/View/index.js +++ b/src/components/AlarmRecord/View/index.js @@ -1,15 +1,22 @@ -import { Descriptions, Modal } from "antd"; +import { Descriptions, Divider, Modal } from "antd"; +import dayjs from "dayjs"; import { useEffect, useState } from "react"; +import VideoIcon from "zy-react-library/components/Icon/VideoIcon"; +import Video from "zy-react-library/components/Video"; import { getLabelName } from "zy-react-library/utils"; -import { ALARM_SOURCE_OPTIONS, ALARM_STATUS_OPTIONS } from "~/enumerate/constant"; +import { DISPOSAL_STATIS, SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; +import { renderAlarmCurrentValue } from "~/utils/alarm"; +import BaiduMap from "../../BaiduMap"; function DetailModal(props) { - const [detail, setDetail] = useState(null); + const [detail, setDetail] = useState({}); + const [videoModalOpen, setVideoModalOpen] = useState(false); useEffect(() => { if (!props.open) { return; } + props.alarmRecordInfo({ id: props.currentId }).then((res) => { if (res?.success) { setDetail(res.data || {}); @@ -17,13 +24,28 @@ function DetailModal(props) { }); }, [props.open, props.currentId, props.alarmRecordInfo]); - const renderCurrentValue = () => { - if (!detail || detail.currentValue == null || detail.currentValue === "") { + const formatTime = (value) => { + if (!value) { return "-"; } - const suffix = detail.compareFlag === "UP" ? " 上升" : detail.compareFlag === "DOWN" ? " 下降" : ""; - const unit = detail.unitName ? ` ${detail.unitName}` : ""; - return `${detail.currentValue}${unit}${suffix}`; + + const time = dayjs(value); + return time.isValid() ? time.format("YYYY-MM-DD HH:mm:ss") : value; + }; + + const renderDisposalStatus = () => { + const status = detail.confirmStatus ?? detail.disposeStatus ?? detail.disposalStatus; + const statusName = detail.confirmStatusName ?? detail.disposeStatusName ?? detail.disposalStatusName; + + if (statusName) { + return statusName; + } + + if (status === 0 || status === 1) { + return getLabelName({ status, list: DISPOSAL_STATIS }) || status; + } + + return "-"; }; return ( @@ -33,31 +55,84 @@ function DetailModal(props) { title="查看" onCancel={props.onCancel} footer={null} - width={720} + maskClosable={false} + width={1200} > - {detail && ( - - {detail.alarmNo || "-"} - - {getLabelName({ status: detail.alarmSource, list: ALARM_SOURCE_OPTIONS }) || detail.alarmSource || "-"} - - {detail.sensorCode || "-"} - {detail.sensorName || "-"} - {detail.alarmTime || "-"} - {detail.alarmLevel || "-"} - {detail.alarmType || "-"} - {detail.alarmDesc || "-"} - - {getLabelName({ status: detail.status, list: ALARM_STATUS_OPTIONS }) || detail.status || "-"} - - {renderCurrentValue()} - - {detail.deviceSourceDesc || "-"} - - {detail.disposeUserName || detail.disposeUserId || "-"} - {detail.disposeTime || "-"} - {detail.disposeRemark || "-"} - + 报警信息 + + {detail.sensorCode || "-"} + {detail.sensorName || "-"} + {detail.sensorTypeName || "-"} + + {getLabelName({ status: detail.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-"} + + {renderAlarmCurrentValue(detail)} + {detail.unitName || "-"} + {detail.thresholdHighHigh || "-"} + {detail.thresholdHigh || "-"} + {detail.thresholdLowLow || "-"} + {detail.thresholdLow || "-"} + {detail.alarmNo || "-"} + {formatTime(detail.alarmTime)} + + {detail.alarmDesc || detail.deviceSourceDesc || "-"} + + + {detail.longitude && detail.latitude + ? ( + + ) + : "暂无定位信息"} + + + + {props.type === 1 && ( +
+ 报警处置 + + {renderDisposalStatus()} + {detail.assignTime || "-"} + {detail.alarmTypeName || detail.alarmType || "-"} + {detail.alarmLevelName || detail.alarmLevel || "-"} + {detail.disposeUserName || "-"} + + + 处置结果 + + {detail.disposeUserName || "-"} + {detail.disposeTime || "-"} + {detail.disposeResult || "-"} + {detail.disposeImage || "-"} + + {detail.videoUrl + ? ( + { + setVideoModalOpen(true); + }} + /> + ) + : "-"} + + +
+ )} + + {videoModalOpen && ( +
setSelectedSensorIds(keys), + }} + columns={[ + { title: "传感器编码", dataIndex: "sensorCode" }, + { title: "传感器名称", dataIndex: "sensorName" }, + { title: "传感器类型", dataIndex: "sensorTypeName" }, + { + title: "传感器属性", + dataIndex: "sensorAttr", + render: (_, record) => getLabelName({ status: record.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-", + }, + { + title: "传感器状态", + dataIndex: "sensorStatus", + render: (_, record) => getLabelName({ status: record.sensorStatus, list: SENSOR_STATUS_OPTIONS }) || "-", + }, + ]} + /> + )} ); } diff --git a/src/components/DeviceRegion/List/components/ManagerModal/index.js b/src/components/DeviceRegion/List/components/ManagerModal/index.js index a2adc04..f9268e7 100644 --- a/src/components/DeviceRegion/List/components/ManagerModal/index.js +++ b/src/components/DeviceRegion/List/components/ManagerModal/index.js @@ -1,29 +1,17 @@ import { Form, Modal } from "antd"; import { useEffect, useState } from "react"; import PersonnelSelect from "zy-react-library/components/Select/Personnel/Gwj"; -import DepartmentSelectTree from "zy-react-library/components/SelectTree/Department/Gwj"; function ManagerModal(props) { const [form] = Form.useForm(); const [departmentId, setDepartmentId] = useState(); + const [submitting, setSubmitting] = useState(false); useEffect(() => { - if (!props.open || !props.currentId) { - return; + if (props.currentRecord && props.currentRecord.fireRegionId) { + form.setFieldsValue({ managerId: props.currentRecord.managerId }); } - props.deviceRegionInfo({ id: props.currentId }).then((res) => { - if (!res?.success) { - return; - } - const data = res.data || {}; - setDepartmentId(data.departmentId); - form.setFieldsValue({ - departmentId: data.departmentId, - managerId: data.managerId, - managerName: data.managerName, - }); - }); - }, [form, props.currentId, props.deviceRegionInfo, props.open]); + }, []); const handleCancel = () => { form.resetFields(); @@ -32,9 +20,22 @@ function ManagerModal(props) { }; const handleSubmit = async (values) => { - await props.deviceRegionManager({ ...values, id: props.currentId }); - handleCancel(); - props.getData(); + if (submitting) { + return; + } + + setSubmitting(true); + values.fireRegionId = props.currentRecord.fireRegionId; + values.regionConfigId = props.currentRecord.regionConfigId; + + try { + await props.deviceRegionManager({ ...values }); + handleCancel(); + props.getData(); + } + finally { + setSubmitting(false); + } }; return ( @@ -44,21 +45,16 @@ function ManagerModal(props) { title="设置负责人" onCancel={handleCancel} onOk={form.submit} - confirmLoading={props.loading} + confirmLoading={props.loading || submitting} + maskClosable={false} + width={640} > -
- - { - setDepartmentId(value); - form.setFieldValue("managerId", undefined); - }} - /> - - + + + form.setFieldValue("managerName", label)} /> diff --git a/src/components/DeviceRegion/List/index.js b/src/components/DeviceRegion/List/index.js index 7caaa33..c2b282a 100644 --- a/src/components/DeviceRegion/List/index.js +++ b/src/components/DeviceRegion/List/index.js @@ -1,11 +1,13 @@ -import { Button, Descriptions, Form, Modal, Space } from "antd"; -import { useEffect, useMemo, useState } from "react"; +import { Button, Descriptions, Divider, Form, Modal, Space } from "antd"; +import { useEffect, useState } from "react"; import Page from "zy-react-library/components/Page"; import Search from "zy-react-library/components/Search"; import DepartmentSelectTree from "zy-react-library/components/SelectTree/Department/Gwj"; import Table from "zy-react-library/components/Table"; import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender"; import useTable from "zy-react-library/hooks/useTable"; +import { getLabelName } from "zy-react-library/utils"; +import { SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; import BindSensorModal from "./components/BindSensorModal"; import ManagerModal from "./components/ManagerModal"; @@ -14,6 +16,7 @@ function DeviceRegionList(props) { const [managerOpen, setManagerOpen] = useState(false); const [bindOpen, setBindOpen] = useState(false); const [viewOpen, setViewOpen] = useState(false); + const [viewLoading, setViewLoading] = useState(false); const [currentId, setCurrentId] = useState(""); const [viewRecord, setViewRecord] = useState(null); const [currentRecord, setCurrentRecord] = useState(null); @@ -34,52 +37,40 @@ function DeviceRegionList(props) { useEffect(() => { loadFireRegionOptions(); - }, [props.deviceRegionFireRegionList]); + }, []); - const dataSource = useMemo(() => (tableProps.dataSource || []).map(item => ({ - ...item, - departmentName: item.departmentName || "-", - managerName: item.managerName || "-", - bindSensorCount: item.bindSensorCount ?? 0, - })), [tableProps.dataSource]); - - const ensureConfigId = async (record) => { - if (record.id) { - return record.id; - } - await props.deviceRegionSaveOrUpdate({ - fireRegionId: record.fireRegionId, - fireRegionName: record.fireRegionName, - fireRegionCode: record.fireRegionCode, - departmentId: record.departmentId, - status: 1, - }); - const res = await props.deviceRegionList({ - pageIndex: 1, - pageSize: 1000, - fireRegionId: record.fireRegionId, - }); - const config = (res?.data || []).find(item => item.fireRegionId === record.fireRegionId); - if (!config?.id) { - throw new Error("区域配置创建失败"); - } - return config.id; - }; + // const dataSource = useMemo(() => (tableProps.dataSource || []).map(item => ({ + // ...item, + // departmentName: item.departmentName || "-", + // managerName: item.managerName || "-", + // bindSensorCount: item.bindSensorCount ?? 0, + // })), [tableProps.dataSource]); const handleOpenManager = async (record) => { - const configId = await ensureConfigId(record); - setCurrentId(configId); setCurrentRecord(record); setManagerOpen(true); }; const handleOpenBind = async (record) => { - const configId = await ensureConfigId(record); - setCurrentId(configId); setCurrentRecord(record); setBindOpen(true); }; + const handleOpenView = async (record) => { + setViewLoading(true); + try { + const res = await props.deviceRegionInfo({ id: record.fireRegionId }); + setViewRecord({ + ...record, + boundSensors: res?.data?.boundSensors || [], + }); + setViewOpen(true); + } + finally { + setViewLoading(false); + } + }; + return ( ( - {props.permission(editPermission) && ( - - )} - {props.permission(editPermission) && ( - - )} - + {/* )} */} + {/* {props.permission("sbqugl-szfer") && ( */} + + {/* )} */} + { + // props.permission("sbqugl-info") && + + + } ), }, ]} {...tableProps} - dataSource={dataSource} + // dataSource={dataSource} /> { setViewOpen(false); setViewRecord(null); }} - width={680} + width={1200} > + 区域信息 {viewRecord?.fireRegionName || "-"} {viewRecord?.fireRegionCode || "-"} {viewRecord?.departmentName || "-"} {viewRecord?.managerName || "-"} - {viewRecord?.bindSensorCount ?? 0} + + 设备信息 + +
getLabelName({ status: record.sensorAttr, list: SENSOR_ATTR_OPTIONS }), + }, + { + title: "传感器状态", + dataIndex: "sensorStatusName", + }, + { + title: "是否定位", + dataIndex: "positioningFlag", + render: (_, record) => record.latitude ? "是" : "否", + }, + ]} + /> {managerOpen && ( { setManagerOpen(false); setCurrentId(""); - setCurrentRecord(null); + setCurrentRecord({}); }} /> )} @@ -181,7 +206,7 @@ function DeviceRegionList(props) { open={bindOpen} currentId={currentId} currentRecord={currentRecord} - loading={props.deviceRegionLoading || props.sensorDeviceLoading} + loading={props.deviceRegionLoading} getData={getData} deviceRegionInfo={props.deviceRegionInfo} deviceRegionBindSensor={props.deviceRegionBindSensor} @@ -190,7 +215,7 @@ function DeviceRegionList(props) { onCancel={() => { setBindOpen(false); setCurrentId(""); - setCurrentRecord(null); + setCurrentRecord({}); }} /> )} diff --git a/src/components/SensorDevice/Add/index.js b/src/components/SensorDevice/Add/index.js index a49d6f8..1d03e36 100644 --- a/src/components/SensorDevice/Add/index.js +++ b/src/components/SensorDevice/Add/index.js @@ -1,27 +1,31 @@ -import { DatePicker, Form, Input, InputNumber, Modal, Radio, Select } from "antd"; +import { DatePicker, Form, Input, Modal, Select } from "antd"; import dayjs from "dayjs"; -import { useEffect } from "react"; -import Map from "zy-react-library/components/Map"; -import { ENABLE_STATUS_OPTIONS, SENSOR_STATUS_OPTIONS, YES_NO_OPTIONS } from "~/enumerate/constant"; +import { useEffect, useReducer, useRef, useState } from "react"; +import { getLabelName } from "zy-react-library/utils"; +import { SENSOR_ATTR_OPTIONS, SENSOR_STATUS_OPTIONS, YES_NO_OPTIONS } from "~/enumerate/constant"; function SensorDeviceModal(props) { const [form] = Form.useForm(); + const submitLockRef = useRef(false); + const [submitting, setSubmitting] = useState(false); + const [detailLoading, dispatchDetailLoading] = useReducer((_, value) => value, false); useEffect(() => { if (!props.open) { return; } + let active = true; + submitLockRef.current = false; + form.resetFields(); if (!props.currentId) { - form.resetFields(); - form.setFieldsValue({ - sensorStatus: "NORMAL", - positioningFlag: 0, - alarmSwitch: 0, - }); - return; + dispatchDetailLoading(false); + return () => { + active = false; + }; } + dispatchDetailLoading(true); props.sensorDeviceInfo({ id: props.currentId }).then((res) => { - if (!res?.success) { + if (!active || !res?.success) { return; } const data = { ...(res.data || {}) }; @@ -29,27 +33,56 @@ function SensorDeviceModal(props) { data.factoryDate = dayjs(data.factoryDate); } form.setFieldsValue(data); + }).finally(() => { + if (active) { + dispatchDetailLoading(false); + } }); - }, [form, props.currentId, props.open, props.sensorDeviceInfo]); + return () => { + active = false; + }; + }, [form, props.currentId, props.open]); const handleCancel = () => { + submitLockRef.current = false; + setSubmitting(false); + dispatchDetailLoading(false); form.resetFields(); props.onCancel(); }; const handleSubmit = async (values) => { + if (submitLockRef.current) { + return; + } + submitLockRef.current = true; + setSubmitting(true); + values.sensorStatusName = getLabelName({ status: values.sensorStatus, list: SENSOR_STATUS_OPTIONS }); const payload = { ...values, factoryDate: values.factoryDate ? values.factoryDate.format("YYYY-MM-DD") : undefined, }; - if (props.currentId) { - await props.sensorDeviceEdit({ ...payload, id: props.currentId }); + let res; + try { + if (props.currentId) { + res = await props.sensorDeviceEdit({ ...payload, id: props.currentId }); + } + else { + res = await props.sensorDeviceSave(payload); + } + if (res?.success) { + handleCancel(); + props.getData(); + return; + } + submitLockRef.current = false; + setSubmitting(false); } - else { - await props.sensorDeviceSave(payload); + catch (error) { + submitLockRef.current = false; + setSubmitting(false); + throw error; } - handleCancel(); - props.getData(); }; return ( @@ -59,32 +92,32 @@ function SensorDeviceModal(props) { title={props.currentId ? "编辑传感器设备" : "新增传感器设备"} onCancel={handleCancel} onOk={form.submit} - confirmLoading={props.loading} + confirmLoading={props.loading || submitting || detailLoading} + loading={!!props.currentId && (props.loading || detailLoading)} + maskClosable={false} width={720} + > - + - + { + props.sensorTypeOptions.forEach((item) => { + if (item.id === e) { + form.setFieldsValue({ sensorAttr: item.sensorAttr }); + } + }); + }} /> - - + + ({ + value: item.bianma, + label: item.name, + }))} + placeholder="请选择传感器状态" + + /> + - - - {YES_NO_OPTIONS.map(item => ( - - {item.name} - - ))} - + + - - - {ENABLE_STATUS_OPTIONS.map(item => ( - - {item.name} - - ))} - + + - - - - - - - - - - - - - - - - - + +
); diff --git a/src/components/SensorDevice/components/ThresholdModal/index.js b/src/components/SensorDevice/components/ThresholdModal/index.js index fd30530..f4d0d3f 100644 --- a/src/components/SensorDevice/components/ThresholdModal/index.js +++ b/src/components/SensorDevice/components/ThresholdModal/index.js @@ -1,32 +1,107 @@ -import { Alert, Form, InputNumber, Modal } from "antd"; -import { useEffect, useState } from "react"; +import { Form, Input, InputNumber, Modal, Select } from "antd"; +import { useEffect, useReducer, useRef, useState } from "react"; +import { SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; function ThresholdModal(props) { const [form] = Form.useForm(); + const submitLockRef = useRef(false); const [sensorAttr, setSensorAttr] = useState(""); + const [submitting, setSubmitting] = useState(false); + const [detailLoading, dispatchDetailLoading] = useReducer((_, value) => value, false); useEffect(() => { - if (!props.open || !props.currentId) { + if (!props.open) { return; } + + let active = true; + submitLockRef.current = false; + setSubmitting(false); + form.resetFields(); + setSensorAttr(""); + + if (!props.currentId) { + dispatchDetailLoading(false); + return () => { + active = false; + }; + } + + dispatchDetailLoading(true); props.sensorDeviceInfo({ id: props.currentId }).then((res) => { - if (res?.success) { - form.setFieldsValue(res.data || {}); - setSensorAttr(res.data?.sensorAttr || ""); + if (!active || !res?.success) { + return; + } + + const data = { ...(res.data || {}) }; + data.sensorTypeName = data.sensorTypeName || props.record.sensorTypeName; + form.setFieldsValue(data); + setSensorAttr(data.sensorAttr || ""); + }).finally(() => { + if (active) { + dispatchDetailLoading(false); } }); - }, [form, props.currentId, props.open, props.sensorDeviceInfo]); + + return () => { + active = false; + }; + }, []); + + const validateHighAlarm = (_, value) => { + const highHighAlarm = form.getFieldValue("thresholdHighHigh"); + if (value === undefined || value === null || highHighAlarm === undefined || highHighAlarm === null) { + return Promise.resolve(); + } + if (Number(value) > Number(highHighAlarm)) { + return Promise.reject(new Error("高报警阈值默认值不能大于高高报警阈值默认值")); + } + return Promise.resolve(); + }; + + const validateLowAlarm = (_, value) => { + const lowLowAlarm = form.getFieldValue("thresholdLowLow"); + if (value === undefined || value === null || lowLowAlarm === undefined || lowLowAlarm === null) { + return Promise.resolve(); + } + if (Number(value) < Number(lowLowAlarm)) { + return Promise.reject(new Error("低报警阈值默认值不能小于低低报警阈值默认值")); + } + return Promise.resolve(); + }; const handleCancel = () => { + submitLockRef.current = false; + setSubmitting(false); + dispatchDetailLoading(false); form.resetFields(); setSensorAttr(""); props.onCancel(); }; const handleSubmit = async (values) => { - await props.sensorDeviceThreshold({ ...values, id: props.currentId }); - handleCancel(); - props.getData(); + if (submitLockRef.current) { + return; + } + + submitLockRef.current = true; + setSubmitting(true); + + try { + const res = await props.sensorDeviceEdit({ ...values, id: props.currentId }); + if (res?.success) { + handleCancel(); + props.getData(); + return; + } + submitLockRef.current = false; + setSubmitting(false); + } + catch (error) { + submitLockRef.current = false; + setSubmitting(false); + throw error; + } }; const isNumberType = sensorAttr === "NUMBER"; @@ -35,38 +110,96 @@ function ThresholdModal(props) { - {!isNumberType && sensorAttr && ( - - )} - {isNumberType && ( - - - - - - - - - - - - - - - )} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + +
); } diff --git a/src/components/SensorType/Add/index.js b/src/components/SensorType/Add/index.js index ba41b01..c2d29d7 100644 --- a/src/components/SensorType/Add/index.js +++ b/src/components/SensorType/Add/index.js @@ -1,44 +1,101 @@ -import { Form, Input, InputNumber, Modal, Radio } from "antd"; -import { useEffect } from "react"; -import { ENABLE_STATUS_OPTIONS, SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; +import { Form, Input, InputNumber, message, Modal, Select } from "antd"; +import { useEffect, useRef, useState } from "react"; +import { SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; function SensorTypeModal(props) { const [form] = Form.useForm(); + const submitLockRef = useRef(false); + const [submitting, setSubmitting] = useState(false); + + const validateHighAlarm = (_, value) => { + const highHighAlarm = form.getFieldValue("thresholdHighHigh"); + if (value === undefined || value === null || highHighAlarm === undefined || highHighAlarm === null) { + return Promise.resolve(); + } + if (Number(value) > Number(highHighAlarm)) { + return Promise.reject(new Error("高报警阈值默认值不能大于高高报警阈值默认值")); + } + return Promise.resolve(); + }; + + const validateLowAlarm = (_, value) => { + const lowLowAlarm = form.getFieldValue("thresholdLowLow"); + if (value === undefined || value === null || lowLowAlarm === undefined || lowLowAlarm === null) { + return Promise.resolve(); + } + if (Number(value) < Number(lowLowAlarm)) { + return Promise.reject(new Error("低报警阈值默认值不能小于低低报警阈值默认值")); + } + return Promise.resolve(); + }; useEffect(() => { if (!props.open) { return; } + let active = true; + submitLockRef.current = false; + form.resetFields(); + if (!props.currentId) { - form.resetFields(); form.setFieldsValue({ sensorAttr: "NUMBER", - status: 1, - sortNo: 0, }); - return; + return () => { + active = false; + }; } - props.sensorTypeInfo({ id: props.currentId }).then((res) => { - if (res?.success) { - form.setFieldsValue(res.data || {}); + console.log( props.currentId); + props["sensorTypeInfo"]({ id: props.currentId }).then((res) => { + + if (!active || !res?.success) { + return; } + form.setFieldsValue({ + sensorAttr: "NUMBER", + ...(res.data || {}), + }); }); - }, [form, props.currentId, props.open, props.sensorTypeInfo]); + return () => { + active = false; + }; + }, [form, props.currentId, props.open]); const handleCancel = () => { + submitLockRef.current = false; + setSubmitting(false); form.resetFields(); props.onCancel(); }; const handleSubmit = async (values) => { - if (props.currentId) { - await props.sensorTypeEdit({ ...values, id: props.currentId }); + if (submitLockRef.current) { + return; } - else { - await props.sensorTypeSave(values); + submitLockRef.current = true; + setSubmitting(true); + let res; + try { + if (props.currentId) { + res = await props.sensorTypeEdit({ ...values, id: props.currentId }); + } + else { + res = await props.sensorTypeSave(values); + } + if (res?.success) { + message.success("操作成功!"); + handleCancel(); + props.getData(); + return; + } + submitLockRef.current = false; + setSubmitting(false); + } + catch (error) { + submitLockRef.current = false; + setSubmitting(false); + throw error; } - handleCancel(); - props.getData(); }; return ( @@ -48,64 +105,103 @@ function SensorTypeModal(props) { title={props.currentId ? "编辑传感器类型" : "新增传感器类型"} onCancel={handleCancel} onOk={form.submit} - confirmLoading={props.loading} + confirmLoading={props.loading || submitting} + maskClosable={false} width={640} >
+ {/* */} + {/* */} + {/* */} - - - - + - - {SENSOR_ATTR_OPTIONS.map(item => ( - - {item.name} - - ))} - + + + + + + + + + + + + + + + + + + + + + + )} diff --git a/src/components/SensorType/List/index.js b/src/components/SensorType/List/index.js index 5d1f15b..2be7888 100644 --- a/src/components/SensorType/List/index.js +++ b/src/components/SensorType/List/index.js @@ -18,16 +18,16 @@ function SensorTypeList(props) { const [currentId, setCurrentId] = useState(""); const { tableProps, getData } = useTable(props["sensorTypeList"], { form }); - const pageType = props.type || "fgs"; - const editPermission = `${pageType}-iotalarm-sensor-type-edit`; - const handleDelete = (record) => { Modal.confirm({ title: "确定删除这条传感器类型吗?", + maskClosable: false, onOk: async () => { - await props["sensorTypeRemove"]({ id: record.id }); - message.success("删除成功"); - getData(); + const res = await props["sensorTypeRemove"]({ id: record.id }); + if (res?.success) { + message.success("删除成功"); + getData(); + } }, }); }; @@ -45,18 +45,18 @@ function SensorTypeList(props) { rowKey="id" toolBarRender={() => ( - {props.permission(editPermission) && ( - - )} + {/* {props.permission("cgqbj-add") && ( */} + + {/* )} */} )} columns={[ @@ -64,13 +64,16 @@ function SensorTypeList(props) { { title: "传感器属性", dataIndex: "sensorAttr", - render: value => getLabelName({ status: value, list: SENSOR_ATTR_OPTIONS }) || value || "-", + render: (_, record) => getLabelName({ status: record.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-", }, { title: "操作", width: 220, render: (_, record) => ( + {/* { */} + {/* props.permission("cgqbj-info") && ( */} + - {props.permission(editPermission) && ( - - )} - {props.permission(editPermission) && ( - - )} + ) + {/* } */} + {/* {props.permission("cgqbj-edit") && ( */} + + {/* )} */} + {/* {props.permission("cgqbj-del") && ( */} + + {/* )} */} ), }, diff --git a/src/components/SensorType/View/index.js b/src/components/SensorType/View/index.js index e23c4c3..17866e9 100644 --- a/src/components/SensorType/View/index.js +++ b/src/components/SensorType/View/index.js @@ -4,6 +4,26 @@ import { SENSOR_ATTR_OPTIONS } from "~/enumerate/constant"; function ViewModal(props) { const record = props.record || {}; + const isNumberAttr = record.sensorAttr === "NUMBER"; + const items = [ + { label: "传感器类型", children: record.typeName || "-" }, + { + label: "传感器属性", + children: getLabelName({ status: record.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || record.sensorAttr || "-", + }, + ]; + + if (isNumberAttr) { + items.push( + { label: "计量单位", children: record.unitName || "-" }, + { label: "量程上限默认值", children: record.rangeMax || "-" }, + { label: "量程下限默认值", children: record.rangeMin || "-" }, + { label: "高高报警阈值默认值", children: record.thresholdHighHigh || "-" }, + { label: "高报警阈值默认值", children: record.thresholdHigh || "-" }, + { label: "低低报警阈值默认值", children: record.thresholdLowLow || "-" }, + { label: "低报警阈值默认值", children: record.thresholdLow || "-" }, + ); + } return ( @@ -22,14 +43,8 @@ function ViewModal(props) { ); diff --git a/src/components/ThresholdAlarmInfo/List/index.js b/src/components/ThresholdAlarmInfo/List/index.js index 01a5ebf..d831a21 100644 --- a/src/components/ThresholdAlarmInfo/List/index.js +++ b/src/components/ThresholdAlarmInfo/List/index.js @@ -6,38 +6,27 @@ import Table from "zy-react-library/components/Table"; import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender"; import useTable from "zy-react-library/hooks/useTable"; import AlarmRecordView from "~/components/AlarmRecord/View"; +import { renderAlarmCurrentValue } from "~/utils/alarm"; function ThresholdList(props) { const [form] = Form.useForm(); const [detailOpen, setDetailOpen] = useState(false); const [currentId, setCurrentId] = useState(""); - const { tableProps, getData } = useTable(props["thresholdAlarmInfoList"], { + const { tableProps, getData } = useTable(props.thresholdAlarmInfoList, { form, - defaultParams: { alarmSource: "THRESHOLD" }, + transform: formData => ({ + ...formData, + alarmTimeStart: formData.alarmTime?.[0], + alarmTimeEnd: formData.alarmTime?.[1], + alarmSource: "THRESHOLD", + }), }); - const handleSearch = (values) => { - getData({ - sensorName: values.sensorName, - alarmTimeStart: values.alarmTime?.[0]?.format?.("YYYY-MM-DD HH:mm:ss"), - alarmTimeEnd: values.alarmTime?.[1]?.format?.("YYYY-MM-DD HH:mm:ss"), - }); - }; - - const renderCurrentValue = (_, record) => { - if (record.currentValue == null || record.currentValue === "") { - return "-"; - } - const suffix = record.compareFlag === "UP" ? " 上升" : record.compareFlag === "DOWN" ? " 下降" : ""; - const unit = record.unitName ? ` ${record.unitName}` : ""; - return `${record.currentValue}${unit}${suffix}`; - }; - return ( renderAlarmCurrentValue(record) }, { title: "操作", width: 100, + hidden: !props.permission("yzbjxx-info"), render: (_, record) => (
{ @@ -76,7 +66,7 @@ function ThresholdList(props) { { setDetailOpen(false); setCurrentId(""); diff --git a/src/enumerate/constant/index.js b/src/enumerate/constant/index.js index 7908833..610f5ce 100644 --- a/src/enumerate/constant/index.js +++ b/src/enumerate/constant/index.js @@ -19,13 +19,13 @@ export const SENSOR_STATUS_OPTIONS = [ { bianma: "NORMAL", name: "正常" }, { bianma: "FAULT", name: "故障" }, { bianma: "OFFLINE", name: "离线" }, + { bianma: "deactivate", name: "停用" }, ]; export const ALARM_STATUS_OPTIONS = [ - { bianma: 10, name: "报警中-待研判" }, - { bianma: 20, name: "报警中-待处置" }, - { bianma: 30, name: "已消警" }, - { bianma: 40, name: "误报" }, + { bianma: 10, name: "已报警" }, + { bianma: 20, name: "报警中" }, + { bianma: 30, name: "已取消" }, ]; export const ALARM_SOURCE_OPTIONS = [ @@ -42,3 +42,7 @@ export const ALARM_TYPE_OPTIONS = [ { bianma: "DCS_ALARM", name: "DCS 报警" }, { bianma: "THRESHOLD_ALARM", name: "阈值报警" }, ]; +export const DISPOSAL_STATIS = [ + { bianma: 1, name: "误报" }, + { bianma: 0, name: "处置" }, +]; diff --git a/src/main.js b/src/main.js index 2b6d039..6e42252 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,6 @@ import { setJJBCommonAntdMessage } from "@cqsjjb/jjb-common-lib"; import { setup } from "@cqsjjb/jjb-dva-runtime"; -import { message } from "antd"; +import { ConfigProvider, message } from "antd"; import dayjs from "dayjs"; import { getFileUrlFromServer } from "zy-react-library/utils"; import "dayjs/locale/zh-cn"; @@ -9,6 +9,12 @@ import "../blessed_by_buddha"; require("antd/dist/reset.css"); require("zy-react-library/css/common.less"); +const ANT_PREFIX = process.env.app.antd?.["ant-prefix"] || "ant"; + +ConfigProvider.config({ + prefixCls: ANT_PREFIX, +}); + dayjs.locale("zh-cn"); setJJBCommonAntdMessage(message); window.mapLongitude = "119.69457721306945"; diff --git a/src/pages/Container/index.js b/src/pages/Container/index.js index 63066e3..31302cf 100644 --- a/src/pages/Container/index.js +++ b/src/pages/Container/index.js @@ -5,6 +5,8 @@ import React from "react"; import { InjectContext } from "~/enumerate/context"; +const ANT_PREFIX = process.env.app.antd?.["ant-prefix"] || "ant"; + export default class Container extends React.Component { state = window?.base?.themeConfig || { algorithm: "defaultAlgorithm", @@ -38,6 +40,7 @@ export default class Container extends React.Component { render() { return ( thresholdHighHigh) + || (Number.isFinite(thresholdHigh) && currentValue > thresholdHigh) + ) { + suffix = " ↑"; + color = "red"; + } else if ( + (Number.isFinite(thresholdLowLow) && currentValue < thresholdLowLow) + || (Number.isFinite(thresholdLow) && currentValue < thresholdLow) + ) { + suffix = " ↓"; + color = "red"; + } + + const unit = record.unitName ? ` ${record.unitName}` : ""; + const content = `${record.currentValue}${unit}${suffix}`; + return color ? {content} : content; +}