safety-eval-service-frontend/src/pages/Container/EnterpriseInfo/EquipInfo/index.js

550 lines
16 KiB
JavaScript
Raw Normal View History

2026-07-06 18:06:49 +08:00
import React, { useEffect, useState } from "react";
2026-07-07 10:49:43 +08:00
import {
Button,
Descriptions,
Form,
Input,
InputNumber,
message,
Modal,
Row,
Col,
Table,
Tag,
Select,
Space,
} from "antd";
import { PlusOutlined } from "@ant-design/icons";
2026-06-29 16:45:58 +08:00
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
2026-07-06 18:06:49 +08:00
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import { tools } from "@cqsjjb/jjb-common-lib";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
2026-06-23 18:07:30 +08:00
import { NS_EQUIP_INFO } from "~/enumerate/namespace";
import { positiveNumberRule } from "~/utils/validators";
2026-07-09 17:12:54 +08:00
import { toEquipPageQuery } from "../equipPageQuery";
2026-06-23 18:07:30 +08:00
2026-07-06 18:06:49 +08:00
const { router } = tools;
2026-07-07 13:54:55 +08:00
const DUAL_CHANNEL_MAP = { 1: "是", 2: "否" };
2026-06-23 18:07:30 +08:00
function EquipInfoPage(props) {
const [formModalOpen, setFormModalOpen] = useState(false);
const [viewModalOpen, setViewModalOpen] = useState(false);
const [currentId, setCurrentId] = useState("");
const [searchForm] = Form.useForm();
2026-07-06 18:06:49 +08:00
const { equipInfo } = props;
2026-07-07 10:49:43 +08:00
const {
equipInfoList: dataSource,
equipInfoTotal: total,
equipInfoLoading: loading,
} = equipInfo || {};
2026-06-23 18:07:30 +08:00
2026-07-06 18:06:49 +08:00
const handleSearch = () => {
2026-07-09 17:12:54 +08:00
props.equipInfoList(toEquipPageQuery(router.query));
2026-07-06 18:06:49 +08:00
};
2026-06-23 18:07:30 +08:00
useEffect(() => {
2026-07-06 18:06:49 +08:00
searchForm.setFieldsValue(router.query);
handleSearch();
2026-06-23 18:07:30 +08:00
}, []);
const onDelete = (id) => {
Modal.confirm({
title: "提示",
content: "数据将会删除,您是否确认删除?",
okText: "是",
cancelText: "否",
onOk: async () => {
2026-07-07 13:54:55 +08:00
const res = await props.equipInfoRemove({ data: id });
2026-06-23 18:07:30 +08:00
if (res?.success !== false) {
message.success("删除成功");
2026-07-06 18:06:49 +08:00
handleSearch();
2026-06-23 18:07:30 +08:00
}
},
});
};
2026-06-26 14:27:49 +08:00
const onToggleStatus = (id, record) => {
2026-07-06 18:06:49 +08:00
const enabled = record.enableFlag === 1;
2026-06-23 18:07:30 +08:00
Modal.confirm({
title: "提示",
2026-06-26 14:27:49 +08:00
content: enabled ? "是否停用" : "是否启用",
2026-06-23 18:07:30 +08:00
okText: "是",
cancelText: "否",
onOk: async () => {
2026-07-06 18:06:49 +08:00
const nextFlag = enabled ? 2 : 1;
2026-07-07 10:49:43 +08:00
const res = await props.equipInfoToggleStatus({
2026-07-07 17:13:33 +08:00
...record,
2026-07-07 10:49:43 +08:00
id,
enableFlag: nextFlag,
});
2026-06-23 18:07:30 +08:00
if (res?.success !== false) {
message.success("操作成功");
2026-07-06 18:06:49 +08:00
handleSearch();
} else {
2026-07-08 20:55:23 +08:00
2026-06-23 18:07:30 +08:00
}
},
});
};
return (
2026-07-07 10:49:43 +08:00
<PageLayout
title="装备信息管理"
extra={
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => {
setCurrentId("");
setFormModalOpen(true);
}}
>
新增装备
</Button>
}
>
2026-07-06 18:06:49 +08:00
<SearchForm
style={{ marginBottom: 24 }}
2026-06-23 18:07:30 +08:00
form={searchForm}
2026-07-06 18:06:49 +08:00
loading={loading}
formLine={[
2026-07-07 13:54:55 +08:00
<Form.Item key="likeDeviceName" name="deviceName">
2026-07-07 10:49:43 +08:00
<ControlWrapper.Input
label="设备名称"
placeholder="请输入"
allowClear
/>
2026-07-06 18:06:49 +08:00
</Form.Item>,
2026-07-07 17:13:33 +08:00
<Form.Item key="instrumentType" name="instrumentType">
2026-07-07 11:18:00 +08:00
<ControlWrapper.Select
2026-07-07 10:49:43 +08:00
label="仪器类型"
2026-07-07 11:18:00 +08:00
placeholder="请选择"
2026-07-07 10:49:43 +08:00
allowClear
2026-07-07 11:18:00 +08:00
style={{ width: "100%" }}
>
<Select.Option value="分析仪器">分析仪器</Select.Option>
<Select.Option value="检测仪器">检测仪器</Select.Option>
<Select.Option value="采样设备">采样设备</Select.Option>
<Select.Option value="物理仪器">物理仪器</Select.Option>
</ControlWrapper.Select>
2026-07-06 18:06:49 +08:00
</Form.Item>,
2026-07-07 17:13:33 +08:00
<Form.Item key="deviceType" name="deviceType">
2026-07-07 11:18:00 +08:00
<ControlWrapper.Select
2026-07-07 10:49:43 +08:00
label="设备类型"
2026-07-07 11:18:00 +08:00
placeholder="请选择"
2026-07-07 10:49:43 +08:00
allowClear
2026-07-07 11:18:00 +08:00
style={{ width: "100%" }}
>
<Select.Option value="固定式">固定式</Select.Option>
<Select.Option value="便携式">便携式</Select.Option>
</ControlWrapper.Select>
2026-07-06 18:06:49 +08:00
</Form.Item>,
2026-06-23 18:07:30 +08:00
]}
2026-07-07 11:30:42 +08:00
onReset={(value) => {
router.query = { ...value, current: 1, size: 10 };
2026-07-06 18:06:49 +08:00
handleSearch();
}}
2026-07-07 11:30:42 +08:00
onFinish={(value) => {
router.query = { ...value, current: 1, size: 10 };
2026-07-06 18:06:49 +08:00
handleSearch();
}}
2026-06-23 18:07:30 +08:00
/>
<Table
2026-07-06 18:06:49 +08:00
rowKey="id"
2026-06-23 18:07:30 +08:00
columns={[
2026-07-07 10:49:43 +08:00
{
title: "设备名称",
dataIndex: "deviceName",
width: 200,
ellipsis: true,
},
2026-07-06 18:06:49 +08:00
{ title: "设备型号", dataIndex: "deviceModel" },
2026-07-07 11:18:00 +08:00
{ title: "仪器类型", dataIndex: "instrumentTypeName" },
2026-07-07 11:30:42 +08:00
{ title: "设备类型", dataIndex: "deviceTypeName" },
2026-07-07 10:49:43 +08:00
{
title: "厂家",
dataIndex: "manufacturer",
ellipsis: true,
width: 180,
},
2026-06-23 18:07:30 +08:00
{ title: "校准单位", dataIndex: "calibrationUnit" },
2026-07-07 10:49:43 +08:00
{ title: "校准初值", dataIndex: "calibrationInitValue", width: 100 },
2026-06-23 18:07:30 +08:00
{
title: "设备状态",
2026-06-26 14:27:49 +08:00
width: 90,
2026-07-06 18:06:49 +08:00
render: (_, record) => {
const enabled = record.enableFlag === 1;
2026-07-07 10:49:43 +08:00
return (
<Tag color={enabled ? "green" : "red"}>
{enabled ? "启用" : "禁用"}
</Tag>
);
2026-07-06 18:06:49 +08:00
},
2026-06-23 18:07:30 +08:00
},
{
title: "操作",
2026-07-06 18:06:49 +08:00
width: 180,
2026-07-07 11:39:02 +08:00
fixed: "right",
2026-06-23 18:07:30 +08:00
render: (_, record) => (
2026-07-06 18:06:49 +08:00
<TableAction>
2026-07-07 10:49:43 +08:00
<Button
type="link"
size="small"
onClick={() => {
setCurrentId(record.id);
setViewModalOpen(true);
}}
>
2026-06-23 18:07:30 +08:00
查看
</Button>
2026-07-07 10:49:43 +08:00
<Button
type="link"
size="small"
onClick={() => {
setCurrentId(record.id);
setFormModalOpen(true);
}}
>
2026-06-23 18:07:30 +08:00
编辑
</Button>
2026-07-07 10:49:43 +08:00
<Button
type="link"
size="small"
onClick={() => onToggleStatus(record.id, record)}
>
2026-07-06 18:06:49 +08:00
{record.enableFlag === 1 ? "禁用" : "启用"}
2026-06-23 18:07:30 +08:00
</Button>
2026-07-07 10:49:43 +08:00
<Button
danger
type="link"
size="small"
onClick={() => onDelete(record.id)}
>
删除
</Button>
2026-07-06 18:06:49 +08:00
</TableAction>
2026-06-23 18:07:30 +08:00
),
},
]}
2026-07-06 18:06:49 +08:00
dataSource={dataSource}
2026-07-07 11:39:02 +08:00
scroll={{ y: props.scrollY, x: 1600 }}
2026-07-06 18:06:49 +08:00
loading={loading}
pagination={{
total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (t) => `${t}`,
current: router.query.current || 1,
pageSize: router.query.size || 10,
onChange: (page, pageSize) => {
router.query = { ...router.query, current: page, size: pageSize };
handleSearch();
},
}}
2026-06-23 18:07:30 +08:00
/>
{formModalOpen && (
<EquipFormModal
open={formModalOpen}
currentId={currentId}
2026-07-06 18:06:49 +08:00
equipInfoGet={props.equipInfoGet}
equipInfoAdd={props.equipInfoAdd}
equipInfoEdit={props.equipInfoEdit}
2026-06-23 18:07:30 +08:00
onCancel={() => {
setFormModalOpen(false);
setCurrentId("");
}}
2026-07-06 18:06:49 +08:00
onSuccess={handleSearch}
2026-06-23 18:07:30 +08:00
/>
)}
{viewModalOpen && (
<EquipViewModal
open={viewModalOpen}
currentId={currentId}
2026-07-06 18:06:49 +08:00
equipInfoGet={props.equipInfoGet}
2026-06-23 18:07:30 +08:00
onCancel={() => {
setViewModalOpen(false);
setCurrentId("");
}}
/>
)}
2026-06-29 16:45:58 +08:00
</PageLayout>
2026-06-23 18:07:30 +08:00
);
}
function EquipFormModal({
2026-07-07 10:49:43 +08:00
open,
currentId,
equipInfoGet,
equipInfoAdd,
equipInfoEdit,
onCancel,
onSuccess,
2026-06-23 18:07:30 +08:00
}) {
const [form] = Form.useForm();
const [submitting, setSubmitting] = useState(false);
const [detailLoading, setDetailLoading] = useState(false);
useEffect(() => {
2026-07-06 18:06:49 +08:00
if (!open) return;
2026-06-23 18:07:30 +08:00
if (!currentId) {
form.resetFields();
return;
}
let cancelled = false;
setDetailLoading(true);
2026-07-07 10:49:43 +08:00
equipInfoGet({ id: currentId })
.then((res) => {
if (cancelled) return;
const data = res?.data || {};
form.setFieldsValue(data);
})
.finally(() => {
if (!cancelled) setDetailLoading(false);
});
return () => {
cancelled = true;
};
2026-06-23 18:07:30 +08:00
}, [open, currentId]);
const handleCancel = () => {
form.resetFields();
onCancel();
};
const handleSubmit = async (values) => {
try {
setSubmitting(true);
2026-07-06 18:06:49 +08:00
if (currentId) values.id = currentId;
2026-07-07 10:49:43 +08:00
const res = await (currentId
? equipInfoEdit(values)
: equipInfoAdd(values));
2026-06-23 18:07:30 +08:00
if (res?.success !== false) {
message.success(currentId ? "编辑成功" : "添加成功");
handleCancel();
onSuccess();
2026-07-06 18:06:49 +08:00
} else {
2026-07-08 20:55:23 +08:00
2026-06-23 18:07:30 +08:00
}
2026-07-06 18:06:49 +08:00
} finally {
2026-06-23 18:07:30 +08:00
setSubmitting(false);
}
};
return (
<Modal
open={open}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-23 18:07:30 +08:00
title={currentId ? "编辑设备" : "添加设备"}
width={900}
loading={detailLoading}
confirmLoading={submitting}
onCancel={handleCancel}
onOk={form.submit}
>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Row gutter={16}>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="deviceName"
label="设备名称"
rules={[{ required: true, message: "请输入设备名称" }]}
>
2026-07-06 18:06:49 +08:00
<Input placeholder="请输入设备名称" />
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="deviceModel"
label="型号"
rules={[{ required: true, message: "请输入型号" }]}
>
2026-07-06 18:06:49 +08:00
<Input placeholder="请输入型号" />
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
2026-07-07 11:18:00 +08:00
name="instrumentTypeName"
2026-07-07 10:49:43 +08:00
label="仪器分类"
rules={[{ required: true, message: "请选择仪器分类" }]}
>
2026-07-07 11:18:00 +08:00
<Select placeholder="请选择仪器分类">
<Select.Option value="分析仪器">分析仪器</Select.Option>
<Select.Option value="检测仪器">检测仪器</Select.Option>
<Select.Option value="采样设备">采样设备</Select.Option>
<Select.Option value="物理仪器">物理仪器</Select.Option>
</Select>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
2026-07-07 11:30:42 +08:00
name="deviceTypeName"
2026-07-07 10:49:43 +08:00
label="设备类型"
rules={[{ required: true, message: "请选择设备类型" }]}
>
2026-07-07 11:18:00 +08:00
<Select placeholder="请选择设备类型">
<Select.Option value="固定式">固定式</Select.Option>
<Select.Option value="便携式">便携式</Select.Option>
</Select>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="manufacturer"
label="厂家"
rules={[{ required: true, message: "请输入厂家" }]}
>
2026-07-06 18:06:49 +08:00
<Input placeholder="请输入厂家" />
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-06 18:06:49 +08:00
<Form.Item name="flowDesc" label="设备流量说明">
<Input placeholder="请输入设备流量说明" />
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="minFlow"
label="最小流量"
rules={[positiveNumberRule("最小流量", false)]}
>
<InputNumber
style={{ width: "100%" }}
placeholder="请输入最小流量"
/>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="maxFlow"
label="最大流量"
rules={[positiveNumberRule("最大流量", false)]}
>
<InputNumber
style={{ width: "100%" }}
placeholder="请输入最大流量"
/>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="calibrationUnit" label="校准单位">
<Input placeholder="请输入校准单位" />
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 10:49:43 +08:00
<Form.Item
name="calibrationInitValue"
label="校准初始值"
rules={[positiveNumberRule("校准初始值", false)]}
>
<InputNumber
style={{ width: "100%" }}
placeholder="请输入校准初始值"
/>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-07 11:18:00 +08:00
<Form.Item name="fieldCalibrationTypeName" label="现场校验类型">
<Select placeholder="请选择现场校验类型" allowClear>
<Select.Option value="现场校验">现场校验</Select.Option>
<Select.Option value="实验室校验">实验室校验</Select.Option>
<Select.Option value="免校验">免校验</Select.Option>
</Select>
2026-06-23 18:07:30 +08:00
</Form.Item>
</Col>
<Col span={12}>
2026-07-06 18:06:49 +08:00
<Form.Item name="dualChannelFlag" label="是否双路">
2026-06-23 18:07:30 +08:00
<Select
allowClear
placeholder="请选择"
2026-07-07 10:49:43 +08:00
options={[
{ label: "是", value: 1 },
2026-07-07 13:54:55 +08:00
{ label: "否", value: 2 },
2026-07-07 10:49:43 +08:00
]}
2026-06-23 18:07:30 +08:00
/>
</Form.Item>
</Col>
</Row>
</Form>
</Modal>
);
}
2026-07-06 18:06:49 +08:00
function EquipViewModal({ open, currentId, equipInfoGet, onCancel }) {
2026-06-23 18:07:30 +08:00
const [info, setInfo] = useState({});
const [detailLoading, setDetailLoading] = useState(false);
useEffect(() => {
if (!open || !currentId) {
setInfo({});
return;
}
let cancelled = false;
setDetailLoading(true);
2026-07-07 10:49:43 +08:00
equipInfoGet({ id: currentId })
.then((res) => {
if (!cancelled) setInfo(res?.data || {});
})
.finally(() => {
if (!cancelled) setDetailLoading(false);
});
return () => {
cancelled = true;
};
2026-06-23 18:07:30 +08:00
}, [open, currentId]);
return (
<Modal
open={open}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-23 18:07:30 +08:00
title="查看设备"
width={900}
loading={detailLoading}
cancelText="返回"
okButtonProps={{ style: { display: "none" } }}
onCancel={onCancel}
>
<Descriptions bordered column={2} labelStyle={{ width: 120 }}>
2026-07-07 10:49:43 +08:00
<Descriptions.Item label="设备名称">
{info.deviceName}
</Descriptions.Item>
<Descriptions.Item label="设备型号">
{info.deviceModel}
</Descriptions.Item>
<Descriptions.Item label="仪器分类">
2026-07-07 11:18:00 +08:00
{info.instrumentTypeName}
2026-07-07 10:49:43 +08:00
</Descriptions.Item>
<Descriptions.Item label="设备类型">
2026-07-07 11:30:42 +08:00
{info.deviceTypeName}
2026-07-07 10:49:43 +08:00
</Descriptions.Item>
2026-06-23 18:07:30 +08:00
<Descriptions.Item label="厂家">{info.manufacturer}</Descriptions.Item>
2026-07-07 10:49:43 +08:00
<Descriptions.Item label="设备流量说明" span={2}>
{info.flowDesc}
</Descriptions.Item>
2026-06-23 18:07:30 +08:00
<Descriptions.Item label="最小流量">{info.minFlow}</Descriptions.Item>
<Descriptions.Item label="最大流量">{info.maxFlow}</Descriptions.Item>
2026-07-07 10:49:43 +08:00
<Descriptions.Item label="校准单位">
{info.calibrationUnit}
</Descriptions.Item>
<Descriptions.Item label="校准初始值">
{info.calibrationInitValue}
</Descriptions.Item>
<Descriptions.Item label="现场校验类型">
2026-07-07 11:18:00 +08:00
{info.fieldCalibrationTypeName}
2026-07-07 10:49:43 +08:00
</Descriptions.Item>
<Descriptions.Item label="是否双路">
{DUAL_CHANNEL_MAP[info.dualChannelFlag] ?? "-"}
</Descriptions.Item>
2026-06-23 18:07:30 +08:00
</Descriptions>
</Modal>
);
}
2026-07-07 10:49:43 +08:00
export default Connect(
[NS_EQUIP_INFO],
true,
)(AntdTableFuncControl(EquipInfoPage));