修改页面 调试接口

main
853931625@qq.com 2026-04-30 15:59:22 +08:00
parent 54b2201fd2
commit 40c99ec0fa
31 changed files with 1632 additions and 732 deletions

View File

@ -9,8 +9,8 @@ module.exports = {
// 应用后端分支名称,部署上线需要
javaGitBranch: "<branch-name>",
// 接口服务地址
// 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: {

View File

@ -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",

View File

@ -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}");

View File

@ -6,5 +6,5 @@ export const alarmRecordList = declareRequest(
);
export const alarmRecordInfo = declareRequest(
"alarmRecordLoading",
`Get > @/iotalarm/alarmRecord/{id}`,
`Get > /iotalarm/alarmRecord/{id}`,
);

View File

@ -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}");

View File

@ -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");

View File

@ -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}");

View File

@ -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}
>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item
label="处置人"
name="disposeUserId"
rules={[{ required: true, message: "请选择处置人" }]}
>
<PersonnelSelect placeholder="请选择处置人" />
</Form.Item>
{!props.isBatch && (
<>
<Divider orientation="left">报警信息</Divider>
<Descriptions column={2} bordered labelStyle={{ width: 200 }}>
<Descriptions.Item label="传感器编码">{detail.sensorCode || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器名称">{detail.sensorName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器类型">{detail.sensorTypeName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器属性">
{getLabelName({ status: detail.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-"}
</Descriptions.Item>
<Descriptions.Item label="告警值">{renderAlarmCurrentValue(detail)}</Descriptions.Item>
<Descriptions.Item label="计量单位">{detail.unitName || "-"}</Descriptions.Item>
<Descriptions.Item label="高高报警阈值">{detail.thresholdHighHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="高报警阈值">{detail.thresholdHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="低低报警阈值">{detail.thresholdLowLow || "-"}</Descriptions.Item>
<Descriptions.Item label="低报警阈值">{detail.thresholdLow || "-"}</Descriptions.Item>
<Descriptions.Item label="报警编号">{detail.alarmNo || "-"}</Descriptions.Item>
<Descriptions.Item label="报警时间">{formatTime(detail.alarmTime)}</Descriptions.Item>
<Descriptions.Item label="报警描述" span={2}>
{detail.alarmDesc || detail.deviceSourceDesc || "-"}
</Descriptions.Item>
<Descriptions.Item label="报警位置" span={2}>
{detail.longitude && detail.latitude
? (
<BaiduMap
longitude={detail.longitude}
latitude={detail.latitude}
style={{
border: "1px solid #f0f0f0",
borderRadius: 4,
overflow: "hidden",
}}
/>
)
: "暂无定位信息"}
</Descriptions.Item>
</Descriptions>
</>
)}
<Divider orientation="left">处置分配</Divider>
<Form
form={form}
layout="horizontal"
onFinish={handleSubmit}
labelCol={{ span: 4 }}
initialValues={{ disposeStatus: 0 }}
>
<Row>
<Col span={12}>
<Form.Item
label="报警处置"
name="disposeStatus"
rules={[{ required: true, message: "请选择报警处置" }]}
>
<Select
options={DISPOSAL_STATIS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择报警处置"
/>
</Form.Item>
</Col>
{disposeStatus !== 1 && (
<Col span={12}>
<Form.Item
label="报警类型"
name="alarmType"
rules={[{ required: true, message: "请选择报警类型" }]}
>
<DictionarySelect
dictValue="alarmType"
onGetLabel={label => {
alarmTypeName.current = label;
}}
/>
</Form.Item>
</Col>
)}
</Row>
{disposeStatus !== 1 && (
<Row>
<Col span={12}>
<Form.Item
label="报警级别"
name="alarmLevel"
rules={[{ required: true, message: "请选择报警级别" }]}
>
<DictionarySelect
dictValue="alarmLevel"
onGetLabel={label => {
alarmLevelName.current = label;
}}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="处置人"
name="disposeUserId"
rules={[{ required: true, message: "请选择处置人" }]}
>
<PersonnelSelect
placeholder="请选择处置人"
isNeedDepartmentId={false}
isNeedCorpInfoId={true}
params={{ corpinfoId }}
/>
</Form.Item>
</Col>
</Row>
)}
</Form>
</Modal>
);

View File

@ -6,6 +6,7 @@ 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";
import AssignModal from "./components/AssignModal";
function AssignList(props) {
@ -16,11 +17,15 @@ function AssignList(props) {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [currentAlarmId, setCurrentAlarmId] = useState(null);
const [isBatch, setIsBatch] = useState(false);
const { tableProps, getData } = useTable(props["alarmAssignList"], { form });
const pageType = props.type || "fgs";
const assignPermission = `${pageType}-iotalarm-alarm-assign`;
const { tableProps, getData } = useTable(props.alarmRecordList, {
form,
transform: formData => ({
...formData,
alarmTimeStart: formData.alarmTime?.[0],
alarmTimeEnd: formData.alarmTime?.[1],
status: 10,
}),
});
const handleBatchAssign = () => {
if (selectedRowKeys.length === 0) {
@ -43,28 +48,11 @@ function AssignList(props) {
onChange: setSelectedRowKeys,
};
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 (
<Page isShowAllAction={false}>
<Search
form={form}
onFinish={handleSearch}
onFinish={getData}
options={[
{ name: "sensorName", label: "传感器名称" },
{ name: "alarmTime", label: "报警时间", render: FORM_ITEM_RENDER_ENUM.DATE_RANGE },
@ -75,11 +63,13 @@ function AssignList(props) {
rowSelection={rowSelection}
toolBarRender={() => (
<Space>
{props.permission(assignPermission) && (
{
// props.permission("bjczfp-plcz") &&
<Button type="primary" onClick={handleBatchAssign}>
批量处置
</Button>
)}
}
</Space>
)}
columns={[
@ -87,26 +77,36 @@ function AssignList(props) {
{ title: "传感器名称", dataIndex: "sensorName", ellipsis: true },
{ title: "报警时间", dataIndex: "alarmTime", width: 180 },
{ title: "报警描述", dataIndex: "alarmDesc", ellipsis: true },
{ title: "告警值", render: renderCurrentValue },
{ title: "告警值", render: (_, record) => renderAlarmCurrentValue(record) },
{
title: "操作",
width: 180,
render: (_, record) => (
<Space>
{props.permission(assignPermission) && (
<Button type="link" onClick={() => handleSingleAssign(record)}>
处置分配
</Button>
)}
<Button
type="link"
onClick={() => {
setDetailId(record.id);
setDetailOpen(true);
}}
>
查看
</Button>
{
props.permission("bjczfp-czfp")
&& (
<Button type="link" onClick={() => handleSingleAssign(record)}>
处置分配
</Button>
)
}
{
props.permission("bjczfp-info")
&& (
<Button
type="link"
onClick={() => {
setDetailId(record.id);
setDetailOpen(true);
}}
>
查看
</Button>
)
}
</Space>
),
},
@ -132,6 +132,7 @@ function AssignList(props) {
alarmIds={selectedRowKeys}
loading={props.alarmDisposeLoading}
getData={getData}
alarmRecordInfo={props.alarmRecordInfo}
alarmAssign={props.alarmAssign}
alarmBatchAssign={props.alarmBatchAssign}
onCancel={() => {

View File

@ -0,0 +1,124 @@
import { Descriptions, Divider, Form, Modal, Select } from "antd";
import { useEffect, useState } from "react";
import PersonnelSelect from "zy-react-library/components/Select/Personnel/Gwj";
import { DISPOSAL_STATIS } from "~/enumerate/constant";
import { renderAlarmCurrentValue } from "~/utils/alarm";
function DetailModal(props) {
const [form] = Form.useForm();
const [detail, setDetail] = useState(null);
useEffect(() => {
if (!props.open) {
return;
}
props.alarmRecordInfo({ id: props.currentId }).then((res) => {
if (res?.success) {
setDetail(res.data || {});
}
});
}, [props.open, props.currentId, props.alarmRecordInfo]);
const handleSubmit = async (values) => {
if (props.isBatch) {
await props.alarmBatchAssign({
ids: props.alarmIds,
disposeUserId: values.disposeUserId,
});
} else {
await props.alarmAssign({
id: props.alarmId,
disposeUserId: values.disposeUserId,
});
}
props.history.goBack();
};
return (
<Modal
destroyOnClose
open={props.open}
title="查看"
onCancel={props.onCancel}
footer={null}
maskClosable={false}
width={720}
>
<Divider orientation="left">报警信息</Divider>
{detail && (
<Descriptions column={2} bordered>
<Descriptions.Item label="传感器编码">{detail.sensorCode || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器名称">{detail.sensorName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器类型">{detail.sensorTypeName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器属性">{detail.sensorAttrName || "-"}</Descriptions.Item>
<Descriptions.Item label="告警值">{renderAlarmCurrentValue(detail)}</Descriptions.Item>
<Descriptions.Item label="计量单位">{detail.unitName || "-"}</Descriptions.Item>
<Descriptions.Item label="高高报警阈值">{detail.thresholdHighHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="高报警阈值">{detail.thresholdHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="低低报警阈值">{detail.thresholdLowLow || "-"}</Descriptions.Item>
<Descriptions.Item label="低报警阈值">{detail.thresholdLow || "-"}</Descriptions.Item>
<Descriptions.Item label="报警编号">{detail.alarmNo || "-"}</Descriptions.Item>
<Descriptions.Item label="报警时间">{detail.alarmTime || "-"}</Descriptions.Item>
<Descriptions.Item label="报警描述" span={2}>
{detail.deviceSourceDesc || "-"}
</Descriptions.Item>
<Descriptions.Item label="报警位置" span={2}>{detail.disposeRemark || "-"}</Descriptions.Item>
</Descriptions>
)}
<Divider orientation="left">处置分配</Divider>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item
label="报警处置"
name="disposeUserId"
rules={[{ required: true, message: "请选择报警处置" }]}
>
<Select
options={DISPOSAL_STATIS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择报警处置"
disabled
/>
</Form.Item>
<Form.Item
label="报警类型"
name="disposeUserId"
rules={[{ required: true, message: "请选择报警类型" }]}
>
<Select
options={DISPOSAL_STATIS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择报警类型"
disabled
/>
</Form.Item>
<Form.Item
label="报警级别"
name="disposeUserId"
rules={[{ required: true, message: "请选择报警级别" }]}
>
<Select
options={DISPOSAL_STATIS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择报警级别"
disabled
/>
</Form.Item>
<Form.Item
label="处置人"
name="disposeUserId"
rules={[{ required: true, message: "请选择处置人" }]}
>
<PersonnelSelect placeholder="请选择处置人" />
</Form.Item>
</Form>
</Modal>
);
}
export default DetailModal;

View File

@ -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 (
<Page isShowAllAction={false}>
<Search
form={form}
onFinish={handleSearch}
onFinish={getData}
options={[
{ name: "sensorName", label: "传感器名称" },
{ name: "disposeUserName", label: "处置人" },
{
name: "alarmTime",
label: "报警时间",
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
},
{
name: "status",
label: "报警状态",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: ALARM_STATUS_OPTIONS,
},
{
name: "alarmTime",
label: "报警时间",
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
},
{
name: "disposeTime",
label: "处置时间",
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
},
{ name: "disposeUserName", label: "处置人" },
]}
/>
<Table
@ -83,9 +63,9 @@ function AlarmRecordList(props) {
{ title: "传感器名称", dataIndex: "sensorName" },
{ title: "报警时间", dataIndex: "alarmTime" },
{ title: "报警描述", dataIndex: "alarmDesc", ellipsis: true },
{ title: "告警值", render: renderCurrentValue },
{ title: "报警级别", dataIndex: "alarmLevel" },
{ title: "报警类型", dataIndex: "alarmType" },
{ title: "告警值", render: (_, record) => 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) => (
<Space>
<Button
type="link"
onClick={() => handleViewDetail(record)}
>
<Button type="link" onClick={() => handleViewDetail(record)}>
查看
</Button>
</Space>
@ -116,6 +95,7 @@ function AlarmRecordList(props) {
<AlarmRecordView
open={detailOpen}
currentId={currentId}
type={1}
alarmRecordInfo={props.alarmRecordInfo}
onCancel={() => {
setDetailOpen(false);

View File

@ -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 && (
<Descriptions column={2} bordered>
<Descriptions.Item label="报警编号">{detail.alarmNo || "-"}</Descriptions.Item>
<Descriptions.Item label="报警来源">
{getLabelName({ status: detail.alarmSource, list: ALARM_SOURCE_OPTIONS }) || detail.alarmSource || "-"}
</Descriptions.Item>
<Descriptions.Item label="传感器编码">{detail.sensorCode || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器名称">{detail.sensorName || "-"}</Descriptions.Item>
<Descriptions.Item label="报警时间">{detail.alarmTime || "-"}</Descriptions.Item>
<Descriptions.Item label="报警级别">{detail.alarmLevel || "-"}</Descriptions.Item>
<Descriptions.Item label="报警类型">{detail.alarmType || "-"}</Descriptions.Item>
<Descriptions.Item label="报警描述">{detail.alarmDesc || "-"}</Descriptions.Item>
<Descriptions.Item label="状态">
{getLabelName({ status: detail.status, list: ALARM_STATUS_OPTIONS }) || detail.status || "-"}
</Descriptions.Item>
<Descriptions.Item label="告警值">{renderCurrentValue()}</Descriptions.Item>
<Descriptions.Item label="设备来源描述" span={2}>
{detail.deviceSourceDesc || "-"}
</Descriptions.Item>
<Descriptions.Item label="处置人">{detail.disposeUserName || detail.disposeUserId || "-"}</Descriptions.Item>
<Descriptions.Item label="处置时间">{detail.disposeTime || "-"}</Descriptions.Item>
<Descriptions.Item label="处置备注" span={2}>{detail.disposeRemark || "-"}</Descriptions.Item>
</Descriptions>
<Divider orientation="left">报警信息</Divider>
<Descriptions column={2} bordered labelStyle={{ width: 200 }}>
<Descriptions.Item label="传感器编码">{detail.sensorCode || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器名称">{detail.sensorName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器类型">{detail.sensorTypeName || "-"}</Descriptions.Item>
<Descriptions.Item label="传感器属性">
{getLabelName({ status: detail.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || "-"}
</Descriptions.Item>
<Descriptions.Item label="告警值">{renderAlarmCurrentValue(detail)}</Descriptions.Item>
<Descriptions.Item label="计量单位">{detail.unitName || "-"}</Descriptions.Item>
<Descriptions.Item label="高高报警阈值">{detail.thresholdHighHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="高报警阈值">{detail.thresholdHigh || "-"}</Descriptions.Item>
<Descriptions.Item label="低低报警阈值">{detail.thresholdLowLow || "-"}</Descriptions.Item>
<Descriptions.Item label="低报警阈值">{detail.thresholdLow || "-"}</Descriptions.Item>
<Descriptions.Item label="报警编号">{detail.alarmNo || "-"}</Descriptions.Item>
<Descriptions.Item label="报警时间">{formatTime(detail.alarmTime)}</Descriptions.Item>
<Descriptions.Item label="报警描述" span={2}>
{detail.alarmDesc || detail.deviceSourceDesc || "-"}
</Descriptions.Item>
<Descriptions.Item label="报警位置" span={2}>
{detail.longitude && detail.latitude
? (
<BaiduMap
longitude={detail.longitude}
latitude={detail.latitude}
style={{
border: "1px solid #f0f0f0",
borderRadius: 4,
overflow: "hidden",
}}
/>
)
: "暂无定位信息"}
</Descriptions.Item>
</Descriptions>
{props.type === 1 && (
<div>
<Divider orientation="left">报警处置</Divider>
<Descriptions column={2} bordered labelStyle={{ width: 200 }}>
<Descriptions.Item label="报警确认">{renderDisposalStatus()}</Descriptions.Item>
<Descriptions.Item label="确认时间">{detail.assignTime || "-"}</Descriptions.Item>
<Descriptions.Item label="报警类型">{detail.alarmTypeName || detail.alarmType || "-"}</Descriptions.Item>
<Descriptions.Item label="报警级别">{detail.alarmLevelName || detail.alarmLevel || "-"}</Descriptions.Item>
<Descriptions.Item label="处置人">{detail.disposeUserName || "-"}</Descriptions.Item>
</Descriptions>
<Divider orientation="left">处置结果</Divider>
<Descriptions column={2} bordered labelStyle={{ width: 200 }}>
<Descriptions.Item label="处置人">{detail.disposeUserName || "-"}</Descriptions.Item>
<Descriptions.Item label="处置时间">{detail.disposeTime || "-"}</Descriptions.Item>
<Descriptions.Item label="处置结果" span={2}>{detail.disposeResult || "-"}</Descriptions.Item>
<Descriptions.Item label="处置图片" span={2}>{detail.disposeImage || "-"}</Descriptions.Item>
<Descriptions.Item label="处置视频" span={2}>
{detail.videoUrl
? (
<VideoIcon
onClick={() => {
setVideoModalOpen(true);
}}
/>
)
: "-"}
</Descriptions.Item>
</Descriptions>
</div>
)}
{videoModalOpen && (
<Video
visible={videoModalOpen}
source={detail.videoUrl}
onCancel={() => setVideoModalOpen(false)}
title="处置视频"
/>
)}
</Modal>
);

View File

@ -0,0 +1,66 @@
import { useState } from "react";
import LocationIcon from "zy-react-library/components/Icon/LocationIcon";
import MapSelector from "zy-react-library/components/Map/MapSelector";
function BaiduMap({
longitude,
latitude,
disable = true,
onChange,
onConfirm,
enablePointSelect,
onPointSelect,
}) {
const [mapVisible, setMapVisible] = useState(false);
const [selectedLocation, setSelectedLocation] = useState({
longitude: "",
latitude: "",
});
const currentLongitude = longitude || selectedLocation.longitude;
const currentLatitude = latitude || selectedLocation.latitude;
const mapDisabled = disable && !enablePointSelect;
const handleConfirm = (nextLongitude, nextLatitude, extra) => {
setSelectedLocation({
longitude: nextLongitude,
latitude: nextLatitude,
});
onPointSelect?.(nextLongitude, nextLatitude, extra);
onChange?.(nextLongitude, nextLatitude, extra);
onConfirm?.(nextLongitude, nextLatitude, extra);
setMapVisible(false);
};
return (
<div>
<div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
<span>
经度
{currentLongitude || "-"}
</span>
<span>
纬度
{currentLatitude || "-"}
</span>
<LocationIcon onClick={() => {
setMapVisible(true);
}}
/>
</div>
{mapVisible && (
<MapSelector
visible={mapVisible}
onClose={() => setMapVisible(false)}
longitude={currentLongitude}
latitude={currentLatitude}
disable={mapDisabled}
onConfirm={handleConfirm}
/>
)}
</div>
);
}
export default BaiduMap;

View File

@ -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 DcsList(props) {
const [form] = Form.useForm();
const [detailOpen, setDetailOpen] = useState(false);
const [currentId, setCurrentId] = useState("");
const { tableProps, getData } = useTable(props["dcsAlarmInfoList"], {
const { tableProps, getData } = useTable(props.dcsAlarmInfoList, {
form,
defaultParams: { alarmSource: "DCS" },
transform: formData => ({
...formData,
alarmTimeStart: formData.alarmTime?.[0],
alarmTimeEnd: formData.alarmTime?.[1],
alarmSource: "DCS",
}),
});
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 (
<Page isShowAllAction={false}>
<Search
form={form}
onFinish={handleSearch}
onFinish={getData}
options={[
{ name: "sensorName", label: "传感器名称" },
{
@ -54,10 +43,11 @@ function DcsList(props) {
{ title: "传感器名称", dataIndex: "sensorName" },
{ title: "报警时间", dataIndex: "alarmTime" },
{ title: "报警描述", dataIndex: "alarmDesc", ellipsis: true },
{ title: "告警值", render: renderCurrentValue },
{ title: "告警值", render: (_, record) => renderAlarmCurrentValue(record) },
{
title: "操作",
width: 100,
hidden: !props.permission("sfbjxx-info"),
render: (_, record) => (
<a
onClick={() => {
@ -76,7 +66,7 @@ function DcsList(props) {
<AlarmRecordView
open={detailOpen}
currentId={currentId}
alarmRecordInfo={props.alarmRecordInfo}
alarmRecordInfo={props.thresholdAlarmInfoInfo}
onCancel={() => {
setDetailOpen(false);
setCurrentId("");

View File

@ -1,71 +1,36 @@
import { Checkbox, Empty, message, Modal, Typography } from "antd";
import { useEffect, useMemo, useState } from "react";
import { Form, message, Modal } from "antd";
import { useState } from "react";
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 { SENSOR_ATTR_OPTIONS, SENSOR_STATUS_OPTIONS } from "~/enumerate/constant";
function BindSensorModal(props) {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState({});
const [options, setOptions] = useState([]);
const [initialSensorIds, setInitialSensorIds] = useState([]);
const [tableReady, setTableReady] = useState(false);
const [selectedSensorIds, setSelectedSensorIds] = useState([]);
const { tableProps, getData } = useTable(props.sensorDeviceList, { form });
useEffect(() => {
if (!props.open || !props.currentId) {
return;
}
const loadData = async () => {
setLoading(true);
try {
const [detailRes, deviceRes] = await Promise.all([
props.deviceRegionInfo({ id: props.currentId }),
props.sensorDeviceList({ pageIndex: 1, pageSize: 500 }),
]);
const regionDetail = detailRes?.data || {};
const deviceList = deviceRes?.data || [];
const boundIds = (regionDetail.boundSensors || []).map(item => item.id);
setDetail(regionDetail);
setInitialSensorIds(boundIds);
setSelectedSensorIds(boundIds);
setOptions(
deviceList.map(item => ({
value: item.id,
label: `${item.sensorCode} - ${item.sensorName}${item.sensorTypeName ? `${item.sensorTypeName}` : ""}`,
})),
);
}
finally {
setLoading(false);
}
};
loadData();
}, [props.currentId, props.deviceRegionInfo, props.open, props.sensorDeviceList]);
const changes = useMemo(() => {
const initialSet = new Set(initialSensorIds);
const selectedSet = new Set(selectedSensorIds);
return {
addIds: selectedSensorIds.filter(id => !initialSet.has(id)),
removeIds: initialSensorIds.filter(id => !selectedSet.has(id)),
};
}, [initialSensorIds, selectedSensorIds]);
const fireRegionName = detail.fireRegionName || props.currentRecord?.fireRegionName || "-";
const fireRegionCode = detail.fireRegionCode || props.currentRecord?.fireRegionCode || "-";
const handleReset = () => {
form.resetFields();
getData();
};
const handleSubmit = async () => {
setLoading(true);
try {
for (const sensorId of changes.addIds) {
await props.deviceRegionBindSensor({
regionConfigId: props.currentId,
sensorId,
});
const res = await props.deviceRegionBindSensor({
fireRegionId: props.currentRecord.fireRegionId,
deviceIdList: selectedSensorIds,
});
if (res.success) {
message.success("关联传感器已更新");
props.onCancel();
props.getData();
}
for (const sensorId of changes.removeIds) {
await props.deviceRegionUnbindSensor({ sensorId });
}
message.success("关联传感器已更新");
props.onCancel();
props.getData();
}
finally {
setLoading(false);
@ -79,44 +44,60 @@ function BindSensorModal(props) {
title="关联传感器"
onCancel={props.onCancel}
onOk={handleSubmit}
confirmLoading={loading || props.loading}
width={760}
afterOpenChange={open => setTableReady(open)}
confirmLoading={loading}
maskClosable={false}
width={1200}
>
<Typography.Paragraph style={{ marginBottom: 16 }}>
当前区域
{fireRegionName}
{" "}
/
{" "}
{fireRegionCode}
</Typography.Paragraph>
{options.length
? (
<Checkbox.Group
value={selectedSensorIds}
onChange={setSelectedSensorIds}
style={{ width: "100%" }}
>
<div
style={{
maxHeight: 420,
overflowY: "auto",
border: "1px solid #f0f0f0",
borderRadius: 6,
padding: 12,
}}
>
{options.map(item => (
<div key={item.value} style={{ padding: "6px 0" }}>
<Checkbox value={item.value}>{item.label}</Checkbox>
</div>
))}
</div>
</Checkbox.Group>
)
: (
<Empty description="暂无可绑定的传感器设备" />
)}
<Search
form={form}
labelCol={{ span: 8 }}
onFinish={getData}
onReset={handleReset}
options={[
{
name: "sensorName",
label: "传感器名称",
},
{
name: "sensorAttr",
label: "传感器属性",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: SENSOR_ATTR_OPTIONS,
},
]}
/>
{tableReady && (
<Table
{...tableProps}
options={false}
rowKey="sensorDeviceId"
disabledResizer={true}
scroll={{ y: 360 }}
pagination={tableProps.pagination ? { ...tableProps.pagination, showSizeChanger: true } : false}
rowSelection={{
preserveSelectedRowKeys: true,
selectedRowKeys: selectedSensorIds,
onChange: keys => 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 }) || "-",
},
]}
/>
)}
</Modal>
);
}

View File

@ -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}
>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item label="负责部门" name="departmentId">
<DepartmentSelectTree
onChange={(value) => {
setDepartmentId(value);
form.setFieldValue("managerId", undefined);
}}
/>
</Form.Item>
<Form.Item label="负责人" name="managerId">
<Form form={form} layout="horizontal" onFinish={handleSubmit} labelCol={{ span: 4 }}>
<Form.Item label="负责人" name="managerId" rules={[{ required: true, message: "请选择负责人" }]}>
<PersonnelSelect
params={{ departmentId }}
params={{ departmentId: props.currentRecord.departmentId }}
onGetLabel={label => form.setFieldValue("managerName", label)}
/>
</Form.Item>

View File

@ -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 (
<Page isShowAllAction={false}>
<Search
@ -116,55 +107,89 @@ function DeviceRegionList(props) {
width: 260,
render: (_, record) => (
<Space>
{props.permission(editPermission) && (
<Button type="link" onClick={() => handleOpenBind(record)}>
关联传感器
</Button>
)}
{props.permission(editPermission) && (
<Button type="link" onClick={() => handleOpenManager(record)}>
设置负责人
</Button>
)}
<Button
type="link"
onClick={() => {
setViewRecord(record);
setViewOpen(true);
}}
>
查看
{/* {props.permission("sbqugl-glcgq") && ( */}
<Button type="link" onClick={() => handleOpenBind(record)}>
关联传感器
</Button>
{/* )} */}
{/* {props.permission("sbqugl-szfer") && ( */}
<Button type="link" onClick={() => handleOpenManager(record)}>
设置负责人
</Button>
{/* )} */}
{
// props.permission("sbqugl-info") &&
<Button
type="link"
onClick={() => handleOpenView(record)}
>
查看
</Button>
}
</Space>
),
},
]}
{...tableProps}
dataSource={dataSource}
// dataSource={dataSource}
/>
<Modal
destroyOnClose
open={viewOpen}
title="查看"
footer={null}
maskClosable={false}
onCancel={() => {
setViewOpen(false);
setViewRecord(null);
}}
width={680}
width={1200}
>
<Divider orientation="left">区域信息</Divider>
<Descriptions bordered column={2}>
<Descriptions.Item label="消防区域">{viewRecord?.fireRegionName || "-"}</Descriptions.Item>
<Descriptions.Item label="消防区域编码">{viewRecord?.fireRegionCode || "-"}</Descriptions.Item>
<Descriptions.Item label="负责部门">{viewRecord?.departmentName || "-"}</Descriptions.Item>
<Descriptions.Item label="负责人">{viewRecord?.managerName || "-"}</Descriptions.Item>
<Descriptions.Item label="关联传感器数">{viewRecord?.bindSensorCount ?? 0}</Descriptions.Item>
</Descriptions>
<Divider orientation="left">设备信息</Divider>
<Table
options={false}
rowKey="id"
loading={viewLoading}
disabledResizer={true}
pagination={false}
dataSource={viewRecord?.boundSensors || []}
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: "sensorStatusName",
},
{
title: "是否定位",
dataIndex: "positioningFlag",
render: (_, record) => record.latitude ? "是" : "否",
},
]}
/>
</Modal>
{managerOpen && (
<ManagerModal
open={managerOpen}
currentId={currentId}
currentRecord={currentRecord}
loading={props.deviceRegionLoading}
getData={getData}
deviceRegionInfo={props.deviceRegionInfo}
@ -172,7 +197,7 @@ function DeviceRegionList(props) {
onCancel={() => {
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({});
}}
/>
)}

View File

@ -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}
>
<Form
form={form}
layout="vertical"
layout="horizontal"
onFinish={handleSubmit}
initialValues={{
sensorStatus: "NORMAL",
positioningFlag: 0,
alarmSwitch: 0,
}}
labelCol={{ span: 6 }}
>
<Form.Item
label="传感器编码"
name="sensorCode"
rules={[{ required: true, message: "请输入传感器编码" }]}
>
<Input maxLength={100} placeholder="请输入传感器编码" />
<Input maxLength={50} placeholder="请输入传感器编码" />
</Form.Item>
<Form.Item
label="传感器名称"
name="sensorName"
rules={[{ required: true, message: "请输入传感器名称" }]}
>
<Input maxLength={200} placeholder="请输入传感器名称" />
<Input maxLength={50} placeholder="请输入传感器名称" />
</Form.Item>
<Form.Item
label="传感器类型"
@ -101,56 +134,69 @@ function SensorDeviceModal(props) {
value: item.id,
label: `${item.typeName}${item.typeCode ? `${item.typeCode}` : ""}`,
}))}
onChange={(e) => {
props.sensorTypeOptions.forEach((item) => {
if (item.id === e) {
form.setFieldsValue({ sensorAttr: item.sensorAttr });
}
});
}}
/>
</Form.Item>
<Form.Item label="安装位置" name="installPosition">
<Input maxLength={255} placeholder="请输入安装位置" />
<Form.Item
label="传感器属性"
name="sensorAttr"
>
<Select
options={SENSOR_ATTR_OPTIONS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择传感器属性"
disabled
/>
</Form.Item>
<Map required={false} />
<Form.Item label="传感器状态" name="sensorStatus">
<Radio.Group>
{SENSOR_STATUS_OPTIONS.map(item => (
<Radio key={item.bianma} value={item.bianma}>
{item.name}
</Radio>
))}
</Radio.Group>
<Form.Item
label="传感器状态"
name="sensorStatus"
>
<Select
options={SENSOR_STATUS_OPTIONS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择传感器状态"
/>
</Form.Item>
<Form.Item label="是否定位" name="positioningFlag">
<Radio.Group>
{YES_NO_OPTIONS.map(item => (
<Radio key={item.bianma} value={item.bianma}>
{item.name}
</Radio>
))}
</Radio.Group>
<Form.Item
label="安装位置"
name="installPosition"
>
<Input maxLength={50} placeholder="请输入安装位置" />
</Form.Item>
<Form.Item label="报警开关" name="alarmSwitch">
<Radio.Group>
{ENABLE_STATUS_OPTIONS.map(item => (
<Radio key={item.bianma} value={item.bianma}>
{item.name}
</Radio>
))}
</Radio.Group>
<Form.Item
label="出厂日期"
name="factoryDate"
>
<DatePicker format="YYYY-MM-DD" style={{ width: "100%" }} placeholder="请选择出厂日期" />
</Form.Item>
<Form.Item label="单位" name="unitName">
<Input maxLength={50} placeholder="请输入单位" />
</Form.Item>
<Form.Item label="量程下限" name="rangeMin">
<InputNumber style={{ width: "100%" }} placeholder="请输入量程下限" />
</Form.Item>
<Form.Item label="量程上限" name="rangeMax">
<InputNumber style={{ width: "100%" }} placeholder="请输入量程上限" />
</Form.Item>
<Form.Item label="出厂日期" name="factoryDate">
<DatePicker style={{ width: "100%" }} placeholder="请选择出厂日期" />
</Form.Item>
<Form.Item label="企业侧源编码" name="enterpriseSourceCode">
<Input maxLength={100} placeholder="请输入企业侧源编码" />
</Form.Item>
<Form.Item label="备注" name="remarks">
<Input.TextArea rows={4} maxLength={255} placeholder="请输入备注" />
<Form.Item
label="是否通过系统设定报警"
name="thresholdFlag"
rules={[{ required: true, message: "请选择是否通过系统设定报警" }]}
>
<Select
options={YES_NO_OPTIONS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择是否通过系统设定报警"
disabled={!!props.currentId}
/>
</Form.Item>
</Form>
</Modal>

View File

@ -1,6 +1,7 @@
import { Button, Form, message, Modal, Space, Switch } from "antd";
import { useEffect, useState } from "react";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import MapSelector from "zy-react-library/components/Map/MapSelector";
import Page from "zy-react-library/components/Page";
import Search from "zy-react-library/components/Search";
import Table from "zy-react-library/components/Table";
@ -25,9 +26,10 @@ function SensorDeviceList(props) {
const [currentRecord, setCurrentRecord] = useState({});
const [sensorTypeOptions, setSensorTypeOptions] = useState([]);
const { tableProps, getData } = useTable(props["sensorDeviceList"], { form });
const pageType = props.type || "fgs";
const editPermission = `${pageType}-iotalarm-sensor-device-edit`;
const [visible, setVisible] = useState(false);
const [selectedLng, setSelectedLng] = useState("");
const [selectedLat, setSelectedLat] = useState("");
const [rowData, setRowData] = useState({});
const loadSensorTypeOptions = async () => {
const res = await props["sensorTypeList"]({
@ -39,10 +41,25 @@ function SensorDeviceList(props) {
setSensorTypeOptions(res.data || []);
}
};
const handleOpen = (row) => {
setSelectedLng(row.longitude);
setSelectedLat(row.latitude);
setRowData(row);
setVisible(true);
};
const handleConfirm = (lng, lat, extra) => {
rowData.latitude = lat;
rowData.longitude = lng;
console.log(rowData);
props["sensorDeviceEdit"](rowData).then((res) => {
if (res?.success) {
message.success("定位成功!");
}
});
};
useEffect(() => {
loadSensorTypeOptions();
}, [props.sensorTypeList]);
}, []);
const sensorTypeSelectOptions = sensorTypeOptions.map(item => ({
bianma: item.id,
@ -52,18 +69,23 @@ function SensorDeviceList(props) {
const handleDelete = (record) => {
Modal.confirm({
title: "确定删除这条传感器设备吗?",
maskClosable: false,
onOk: async () => {
await props["sensorDeviceRemove"]({ id: record.id });
message.success("删除成功");
getData();
const res = await props["sensorDeviceRemove"]({ id: record.id });
if (res?.success) {
message.success("删除成功");
getData();
}
},
});
};
const handleAlarmSwitch = async (record, checked) => {
await props["sensorDeviceStatus"]({ id: record.id, alarmSwitch: checked ? 1 : 0 });
message.success("报警开关更新成功");
getData();
const res = await props["sensorDeviceEdit"]({ id: record.id, alarmSwitch: checked ? 1 : 0 });
if (res?.success) {
message.success("报警开关更新成功");
getData();
}
};
return (
@ -74,10 +96,10 @@ function SensorDeviceList(props) {
options={[
{ name: "sensorName", label: "传感器名称" },
{
name: "sensorTypeId",
label: "传感器类型",
name: "thresholdFlag",
label: "是否阈值设定",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: sensorTypeSelectOptions,
items: YES_NO_OPTIONS,
},
{
name: "sensorStatus",
@ -86,10 +108,10 @@ function SensorDeviceList(props) {
items: SENSOR_STATUS_OPTIONS,
},
{
name: "thresholdFlag",
label: "是否阈值设定",
name: "sensorTypeId",
label: "传感器类型",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: YES_NO_OPTIONS,
items: sensorTypeSelectOptions,
},
]}
/>
@ -97,18 +119,18 @@ function SensorDeviceList(props) {
rowKey="id"
toolBarRender={() => (
<Space>
{props.permission(editPermission) && (
<Button
type="primary"
icon={<AddIcon />}
onClick={() => {
setCurrentId("");
setModalOpen(true);
}}
>
新增
</Button>
)}
{/* {props.permission("cgqsbgl-add") && ( */}
<Button
type="primary"
icon={<AddIcon />}
onClick={() => {
setCurrentId("");
setModalOpen(true);
}}
>
新增
</Button>
{/* )} */}
</Space>
)}
columns={[
@ -118,17 +140,17 @@ function SensorDeviceList(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: "传感器状态",
dataIndex: "sensorStatus",
render: value => getLabelName({ status: value, list: SENSOR_STATUS_OPTIONS }) || value || "-",
render: (_, record) => getLabelName({ status: record.sensorStatus, list: SENSOR_STATUS_OPTIONS }) || "-",
},
{
title: "是否定位",
dataIndex: "positioningFlag",
render: value => getLabelName({ status: value, list: YES_NO_OPTIONS }) || value || "-",
render: (_, record) => record.latitude ? "是" : "否",
},
{
title: "报警开关",
@ -138,75 +160,87 @@ function SensorDeviceList(props) {
checked={record.alarmSwitch === 1}
checkedChildren="开"
unCheckedChildren="关"
disabled={!props.permission(editPermission)}
// disabled={!props.permission(editPermission)}
onChange={checked => handleAlarmSwitch(record, checked)}
/>
),
},
{
title: "是否阈值设定",
title: "是否通过系统设定报警",
dataIndex: "thresholdFlag",
render: value => getLabelName({ status: value, list: YES_NO_OPTIONS }) || value || "-",
render: (_, record) => getLabelName({ status: record.thresholdFlag, list: YES_NO_OPTIONS }) || "-",
},
{
title: "操作",
width: 320,
render: (_, record) => (
<Space>
<Button
type="link"
onClick={() => {
setCurrentRecord(record);
setViewOpen(true);
}}
>
查看
</Button>
<Button
type="link"
onClick={() => {
setCurrentRecord(record);
setPositionOpen(true);
}}
>
定位
</Button>
<Button
type="link"
onClick={() => {
setCurrentRecord(record);
setRealtimeOpen(true);
}}
>
实时数据
</Button>
{props.permission(editPermission) && record.sensorAttr === "NUMBER" && record.thresholdFlag === 1 && (
{
// props.permission("cgqsbgl-info") &&
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setThresholdOpen(true);
setCurrentRecord(record);
setViewOpen(true);
}}
>
阈值设定
查看
</Button>
)}
{props.permission(editPermission) && (
}
{/* {props.permission("cgqsbgl-edit") && ( */}
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setModalOpen(true);
}}
>
编辑
</Button>
{/* )} */}
{/* {props.permission("cgqsbgl-del") && ( */}
<Button danger type="link" onClick={() => handleDelete(record)}>
删除
</Button>
{/* )} */}
{
// props.permission("cgqsbgl-locate") &&
<Button
type="link"
onClick={() => handleOpen(record)}
>
定位
</Button>
}
{
// props.permission("cgqsbgl-sssj") &&
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setModalOpen(true);
setCurrentRecord(record);
setRealtimeOpen(true);
}}
>
编辑
实时数据
</Button>
)}
{props.permission(editPermission) && (
<Button danger type="link" onClick={() => handleDelete(record)}>
删除
</Button>
)}
}
{/* {props.permission("cgqsbgl-yzsd") && record.sensorAttr === "NUMBER" && record.thresholdFlag === 1 && ( */}
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setCurrentRecord(record);
setThresholdOpen(true);
}}
>
阈值设定
</Button>
{/* )} */}
</Space>
),
},
@ -233,13 +267,15 @@ function SensorDeviceList(props) {
<ThresholdModal
open={thresholdOpen}
currentId={currentId}
record={currentRecord}
loading={props.sensorDeviceLoading}
getData={getData}
sensorDeviceInfo={props.sensorDeviceInfo}
sensorDeviceThreshold={props.sensorDeviceThreshold}
sensorDeviceEdit={props.sensorDeviceEdit}
onCancel={() => {
setThresholdOpen(false);
setCurrentId("");
setCurrentRecord({});
}}
/>
)}
@ -267,12 +303,27 @@ function SensorDeviceList(props) {
<RealtimeModal
open={realtimeOpen}
record={currentRecord}
sensorDeviceList={props["sensorDevicelistBySensorDevice"]}
onCancel={() => {
setRealtimeOpen(false);
setCurrentRecord({});
}}
/>
)}
{
visible
&& (
<MapSelector
visible={visible}
latitude={selectedLat}
longitude={selectedLng}
onClose={() => setVisible(false)}
onConfirm={handleConfirm}
/>
)
}
</Page>
);
}

View File

@ -1,6 +1,6 @@
import { Button, Descriptions, Modal } from "antd";
import { getLabelName } from "zy-react-library/utils";
import { ENABLE_STATUS_OPTIONS, SENSOR_ATTR_OPTIONS, SENSOR_STATUS_OPTIONS, YES_NO_OPTIONS } from "~/enumerate/constant";
import { SENSOR_ATTR_OPTIONS, SENSOR_STATUS_OPTIONS, YES_NO_OPTIONS } from "~/enumerate/constant";
function ViewModal(props) {
const record = props.record || {};
@ -13,6 +13,7 @@ function ViewModal(props) {
cancelText="关闭"
width={800}
onCancel={props.onCancel}
maskClosable={false}
footer={(
<div>
<Button onClick={props.onCancel}>关闭</Button>
@ -37,29 +38,14 @@ function ViewModal(props) {
children: getLabelName({ status: record.sensorStatus, list: SENSOR_STATUS_OPTIONS }) || record.sensorStatus || "-",
span: 2,
},
{
label: "是否定位",
children: getLabelName({ status: record.positioningFlag, list: YES_NO_OPTIONS }) || record.positioningFlag || "-",
span: 2,
},
{
label: "报警开关",
children: getLabelName({ status: record.alarmSwitch, list: ENABLE_STATUS_OPTIONS }) || record.alarmSwitch || "-",
span: 2,
},
{ label: "安装位置", children: record.installPosition || "-", span: 2 },
{ label: "出厂日期", children: record.factoryDate || "-", span: 2 },
{
label: "是否阈值设定",
children: getLabelName({ status: record.thresholdFlag, list: YES_NO_OPTIONS }) || record.thresholdFlag || "-",
span: 2,
},
{ label: "安装位置", children: record.installPosition || "-", span: 2 },
{ label: "经度", children: record.longitude || "-", span: 2 },
{ label: "纬度", children: record.latitude || "-", span: 2 },
{ label: "单位", children: record.unitName || "-", span: 2 },
{ label: "量程", children: `${record.rangeMin ?? "-"} ~ ${record.rangeMax ?? "-"}`, span: 2 },
{ label: "出厂日期", children: record.factoryDate || "-", span: 2 },
{ label: "企业侧源编码", children: record.enterpriseSourceCode || "-", span: 2 },
{ label: "备注", children: record.remarks || "-", span: 2 },
]}
/>
</Modal>

View File

@ -15,6 +15,7 @@ function PositionModal(props) {
cancelText="关闭"
width={720}
onCancel={props.onCancel}
maskClosable={false}
footer={(
<div>
<Button onClick={props.onCancel}>关闭</Button>

View File

@ -1,9 +1,117 @@
import { Descriptions, Modal } from "antd";
import { getLabelName } from "zy-react-library/utils";
import { ENABLE_STATUS_OPTIONS, SENSOR_STATUS_OPTIONS, YES_NO_OPTIONS } from "~/enumerate/constant";
import {
ReloadOutlined,
SearchOutlined,
} from "@ant-design/icons";
import { Button, DatePicker, Form, Modal, Space } from "antd";
import dayjs from "dayjs";
import * as echarts from "echarts";
import { useEffect, useRef } from "react";
import Table from "zy-react-library/components/Table";
import useTable from "zy-react-library/hooks/useTable";
const COLLECT_INTERVAL_SECONDS = 10;
const COLLECT_DURATION_SECONDS = 60 * 60;
function getMockCollectData(record) {
const now = dayjs();
const rangeMin = Number(record.rangeMin);
const rangeMax = Number(record.rangeMax);
const hasRange = Number.isFinite(rangeMin) && Number.isFinite(rangeMax) && rangeMax > rangeMin;
const base = hasRange ? (rangeMin + rangeMax) / 2 : 50;
const amplitude = hasRange ? (rangeMax - rangeMin) * 0.18 : 8;
const count = COLLECT_DURATION_SECONDS / COLLECT_INTERVAL_SECONDS;
return Array.from({ length: count + 1 }, (_, index) => {
const time = now.subtract(COLLECT_DURATION_SECONDS - index * COLLECT_INTERVAL_SECONDS, "second");
const value = record.sensorAttr === "SWITCH"
? Math.round(Math.random())
: base
+ Math.sin(index / 10) * amplitude
+ (Math.random() - 0.5) * amplitude * 0.5;
return {
time: time.format("HH:mm:ss"),
value: Number(value.toFixed(2)),
};
});
}
function RealtimeModal(props) {
const [form] = Form.useForm();
const { tableProps, getData } = useTable(props.sensorDeviceList, {
form,
usePermission: false,
transform: formData => ({
alarmTimeStart: formData.createTime?.[0]?.format("YYYY-MM-DD"),
alarmTimeEnd: formData.createTime?.[1]?.format("YYYY-MM-DD"),
sensorDeviceId: props.record.sensorDeviceId,
}),
});
const record = props.record || {};
const chartRef = useRef(null);
const handleReset = () => {
form.resetFields();
getData();
};
useEffect(() => {
if (!props.open || !chartRef.current) {
return;
}
const chart = echarts.init(chartRef.current);
const data = getMockCollectData(record);
console.log(data);
chart.setOption({
grid: {
top: 48,
right: 24,
bottom: 48,
left: 56,
},
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category",
boundaryGap: false,
data: data.map(item => item.time),
axisLabel: {
hideOverlap: true,
},
},
yAxis: {
type: "value",
// name: `采集值${unit}`,
scale: true,
},
series: [
{
name: "采集值",
type: "line",
smooth: true,
showSymbol: false,
data: data.map(item => item.value),
lineStyle: {
width: 2,
},
areaStyle: {
opacity: 0.08,
},
},
],
});
const handleResize = () => chart.resize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
chart.dispose();
};
}, [props.open, record]);
return (
<Modal
@ -11,39 +119,45 @@ function RealtimeModal(props) {
title="实时概览"
onCancel={props.onCancel}
footer={null}
width={720}
maskClosable={false}
width={1200}
>
<Descriptions
bordered
column={2}
items={[
{ label: "传感器编码", children: record.sensorCode || "-" },
{ label: "传感器名称", children: record.sensorName || "-" },
{ label: "传感器类型", children: record.sensorTypeName || "-" },
{
label: "传感器状态",
children: getLabelName({ status: record.sensorStatus, list: SENSOR_STATUS_OPTIONS }) || record.sensorStatus || "-",
},
{
label: "报警开关",
children: getLabelName({ status: record.alarmSwitch, list: ENABLE_STATUS_OPTIONS }) || record.alarmSwitch || "-",
},
{
label: "是否定位",
children: getLabelName({ status: record.positioningFlag, list: YES_NO_OPTIONS }) || record.positioningFlag || "-",
},
{ label: "经度", children: record.longitude || "-" },
{ label: "纬度", children: record.latitude || "-" },
{ label: "当前量程", children: `${record.rangeMin ?? "-"} ~ ${record.rangeMax ?? "-"}` },
{ label: "单位", children: record.unitName || "-" },
{ label: "安装位置", children: record.installPosition || "-" },
{ label: "低低报", children: record.thresholdLowLow ?? "-" },
{ label: "低报", children: record.thresholdLow ?? "-" },
{ label: "高报", children: record.thresholdHigh ?? "-" },
{ label: "高高报", children: record.thresholdHighHigh ?? "-" },
{ label: "企业侧源编码", children: record.enterpriseSourceCode || "-" },
{ label: "备注", children: record.remarks || "-" },
<div
ref={chartRef}
style={{ width: "100%", height: 320, marginBottom: 16 }}
/>
<Form form={form} layout="inline" style={{ marginBottom: 16 }}>
<Form.Item name="createTime" label="采集时间">
<DatePicker.RangePicker format="YYYY-MM-DD" />
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" icon={<SearchOutlined />} onClick={() => getData()}>
搜索
</Button>
<Button icon={<ReloadOutlined />} onClick={handleReset}>
重置
</Button>
</Space>
</Form.Item>
</Form>
<Table
options={false}
disabledResizer={true}
columns={[
{ title: "传感器名称", dataIndex: "sensorName" },
{ title: "采集时间", dataIndex: "alarmTime" },
{ title: "报警描述", dataIndex: "alarmDesc" },
{ title: "告警值", dataIndex: "currentValue" },
{ title: "计量单位", dataIndex: "unitName" },
{ title: "高高报警阈值", dataIndex: "thresholdHighHigh" },
{ title: "高报警阈值", dataIndex: "thresholdHigh" },
{ title: "低低报警阈值", dataIndex: "thresholdLowLow" },
{ title: "低报警阈值", dataIndex: "thresholdLow" },
]}
{...tableProps}
/>
</Modal>
);

View File

@ -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) {
<Modal
destroyOnClose
open={props.open}
title="阈值置"
title="阈值置"
onCancel={handleCancel}
onOk={isNumberType ? form.submit : undefined}
confirmLoading={props.loading}
width={560}
confirmLoading={props.loading || submitting || detailLoading}
loading={props.loading || detailLoading}
maskClosable={false}
width={800}
footer={isNumberType ? undefined : null}
>
{!isNumberType && sensorAttr && (
<Alert
type="warning"
message="仅数值型传感器支持阈值配置"
description="当前传感器属性为开关量,无需配置四级阈值。"
showIcon
style={{ marginBottom: 16 }}
/>
)}
{isNumberType && (
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item label="低低报阈值" name="thresholdLowLow">
<InputNumber style={{ width: "100%" }} placeholder="请输入低低报阈值" />
</Form.Item>
<Form.Item label="低报阈值" name="thresholdLow">
<InputNumber style={{ width: "100%" }} placeholder="请输入低报阈值" />
</Form.Item>
<Form.Item label="高报阈值" name="thresholdHigh">
<InputNumber style={{ width: "100%" }} placeholder="请输入高报阈值" />
</Form.Item>
<Form.Item label="高高报阈值" name="thresholdHighHigh">
<InputNumber style={{ width: "100%" }} placeholder="请输入高高报阈值" />
</Form.Item>
</Form>
)}
<Form form={form} layout="horizontal" onFinish={handleSubmit} labelCol={{ span: 6 }}>
<Form.Item label="传感器编码" name="sensorCode">
<Input maxLength={50} placeholder="请输入传感器编码" disabled />
</Form.Item>
<Form.Item label="传感器名称" name="sensorName">
<Input maxLength={50} placeholder="请输入传感器名称" disabled />
</Form.Item>
<Form.Item label="传感器类型" name="sensorTypeName">
<Input maxLength={50} placeholder="请输入传感器类型" disabled />
</Form.Item>
<Form.Item label="传感器属性" name="sensorAttr">
<Select
options={SENSOR_ATTR_OPTIONS.map(item => ({
value: item.bianma,
label: item.name,
}))}
disabled
placeholder="请选择传感器属性"
/>
</Form.Item>
<Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.sensorAttr !== nextValues.sensorAttr}>
{({ getFieldValue }) => getFieldValue("sensorAttr") === "NUMBER" && (
<>
<Form.Item
preserve={false}
label="计量单位"
name="unitName"
rules={[{ required: true, message: "请输入计量单位" }]}
>
<Input maxLength={50} placeholder="请输入计量单位" />
</Form.Item>
<Form.Item
preserve={false}
label="量程上限默认值"
name="rangeMax"
rules={[{ required: true, message: "请输入量程上限默认值" }]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入量程上限默认值" />
</Form.Item>
<Form.Item
preserve={false}
label="量程下限默认值"
name="rangeMin"
rules={[{ required: true, message: "请输入量程下限默认值" }]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入量程下限默认值" />
</Form.Item>
<Form.Item preserve={false} label="高高报警阈值默认值" name="thresholdHighHigh">
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入高高报警阈值默认值" />
</Form.Item>
<Form.Item
preserve={false}
dependencies={["thresholdHighHigh"]}
label="高报警阈值默认值"
name="thresholdHigh"
rules={[
{ required: true, message: "请输入高报警阈值默认值" },
{ validator: validateHighAlarm },
]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入高报警阈值默认值" />
</Form.Item>
<Form.Item preserve={false} label="低低报警阈值默认值" name="thresholdLowLow">
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入低低报警阈值默认值" />
</Form.Item>
<Form.Item
preserve={false}
dependencies={["thresholdLowLow"]}
label="低报警阈值默认值"
name="thresholdLow"
rules={[
{ required: true, message: "请输入低报警阈值默认值" },
{ validator: validateLowAlarm },
]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入低报警阈值默认值" />
</Form.Item>
</>
)}
</Form.Item>
</Form>
</Modal>
);
}

View File

@ -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}
>
<Form
form={form}
layout="vertical"
labelCol={{ span: 6 }}
layout="horizontal"
onFinish={handleSubmit}
loading={props.loading}
initialValues={{
sensorAttr: "NUMBER",
status: 1,
sortNo: 0,
}}
>
{/* <Form.Item */}
{/* label="类型编码" */}
{/* name="typeCode" */}
{/* rules={[{ required: true, message: "请输入类型编码" }]} */}
{/* > */}
{/* <Input maxLength={64} placeholder="请输入类型编码" /> */}
{/* </Form.Item> */}
<Form.Item
label="类型编码"
name="typeCode"
rules={[{ required: true, message: "请输入类型编码" }]}
>
<Input maxLength={64} placeholder="请输入类型编码" />
</Form.Item>
<Form.Item
label="类型名称"
label="传感器类型"
name="typeName"
rules={[{ required: true, message: "请输入类型名称" }]}
rules={[{ required: true, message: "请输入传感器类型" }]}
>
<Input maxLength={100} placeholder="请输入类型名称" />
<Input maxLength={50} placeholder="请输入传感器类型" />
</Form.Item>
<Form.Item
label="传感器属性"
name="sensorAttr"
rules={[{ required: true, message: "请选择传感器属性" }]}
>
<Radio.Group disabled={!!props.currentId}>
{SENSOR_ATTR_OPTIONS.map(item => (
<Radio key={item.bianma} value={item.bianma}>
{item.name}
</Radio>
))}
</Radio.Group>
<Select
options={SENSOR_ATTR_OPTIONS.map(item => ({
value: item.bianma,
label: item.name,
}))}
placeholder="请选择传感器属性"
/>
{/* <Radio.Group disabled={!!props.currentId}> */}
{/* {SENSOR_ATTR_OPTIONS.map(item => ( */}
{/* <Radio key={item.bianma} value={item.bianma}> */}
{/* {item.name} */}
{/* </Radio> */}
{/* ))} */}
{/* </Radio.Group> */}
</Form.Item>
<Form.Item label="排序" name="sortNo">
<InputNumber min={0} precision={0} style={{ width: "100%" }} placeholder="请输入排序" />
</Form.Item>
<Form.Item
label="状态"
name="status"
rules={[{ required: true, message: "请选择状态" }]}
>
<Radio.Group>
{ENABLE_STATUS_OPTIONS.map(item => (
<Radio key={item.bianma} value={item.bianma}>
{item.name}
</Radio>
))}
</Radio.Group>
</Form.Item>
<Form.Item label="备注" name="remarks">
<Input.TextArea rows={4} maxLength={255} placeholder="请输入备注" />
<Form.Item noStyle shouldUpdate={(prevValues, nextValues) => prevValues.sensorAttr !== nextValues.sensorAttr}>
{({ getFieldValue }) => getFieldValue("sensorAttr") === "NUMBER" && (
<>
<Form.Item
preserve={false}
label="计量单位"
name="unitName"
rules={[{ required: true, message: "请输入计量单位" }]}
>
<Input maxLength={50} placeholder="请输入计量单位" />
</Form.Item>
<Form.Item preserve={false} label="量程上限默认值" name="rangeMax" rules={[{ required: true, message: "请输入量程上限默认值" }]}>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入量程上限默认值" />
</Form.Item>
<Form.Item preserve={false} label="量程下限默认值" name="rangeMin" rules={[{ required: true, message: "请输入量程下限默认值" }]}>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入量程下限默认值" />
</Form.Item>
<Form.Item preserve={false} label="高高报警阈值默认值" name="thresholdHighHigh">
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="高高报警阈值默认值" />
</Form.Item>
<Form.Item
preserve={false}
dependencies={["thresholdHighHigh"]}
label="高报警阈值默认值"
name="thresholdHigh"
rules={[
{ required: true, message: "请输入高报警阈值默认值" },
{ validator: validateHighAlarm },
]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入高报警阈值默认值" />
</Form.Item>
<Form.Item preserve={false} label="低低报警阈值默认值" name="thresholdLowLow">
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入低低报警阈值默认值" />
</Form.Item>
<Form.Item
preserve={false}
dependencies={["thresholdLowLow"]}
label="低报警阈值默认值"
name="thresholdLow"
rules={[
{ required: true, message: "请输入低报警阈值默认值" },
{ validator: validateLowAlarm },
]}
>
<InputNumber min={0} precision={2} style={{ width: "100%" }} placeholder="请输入低报警阈值默认值" />
</Form.Item>
</>
)}
</Form.Item>
</Form>
</Modal>

View File

@ -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={() => (
<Space>
{props.permission(editPermission) && (
<Button
type="primary"
icon={<AddIcon />}
onClick={() => {
setCurrentId("");
setModalOpen(true);
}}
>
新增
</Button>
)}
{/* {props.permission("cgqbj-add") && ( */}
<Button
type="primary"
icon={<AddIcon />}
onClick={() => {
setCurrentId("");
setModalOpen(true);
}}
>
新增
</Button>
{/* )} */}
</Space>
)}
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) => (
<Space>
{/* { */}
{/* props.permission("cgqbj-info") && ( */}
<Button
type="link"
onClick={() => {
@ -80,22 +83,24 @@ function SensorTypeList(props) {
>
查看
</Button>
{props.permission(editPermission) && (
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setModalOpen(true);
}}
>
编辑
</Button>
)}
{props.permission(editPermission) && (
<Button danger type="link" onClick={() => handleDelete(record)}>
删除
</Button>
)}
)
{/* } */}
{/* {props.permission("cgqbj-edit") && ( */}
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setModalOpen(true);
}}
>
编辑
</Button>
{/* )} */}
{/* {props.permission("cgqbj-del") && ( */}
<Button danger type="link" onClick={() => handleDelete(record)}>
删除
</Button>
{/* )} */}
</Space>
),
},

View File

@ -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 (
<Modal
@ -13,6 +33,7 @@ function ViewModal(props) {
cancelText="关闭"
width={640}
onCancel={props.onCancel}
maskClosable={false}
footer={(
<div>
<Button onClick={props.onCancel}>关闭</Button>
@ -22,14 +43,8 @@ function ViewModal(props) {
<Descriptions
bordered
column={1}
labelStyle={{ width: 160 }}
items={[
{ label: "传感器类型", children: record.typeName || "-" },
{
label: "传感器属性",
children: getLabelName({ status: record.sensorAttr, list: SENSOR_ATTR_OPTIONS }) || record.sensorAttr || "-",
},
]}
labelStyle={{ width: 200 }}
items={items}
/>
</Modal>
);

View File

@ -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 (
<Page isShowAllAction={false}>
<Search
form={form}
onFinish={handleSearch}
onFinish={getData}
options={[
{ name: "sensorName", label: "传感器名称" },
{
@ -54,10 +43,11 @@ function ThresholdList(props) {
{ title: "传感器名称", dataIndex: "sensorName" },
{ title: "报警时间", dataIndex: "alarmTime" },
{ title: "报警描述", dataIndex: "alarmDesc", ellipsis: true },
{ title: "告警值", render: renderCurrentValue },
{ title: "告警值", render: (_, record) => renderAlarmCurrentValue(record) },
{
title: "操作",
width: 100,
hidden: !props.permission("yzbjxx-info"),
render: (_, record) => (
<a
onClick={() => {
@ -76,7 +66,7 @@ function ThresholdList(props) {
<AlarmRecordView
open={detailOpen}
currentId={currentId}
alarmRecordInfo={props.alarmRecordInfo}
alarmRecordInfo={props.thresholdAlarmInfoInfo}
onCancel={() => {
setDetailOpen(false);
setCurrentId("");

View File

@ -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: "处置" },
];

View File

@ -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";

View File

@ -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 (
<ConfigProvider
prefixCls={ANT_PREFIX}
theme={{
token: this.token,
algorithm: this.algorithm,

36
src/utils/alarm.js Normal file
View File

@ -0,0 +1,36 @@
export function renderAlarmCurrentValue(record) {
if (!record || record.currentValue == null || record.currentValue === "") {
return "-";
}
if (record.sensorAttr !== "NUMBER") {
return Number(record.currentValue) === 1 ? "开" : "关";
}
const currentValue = Number(record.currentValue);
const thresholdHighHigh = Number(record.thresholdHighHigh);
const thresholdHigh = Number(record.thresholdHigh);
const thresholdLowLow = Number(record.thresholdLowLow);
const thresholdLow = Number(record.thresholdLow);
let suffix = "";
let color = "";
if (
(Number.isFinite(thresholdHighHigh) && currentValue > 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 ? <span style={{ color }}>{content}</span> : content;
}