1、消防资源整体功能

master
shenzhidan 2026-02-06 17:28:19 +08:00
parent 18d8e7108e
commit 1bffcfe8e8
14 changed files with 843 additions and 707 deletions

View File

@ -11,6 +11,9 @@ require("zy-react-library/css/common.less");
dayjs.locale("zh-cn");
setJJBCommonAntdMessage(message);
window.mapLongitude = "119.69457721306945";
window.mapLatitude = "39.940504336846665";
const app = setup();
// 非底座环境运行

View File

@ -1,7 +1,8 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Card, Col, Form, Input, InputNumber, message, Row, Space, Table } from "antd";
import { useEffect, useState } from "react";
import MapSelector from "zy-react-library/components/Map/MapSelector";
import Page from "zy-react-library/components/Page";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import Upload from "zy-react-library/components/Upload";
@ -17,6 +18,9 @@ function Add(props) {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
// 设备信息列表
const [deviceList, setDeviceList] = useState([]);
@ -36,10 +40,10 @@ function Add(props) {
try {
const { data } = await props["controlRoomDetail"]({ id: query.id });
// 如果有业务ID查询图片文件
// 如果有业务ID查询图片文件
if (data.roomId) {
const files = await getFile({
eqType: UPLOAD_FILE_TYPE_ENUM[302], // 消防点检检查合格图片
eqType: UPLOAD_FILE_TYPE_ENUM[302],
eqForeignKey: data.roomId,
});
data.roomImages = files;
@ -70,6 +74,17 @@ function Add(props) {
query.id && getData();
}, []);
const openMap = () => {
setMapLng(form.getFieldValue("lng") || "");
setMapLat(form.getFieldValue("lat") || "");
setMapOpen(true);
};
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
setMapOpen(false);
};
const onFinish = async (values) => {
// 验证设备列表
if (deviceList.length === 0) {
@ -109,18 +124,18 @@ function Add(props) {
setSubmitting(true);
try {
// 先删除标记删除的文件
// 先删除标记删除的文件
if (deleteFiles.length > 0) {
await deleteFile({ single: false, files: deleteFiles });
}
// 上传图片文件获取业务IDroom_id
// 上传图片文件获取业务IDroom_id
const { id: roomId } = await uploadFile({
single: false,
files: values.roomImages,
params: {
type: UPLOAD_FILE_TYPE_ENUM[302], // ⭐ 消防点检检查合格图片
foreignKey: values.roomId, // 编辑时传入已有的 roomId
type: UPLOAD_FILE_TYPE_ENUM[302],
foreignKey: values.roomId,
},
});
@ -129,7 +144,7 @@ function Add(props) {
// 构建提交参数
const params = {
...values,
roomId, // ⭐ 使用上传返回的业务ID
roomId,
// 设备列表:去掉前端添加的 key
devices: deviceList.map(({ key, ...device }) => ({
deviceName: device.deviceName,
@ -213,7 +228,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
设备名称
</>),
</>),
dataIndex: "deviceName",
render: (text, record) => (
<Input
@ -227,7 +242,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
设备型号
</>),
</>),
dataIndex: "deviceModel",
render: (text, record) => (
<Input
@ -241,7 +256,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
设备数量
</>),
</>),
dataIndex: "deviceQty",
render: (text, record) => (
<InputNumber
@ -257,7 +272,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
设备位置
</>),
</>),
dataIndex: "deviceLocation",
render: (text, record) => (
<Input
@ -285,7 +300,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
人员姓名
</>),
</>),
dataIndex: "personName",
render: (text, record) => (
<Input
@ -299,7 +314,7 @@ function Add(props) {
title: (<>
<span style={{ color: "red" }}>*</span>
人员手机号
</>),
</>),
dataIndex: "personPhone",
render: (text, record) => (
<Input
@ -342,9 +357,9 @@ function Add(props) {
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, marginTop: 24 }}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
{/* 添加隐藏字段保存 roomId */}
@ -357,8 +372,6 @@ function Add(props) {
<Form.Item
label="消防控制室名称"
name="roomName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入消防控制室名称" },
{ max: 100, message: "消防控制室名称不能超过100个字符" },
@ -372,8 +385,6 @@ function Add(props) {
<Form.Item
label="消防控制室状态"
name="roomStatus"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请选择消防控制室状态" }]}
>
<DictionarySelect
@ -389,8 +400,6 @@ function Add(props) {
<Form.Item
label="负责人"
name="principalName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入负责人" },
{ max: 50, message: "负责人不能超过50个字符" },
@ -404,8 +413,6 @@ function Add(props) {
<Form.Item
label="负责人手机号"
name="principalPhone"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入负责人手机号" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
@ -421,37 +428,29 @@ function Add(props) {
<Form.Item
label="经度"
name="lng"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入经度" }]}
rules={[{ required: true, message: "请选择经度" }]}
>
<InputNumber
placeholder="请输入经度"
style={{ width: "100%" }}
min={-180}
max={180}
step={0.000001}
precision={6}
/>
<Input placeholder="请点击地图定位按钮选择" disabled />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="纬度"
name="lat"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入纬度" }]}
required
>
<InputNumber
placeholder="请输入纬度"
style={{ width: "100%" }}
min={-90}
max={90}
step={0.000001}
precision={6}
/>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
</Form.Item>
</Col>
</Row>
@ -461,10 +460,10 @@ function Add(props) {
<Form.Item
label="消防控制室图片"
name="roomImages"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防控制室图片" }]}
extra="默认上传4个目前支持jpg、jpeg、png格式单张图片不超过5mb"
extra="默认上传4个,目前支持jpg、jpeg、png格式,单张图片不超过5mb"
>
<Upload
fileType="image"
@ -494,7 +493,7 @@ function Add(props) {
dataSource={deviceList}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无设备信息请点击新增按钮添加" }}
locale={{ emptyText: "暂无设备信息,请点击新增按钮添加" }}
/>
</Card>
@ -512,7 +511,7 @@ function Add(props) {
dataSource={personnelList}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无人员信息请点击新增按钮添加" }}
locale={{ emptyText: "暂无人员信息,请点击新增按钮添加" }}
/>
</Card>
@ -527,6 +526,14 @@ function Add(props) {
</Space>
</Form.Item>
</Form>
<MapSelector
visible={mapOpen}
onClose={() => setMapOpen(false)}
longitude={mapLng}
latitude={mapLat}
onConfirm={handleMapConfirm}
/>
</Page>
);
}

View File

@ -19,25 +19,14 @@ function List(props) {
const [deleting, setDeleting] = useState(false);
const [statusDict, setStatusDict] = useState([]);
const [initialized, setInitialized] = useState(false);
const { getDictionary } = useDictionary();
// 一次性初始化字典和表单
useEffect(() => {
if (props.location?.state?.refresh) {
getData();
props.history.replace({ ...props.location, state: {} });
}
}, [props.location?.state?.refresh]);
useEffect(() => {
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
}
}, [query.eqCorpId]);
useEffect(() => {
const fetchDict = async () => {
const init = async () => {
// 加载字典
try {
const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" });
setStatusDict(Array.isArray(dict) ? dict : []);
@ -45,13 +34,35 @@ function List(props) {
catch (error) {
setStatusDict([]);
}
// 设置表单初始值并加载数据
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
}
getData();
setInitialized(true);
};
fetchDict();
if (!initialized) {
init();
}
}, []);
// 监听 eqCorpId 变化
useEffect(() => {
if (initialized && query.eqCorpId) {
const currentCorpId = form.getFieldValue("eqCorpId");
if (currentCorpId !== query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
}
}
}, [query.eqCorpId, initialized]);
const getStatusLabel = (record) => {
if (record.roomStatusName)
return record.roomStatusName;
if (!record) return "-";
if (record.roomStatusName) return record.roomStatusName;
const match = statusDict.find(item => item.dictValue === record.roomStatus);
return match?.dictLabel || record.roomStatus || "-";
};
@ -71,9 +82,12 @@ function List(props) {
setDeleting(true);
try {
await props["controlRoomDelete"]({ id: String(id) });
message.success("删除");
message.success("删除成功");
getData();
}
catch (error) {
message.error("删除失败");
}
finally {
setDeleting(false);
}
@ -85,29 +99,29 @@ function List(props) {
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{
name: "likeRoomName",
label: "消防控制室名称:",
span: 4,
formItemProps: { style: { marginRight: 16 } },
label: "消防控制室名称",
},
{
name: "eqRoomStatus",
label: "消防控制室状态",
label: "消防控制室状态",
render: (<DictionarySelect dictValue="fire_resource_contro_root_type" />),
span: 4,
formItemProps: { style: { marginLeft: 16 } },
},
{ name: "eqCorpId", onlyForLabel: true },
{
name: "eqCorpId",
onlyForLabel: true,
},
]}
form={form}
onFinish={getData}
/>
<Table
toolBarRender={() => (
<Space>
{/* {props.permission("xfkzs-btn-add") && ( */}
<Button
type="primary"
onClick={() => {
@ -116,53 +130,77 @@ function List(props) {
>
新增
</Button>
{/* )} */}
</Space>
)}
columns={[
// { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "消防控制室名称", dataIndex: "roomName", ellipsis: true, width: 140 },
{
title: "消防控制室名称",
dataIndex: "roomName",
width: 200,
ellipsis: true,
},
{
title: "消防控制室状态",
width: 140,
width: 150,
align: "center",
ellipsis: true,
render: (_, record) => getStatusLabel(record),
},
{ title: "负责人", dataIndex: "principalName", width: 120, align: "center" },
{ title: "负责人手机号", dataIndex: "principalPhone", width: 140, align: "center" },
{ title: "设备数", dataIndex: "deviceCount", width: 100, align: "center" },
{ title: "人员数", dataIndex: "personCount", width: 100, align: "center" },
{
title: "负责人",
dataIndex: "principalName",
width: 120,
align: "center",
ellipsis: true,
},
{
title: "负责人手机号",
dataIndex: "principalPhone",
width: 150,
align: "center",
ellipsis: true,
},
{
title: "设备数",
dataIndex: "deviceCount",
width: 100,
align: "center",
render: text => text || 0,
},
{
title: "人员数",
dataIndex: "personCount",
width: 100,
align: "center",
render: text => text || 0,
},
{
title: "操作",
fixed: "right",
width: 180,
width: 200,
align: "center",
render: (_, record) => (
<Space>
{/* {props.permission("xfkzs-btn-view") && ( */}
<Space size={8}>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
{/* )} */}
{/* {props.permission("xfkzs-btn-edit") && ( */}
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
{/* )} */}
{/* {props.permission("xfkzs-btn-delete") && ( */}
<Button
type="link"
size="small"
danger
onClick={() => {
onDelete(record.id);
@ -170,7 +208,6 @@ function List(props) {
>
删除
</Button>
{/* )} */}
</Space>
),
},

View File

@ -14,7 +14,6 @@ function View(props) {
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState(null);
const [statusDict, setStatusDict] = useState([]);
const [statusLabel, setStatusLabel] = useState("-");
const { loading: dictLoading, getDictionary } = useDictionary();
const { loading: getFileLoading, getFile } = useGetFile();
@ -24,16 +23,16 @@ function View(props) {
try {
const { data } = await props["controlRoomDetail"]({ id: query.id });
let nextDetail = data;
// 获取图片文件
if (data.roomId) {
const files = await getFile({
eqType: UPLOAD_FILE_TYPE_ENUM[302],
eqForeignKey: data.roomId,
});
nextDetail = { ...data, roomImages: files };
data.roomImages = files;
}
setDetail(nextDetail);
setDetail(data);
}
catch (error) {
message.error("加载详情失败");
@ -60,19 +59,15 @@ function View(props) {
fetchDict();
}, []);
useEffect(() => {
// 获取状态显示文本
const getStatusLabel = () => {
if (!detail)
return;
return "-";
const match = statusDict.find(item => item.dictValue === detail.roomStatus);
setStatusLabel(match?.dictLabel || detail.roomStatusName || detail.roomStatus || "-");
}, [detail, statusDict]);
const longitude = detail?.lng ?? detail?.longitude;
const latitude = detail?.lat ?? detail?.latitude;
const lngLatText = longitude != null && latitude != null
? `${longitude}, ${latitude}`
: (longitude ?? latitude ?? "-");
return match?.dictLabel || detail.roomStatusName || detail.roomStatus || "-";
};
// 设备表格列定义
const deviceColumns = [
{
title: "序号",
@ -86,6 +81,7 @@ function View(props) {
width: 180,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "设备型号",
@ -93,22 +89,25 @@ function View(props) {
width: 180,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "设备数量",
dataIndex: "deviceQty",
align: "center",
width: 120,
align: "center",
render: text => text || 0,
},
{
title: "设备位置",
dataIndex: "deviceLocation",
align: "center",
ellipsis: true,
width: 240,
render: text => text || "-",
},
];
// 人员表格列定义
const personnelColumns = [
{
title: "序号",
@ -122,6 +121,7 @@ function View(props) {
width: 160,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "人员手机号",
@ -129,13 +129,14 @@ function View(props) {
width: 180,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "人员值班情况",
render: (_, record) => record.dutyDesc || "-",
dataIndex: "dutyDesc",
align: "center",
ellipsis: true,
width: 240,
render: text => text || "-",
},
];
@ -146,13 +147,17 @@ function View(props) {
isShowFooter={false}
>
{detail && (
<>
<Card title="基本信息" style={{ marginBottom: 24, marginTop: 24 }}>
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Descriptions
bordered
column={2}
labelStyle={{ width: 180, backgroundColor: "#fafafa" }}
contentStyle={{ backgroundColor: "#fff" }}
labelStyle={{
width: "200px",
backgroundColor: "#fafafa",
fontWeight: "normal",
}}
items={[
{
label: "消防控制室名称",
@ -160,7 +165,7 @@ function View(props) {
},
{
label: "消防控制室状态",
children: statusLabel,
children: getStatusLabel(),
},
{
label: "负责人",
@ -171,31 +176,33 @@ function View(props) {
children: detail.principalPhone || "-",
},
{
label: "经纬度",
children: lngLatText,
span: 2,
label: "经度",
children: detail.lng || detail.longitude || "-",
},
{
label: "纬度",
children: detail.lat || detail.latitude || "-",
},
{
label: "消防控制室图片",
children: detail.roomImages && detail.roomImages.length > 0
? (
<Image.PreviewGroup>
<Space>
{detail.roomImages.map((img, index) => (
<Image
key={index}
width={100}
height={100}
src={img}
style={{ objectFit: "cover" }}
/>
))}
</Space>
</Image.PreviewGroup>
)
: (
"无"
),
<Image.PreviewGroup>
<Space wrap>
{detail.roomImages.map((img, index) => (
<Image
key={index}
width={100}
height={100}
src={img.url || img}
style={{ objectFit: "cover", borderRadius: 4 }}
alt={`消防控制室图片${index + 1}`}
/>
))}
</Space>
</Image.PreviewGroup>
)
: "-",
span: 2,
},
]}
@ -207,10 +214,8 @@ function View(props) {
columns={deviceColumns}
dataSource={detail.devices || []}
pagination={false}
rowKey={(record, index) => index}
rowKey={(record, index) => record.id || `device-${index}`}
locale={{ emptyText: "暂无设备信息" }}
bordered
tableLayout="fixed"
/>
</Card>
@ -219,26 +224,17 @@ function View(props) {
columns={personnelColumns}
dataSource={detail.persons || []}
pagination={false}
rowKey={(record, index) => index}
rowKey={(record, index) => record.id || `person-${index}`}
locale={{ emptyText: "暂无人员信息" }}
bordered
tableLayout="fixed"
/>
</Card>
<div style={{ marginTop: 24, textAlign: "center" }}>
<Button
onClick={() => {
props.history.replace({
pathname: "/Container/BranchCompany/ControlRoom/list",
state: { refresh: true },
});
}}
>
<div style={{ textAlign: "center" }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>
</div>
</>
</div>
)}
</Page>
);

View File

@ -1,7 +1,8 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Card, Col, Form, Input, InputNumber, message, Row, Space, Table } from "antd";
import { Button, Card, Col, Form, Input, message, Row, Space, Table } from "antd";
import { useEffect, useState } from "react";
import MapSelector from "zy-react-library/components/Map/MapSelector";
import Page from "zy-react-library/components/Page";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import Upload from "zy-react-library/components/Upload";
@ -17,6 +18,9 @@ function Add(props) {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
// 设备信息列表
const [devices, setDeviceList] = useState([]);
@ -43,7 +47,7 @@ function Add(props) {
// 设置设备列表
if (data.devices && data.devices.length > 0) {
setDeviceList(data.devices.map((item, index) => ({ ...item, key: index })));
setDeviceList(data.devices.map((item, index) => ({ ...item, key: item.id || index })));
}
}
catch (error) {
@ -56,7 +60,18 @@ function Add(props) {
useEffect(() => {
query.id && getData();
}, []);
}, [query.id]);
const openMap = () => {
setMapLng(form.getFieldValue("lng") || "");
setMapLat(form.getFieldValue("lat") || "");
setMapOpen(true);
};
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
setMapOpen(false);
};
const onFinish = async (values) => {
// 验证设备列表
@ -67,16 +82,17 @@ function Add(props) {
// 验证设备列表是否填写完整
const invalidDevice = devices.find(
item => !item.deviceName || !item.deviceModel || !item.deviceQty || !item.deviceLocation,
item => !item.deviceCode || !item.deviceName || !item.deviceCategory
|| !item.chargeUnit || !item.deviceLocation || !item.paramsSpec,
);
if (invalidDevice) {
message.warning("请完善设备信息");
return;
}
// 楠岃瘉鍥剧墖鏄惁涓婁紶
// 验证图片是否上传
if (!values.roomImages || values.roomImages.length === 0) {
message.warning("璇蜂笂浼犳秷闃叉车鎴垮浘鐗?");
message.warning("请上传消防泵房图片");
return;
}
@ -102,9 +118,10 @@ function Add(props) {
devices: devices.map(({ key, ...device }) => ({
deviceCode: device.deviceCode,
deviceName: device.deviceName,
deviceModel: device.deviceModel,
deviceQty: device.deviceQty,
deviceCategory: device.deviceCategory,
chargeUnit: device.chargeUnit,
deviceLocation: device.deviceLocation,
paramsSpec: device.paramsSpec,
...(device.id && { id: device.id }),
})),
};
@ -128,10 +145,12 @@ function Add(props) {
const addDevice = () => {
const newDevice = {
key: Date.now(),
deviceCode: "",
deviceName: "",
deviceModel: "",
deviceQty: null,
deviceCategory: "",
chargeUnit: "",
deviceLocation: "",
paramsSpec: "",
};
setDeviceList([...devices, newDevice]);
};
@ -154,6 +173,7 @@ function Add(props) {
设备编号
</>),
dataIndex: "deviceCode",
width: 150,
render: (text, record) => (
<Input
value={text}
@ -168,6 +188,7 @@ function Add(props) {
设备名称
</>),
dataIndex: "deviceName",
width: 150,
render: (text, record) => (
<Input
value={text}
@ -179,50 +200,66 @@ function Add(props) {
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备型号
设备分类
</>),
dataIndex: "deviceModel",
dataIndex: "deviceCategory",
width: 150,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备型号"
onChange={e => updateDevice(record.key, "deviceModel", e.target.value)}
placeholder="请输入设备分类"
onChange={e => updateDevice(record.key, "deviceCategory", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备数量
负责单位
</>),
dataIndex: "deviceQty",
dataIndex: "chargeUnit",
width: 150,
render: (text, record) => (
<InputNumber
<Input
value={text}
placeholder="请输入设备数量"
min={1}
style={{ width: "100%" }}
onChange={value => updateDevice(record.key, "deviceQty", value)}
placeholder="请输入负责单位"
onChange={e => updateDevice(record.key, "chargeUnit", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备位置
具体位置
</>),
dataIndex: "deviceLocation",
width: 150,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备位置"
placeholder="请输入具体位置"
onChange={e => updateDevice(record.key, "deviceLocation", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备参数和规格
</>),
dataIndex: "paramsSpec",
width: 180,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备参数和规格"
onChange={e => updateDevice(record.key, "paramsSpec", e.target.value)}
/>
),
},
{
title: "操作",
width: 80,
width: 100,
align: "center",
render: (_, record) => (
<Button type="link" danger onClick={() => removeDevice(record.key)}>
@ -241,21 +278,20 @@ function Add(props) {
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, marginTop: 24 }}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Form.Item name="pumpRoomId" hidden>
<Input />
</Form.Item>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="消防泵房名称"
name="pumpRoomName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入消防泵房名称" },
{ max: 100, message: "消防泵房名称不能超过100个字符" },
@ -269,8 +305,6 @@ function Add(props) {
<Form.Item
label="消防泵房状态"
name="pumpRoomStatus"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请选择消防泵房状态" }]}
>
<DictionarySelect
@ -286,8 +320,6 @@ function Add(props) {
<Form.Item
label="负责人"
name="principalName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入负责人" },
{ max: 50, message: "负责人不能超过50个字符" },
@ -301,8 +333,6 @@ function Add(props) {
<Form.Item
label="负责人手机号"
name="principalPhone"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入负责人手机号" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
@ -318,49 +348,42 @@ function Add(props) {
<Form.Item
label="经度"
name="lng"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入经度" }]}
rules={[{ required: true, message: "请选择经度" }]}
>
<InputNumber
placeholder="请输入经度"
style={{ width: "100%" }}
min={-180}
max={180}
step={0.000001}
precision={6}
/>
<Input placeholder="请点击地图定位按钮选择" disabled />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="纬度"
name="lat"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入纬度" }]}
required
>
<InputNumber
placeholder="请输入纬度"
style={{ width: "100%" }}
min={-90}
max={90}
step={0.000001}
precision={6}
/>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={24}>
<Form.Item
label="消防泵房图片"
name="roomImages"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防泵房图片" }]}
extra="默认上传4个目前支持jpg、jpeg、png格式单张图片不超过5mb"
extra="默认上传4个,目前支持jpg、jpeg、png格式,单张图片不超过5mb"
>
<Upload
fileType="image"
@ -374,7 +397,6 @@ function Add(props) {
</Form.Item>
</Col>
</Row>
</Card>
<Card
@ -393,7 +415,6 @@ function Add(props) {
rowKey="key"
locale={{ emptyText: "暂无设备信息,请点击新增按钮添加" }}
/>
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
@ -407,6 +428,14 @@ function Add(props) {
</Space>
</Form.Item>
</Form>
<MapSelector
visible={mapOpen}
onClose={() => setMapOpen(false)}
longitude={mapLng}
latitude={mapLat}
onConfirm={handleMapConfirm}
/>
</Page>
);
}

View File

@ -19,11 +19,14 @@ function List(props) {
const [deleting, setDeleting] = useState(false);
const [statusDict, setStatusDict] = useState([]);
const [initialized, setInitialized] = useState(false);
const { getDictionary } = useDictionary();
// 一次性初始化字典和表单
useEffect(() => {
const fetchDict = async () => {
const init = async () => {
// 加载字典
try {
const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" });
setStatusDict(Array.isArray(dict) ? dict : []);
@ -31,23 +34,39 @@ function List(props) {
catch (error) {
setStatusDict([]);
}
// 设置表单初始值并加载数据
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
}
getData();
setInitialized(true);
};
fetchDict();
if (!initialized) {
init();
}
}, []);
// 监听 eqCorpId 变化
useEffect(() => {
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
if (initialized && query.eqCorpId) {
const currentCorpId = form.getFieldValue("eqCorpId");
if (currentCorpId !== query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
}
}
}, [query.eqCorpId]);
}, [query.eqCorpId, initialized]);
const getStatusLabel = (record) => {
if (record.roomStatusName)
return record.roomStatusName;
if (!record) return "-";
if (record.roomStatusName) return record.roomStatusName;
const match = statusDict.find(item => item.dictValue === record.pumpRoomStatus);
return match?.dictLabel || record.pumpRoomStatus || "-";
};
const onDelete = (id) => {
Modal.confirm({
title: "确认删除",
@ -63,9 +82,12 @@ function List(props) {
setDeleting(true);
try {
await props["pumpRoomDelete"]({ id });
message.success("删除");
message.success("删除成功");
getData();
}
catch (error) {
message.error("删除失败");
}
finally {
setDeleting(false);
}
@ -77,18 +99,26 @@ function List(props) {
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{ name: "likePumpRoomName", label: "消防泵房名称" },
{
name: "likePumpRoomName",
label: "消防泵房名称",
},
{
name: "eqPumpRoomStatus",
label: "消防泵房状态",
render: (<DictionarySelect dictValue="fire_resource_contro_root_type" />),
},
{ name: "eqCorpId", onlyForLabel: true },
{
name: "eqCorpId",
onlyForLabel: true,
},
]}
form={form}
onFinish={getData}
/>
<Table
toolBarRender={() => (
<Space>
@ -103,43 +133,67 @@ function List(props) {
</Space>
)}
columns={[
// { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "消防泵房名称", dataIndex: "pumpRoomName", ellipsis: true, width: 120 },
{
title: "消防泵房名称",
dataIndex: "pumpRoomName",
width: 200,
ellipsis: true,
},
{
title: "消防泵房状态",
width: 140,
width: 150,
align: "center",
ellipsis: true,
render: (_, record) => getStatusLabel(record),
},
{ title: "负责人", dataIndex: "principalName", width: 120 },
{ title: "负责人手机号", dataIndex: "principalPhone", width: 140 },
{ title: "设备数", dataIndex: "deviceCount", width: 100, align: "center" },
{
title: "负责人",
dataIndex: "principalName",
width: 120,
align: "center",
ellipsis: true,
},
{
title: "负责人手机号",
dataIndex: "principalPhone",
width: 150,
align: "center",
ellipsis: true,
},
{
title: "设备数",
dataIndex: "deviceCount",
width: 100,
align: "center",
render: text => text || 0,
},
{
title: "操作",
fixed: "right",
width: 180,
width: 200,
align: "center",
render: (_, record) => (
<Space>
<Space size={8}>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
<Button
type="link"
size="small"
danger
onClick={() => onDelete(record.id)}
>

View File

@ -31,28 +31,32 @@ function View(props) {
fetchDict();
}, []);
const getStatusLabel = (record) => {
if (!record)
// 获取状态显示文本
const getStatusLabel = () => {
if (!detail)
return "-";
if (record.roomStatusName)
return record.roomStatusName;
const match = statusDict.find(item => item.dictValue === record.pumpRoomStatus);
return match?.dictLabel || record.pumpRoomStatus || "-";
if (detail.roomStatusName)
return detail.roomStatusName;
const match = statusDict.find(item => item.dictValue === detail.pumpRoomStatus);
return match?.dictLabel || detail.pumpRoomStatus || "-";
};
const getData = async () => {
setLoading(true);
try {
const { data } = await props["pumpRoomDetail"]({ id: query.id });
let nextDetail = data;
// 获取图片文件
const roomKey = data.roomId || data.pumpRoomId || data.id;
if (roomKey) {
const files = await getFile({
eqType: UPLOAD_FILE_TYPE_ENUM[302],
eqForeignKey: roomKey,
});
nextDetail = { ...data, roomImages: files };
data.roomImages = files;
}
setDetail(nextDetail);
setDetail(data);
}
catch (error) {
message.error("加载详情失败");
@ -64,16 +68,63 @@ function View(props) {
useEffect(() => {
query.id && getData();
}, []);
}, [query.id]);
// 设备表格列定义
const deviceColumns = [
{ title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "设备编号", dataIndex: "deviceCode", align: "center" },
{ title: "设备名称", dataIndex: "deviceName", align: "center" },
{ title: "设备型号", dataIndex: "deviceModel", align: "center" },
{ title: "设备数量", dataIndex: "deviceQty", align: "center" },
{ title: "设备位置", dataIndex: "deviceLocation", align: "center" },
{
title: "序号",
width: 80,
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "设备编号",
dataIndex: "deviceCode",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "设备名称",
dataIndex: "deviceName",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "设备分类",
dataIndex: "deviceCategory",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "负责单位",
dataIndex: "chargeUnit",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "具体位置",
dataIndex: "deviceLocation",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "设备参数和规格",
dataIndex: "paramsSpec",
align: "center",
ellipsis: true,
render: text => text || "-",
},
];
return (
@ -83,59 +134,62 @@ function View(props) {
isShowFooter={false}
>
{detail && (
<>
<Card title="基本信息" style={{ marginBottom: 24, marginTop: 24 }}>
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Descriptions
bordered
column={2}
labelStyle={{ width: 180, backgroundColor: "#fafafa" }}
contentStyle={{ backgroundColor: "#fff" }}
labelStyle={{
width: "200px",
backgroundColor: "#fafafa",
fontWeight: "normal",
}}
items={[
{
label: "消防泵房名称",
children: detail.pumpRoomName,
children: detail.pumpRoomName || "-",
},
{
label: "消防泵房状态",
children: getStatusLabel(detail),
children: getStatusLabel(),
},
{
label: "负责人",
children: detail.principalName,
children: detail.principalName || "-",
},
{
label: "负责人手机号",
children: detail.principalPhone,
children: detail.principalPhone || "-",
},
{
label: "经度",
children: detail.lng,
children: detail.lng || "-",
},
{
label: "纬度",
children: detail.lat,
children: detail.lat || "-",
},
{
label: "消防泵房图片",
children: detail.roomImages && detail.roomImages.length > 0
? (
<Image.PreviewGroup>
<Space>
{detail.roomImages.map((img, index) => (
<Image
key={index}
width={100}
height={100}
src={img}
style={{ objectFit: "cover" }}
/>
))}
</Space>
</Image.PreviewGroup>
)
: (
"无"
),
<Image.PreviewGroup>
<Space wrap>
{detail.roomImages.map((img, index) => (
<Image
key={index}
width={100}
height={100}
src={img.url || img}
style={{ objectFit: "cover", borderRadius: 4 }}
alt={`消防泵房图片${index + 1}`}
/>
))}
</Space>
</Image.PreviewGroup>
)
: "-",
span: 2,
},
]}
@ -147,17 +201,18 @@ function View(props) {
columns={deviceColumns}
dataSource={detail.devices || []}
pagination={false}
rowKey={(record, index) => index}
rowKey={(record, index) => record.id || `device-${index}`}
scroll={{ x: 1000 }}
locale={{ emptyText: "暂无设备信息" }}
/>
</Card>
<div style={{ marginTop: 24, textAlign: "center" }}>
<div style={{ textAlign: "center" }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>
</div>
</>
</div>
)}
</Page>
);

View File

@ -17,7 +17,7 @@ function Add(props) {
// 消防队员列表
const [rescueMembers, setRescueMembers] = useState([]);
// 添加状态保存字典显示名称
// 添加状态保存字典显示名称
const [teamTypeName, setTeamTypeName] = useState("");
const [regionScopeName, setRegionScopeName] = useState("");
@ -33,7 +33,7 @@ function Add(props) {
form.setFieldsValue(data);
// 设置字典显示名称
// 设置字典显示名称
if (data.teamTypeName) {
setTeamTypeName(data.teamTypeName);
}
@ -43,7 +43,7 @@ function Add(props) {
// 设置消防队员列表
if (data.rescueMembers && data.rescueMembers.length > 0) {
setRescueMembers(data.rescueMembers.map((item, index) => ({ ...item, key: index })));
setRescueMembers(data.rescueMembers.map((item, index) => ({ ...item, key: item.id || index })));
}
}
catch (error) {
@ -83,7 +83,7 @@ function Add(props) {
...values,
establishDate: values.establishDate ? values.establishDate.format("YYYY-MM-DD") : null,
// 从状态中获取字典显示名称
// 从状态中获取字典显示名称
teamTypeName,
regionScopeName,
@ -191,23 +191,23 @@ function Add(props) {
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, marginTop: 24 }}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Form.Item name="teamId" hidden>
<Input />
</Form.Item>
{/* 第一行:救援队名称、类型 */}
{/* 第一行:救援队名称(单列) */}
<Row gutter={24}>
<Col span={12}>
<Col span={24}>
<Form.Item
label="救援队名称"
name="teamName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[
{ required: true, message: "请输入救援队名称" },
{ max: 100, message: "救援队名称不能超过100个字符" },
@ -216,38 +216,46 @@ function Add(props) {
<Input placeholder="请输入救援队名称" />
</Form.Item>
</Col>
</Row>
{/* 第二行:类型、负责人单位或部门 */}
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="类型"
name="teamType"
labelCol={{ span: 12 }}
rules={[
{ required: true, message: "请选择救援队类型" },
{ max: 50, message: "救援队类型不能超过50个字符" },
]}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请选择救援队类型" }]}
>
<DictionarySelect
dictValue="fire_resource_team_type"
placeholder="请选择"
onChange={(value, option) => {
// ⭐ 监听选择事件,保存显示名称
setTeamTypeName(option?.children || option?.label || "");
}}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="负责人单位或部门"
name="chargeOrgDept"
rules={[
{ required: true, message: "请输入负责人单位或部门" },
{ max: 200, message: "负责人单位或部门不能超过200个字符" },
]}
>
<Input placeholder="请输入负责人单位或部门" />
</Form.Item>
</Col>
</Row>
{/* 第二行:队长、队长电话 */}
{/* 第行:队长、队长电话 */}
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="队长"
name="captainName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入队长姓名" },
{ max: 50, message: "队长姓名不能超过50个字符" },
@ -261,8 +269,6 @@ function Add(props) {
<Form.Item
label="队长电话"
name="captainPhone"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入队长电话" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
@ -273,14 +279,12 @@ function Add(props) {
</Col>
</Row>
{/* 第行:指挥人员、建立日期 */}
{/* 第行:指挥人员、建立日期 */}
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="指挥人员"
name="commandCrew"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入指挥人员姓名" },
{ max: 50, message: "指挥人员姓名不能超过50个字符" },
@ -294,8 +298,6 @@ function Add(props) {
<Form.Item
label="建立日期"
name="establishDate"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请选择建立日期" }]}
>
<DatePicker
@ -307,24 +309,18 @@ function Add(props) {
</Col>
</Row>
{/* 第行:所属区域或范围、职责和任务范围 */}
{/* 第行:所属区域或范围、职责和任务范围 */}
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="所属区域或范围"
name="regionScope"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请选择救援队所属区域或范围" },
{ max: 50, message: "救援队所属区域或范围不能超过50个字符" },
]}
rules={[{ required: true, message: "请选择救援队所属区域或范围" }]}
>
<DictionarySelect
dictValue="fire_resource_area_scope"
placeholder="请选择"
onChange={(value, option) => {
// ⭐ 监听选择事件,保存显示名称
setRegionScopeName(option?.children || option?.label || "");
}}
/>
@ -335,37 +331,12 @@ function Add(props) {
<Form.Item
label="职责和任务范围"
name="dutyScope"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入职责和任务范围" },
{ max: 500, message: "职责和任务范围不能超过500个字符" },
]}
>
<Input.TextArea
placeholder="请输入职责和任务范围"
rows={4}
maxLength={500}
showCount
/>
</Form.Item>
</Col>
</Row>
{/* 第五行:负责人单位或部门(单独一行) */}
<Row gutter={24}>
<Col span={24}>
<Form.Item
label="负责人单位或部门"
name="chargeOrgDept"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
rules={[
{ required: true, message: "请输入负责人单位或部门" },
{ max: 200, message: "负责人单位或部门不能超过200个字符" },
]}
>
<Input placeholder="请输入负责人单位或部门" />
<Input placeholder="请输入职责和任务范围" />
</Form.Item>
</Col>
</Row>
@ -385,7 +356,7 @@ function Add(props) {
dataSource={rescueMembers}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无队员信息请点击新增按钮添加" }}
locale={{ emptyText: "暂无队员信息,请点击新增按钮添加" }}
/>
</Card>

View File

@ -8,7 +8,6 @@ import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import Table from "zy-react-library/components/Table";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import useTable from "zy-react-library/hooks/useTable";
import { getLabelName } from "zy-react-library/utils";
import { NS_RESCUE_TEAM } from "~/enumerate/namespace";
function List(props) {
@ -18,13 +17,29 @@ function List(props) {
const { tableProps, getData } = useTable(props["rescueTeamList"], { form });
const [deleting, setDeleting] = useState(false);
const [initialized, setInitialized] = useState(false);
// 一次性初始化表单
useEffect(() => {
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
if (!initialized) {
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
}
getData();
setInitialized(true);
}
}, [query.eqCorpId]);
}, []);
// 监听 eqCorpId 变化
useEffect(() => {
if (initialized && query.eqCorpId) {
const currentCorpId = form.getFieldValue("eqCorpId");
if (currentCorpId !== query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
}
}
}, [query.eqCorpId, initialized]);
const onDelete = (id) => {
Modal.confirm({
@ -41,9 +56,12 @@ function List(props) {
setDeleting(true);
try {
await props["rescueTeamDelete"]({ id });
message.success("删除");
message.success("删除成功");
getData();
}
catch (error) {
message.error("删除失败");
}
finally {
setDeleting(false);
}
@ -55,24 +73,42 @@ function List(props) {
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{ name: "likeTeamName", label: "救援队名称" },
{
name: "likeTeamName",
label: "救援队名称",
},
{
name: "eqTeamType",
label: "类型",
render: (<DictionarySelect dictValue="fire_resource_team_type" />),
},
{ name: "likeChargeOrgDept", label: "负责人单位或部门" },
{ name: "likeCaptainName", label: "队长" },
{ name: "eqCorpId", onlyForLabel: true },
{
name: "likeChargeOrgDept",
label: "负责人单位或部门",
},
{
name: "likeCaptainName",
label: "队长",
},
{
name: "eqRegionScope",
label: "所属区域或范围",
render: (<DictionarySelect dictValue="fire_resource_area_scope" />),
},
{
name: "eqCorpId",
onlyForLabel: true,
},
]}
form={form}
onFinish={getData}
/>
<Table
toolBarRender={() => (
<Space>
{/* {props.permission("jydgl-btn-add") && ( */}
<Button
type="primary"
onClick={() => {
@ -81,59 +117,89 @@ function List(props) {
>
新增
</Button>
{/* )} */}
</Space>
)}
columns={[
// { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "救援队名称", dataIndex: "teamName", ellipsis: true },
{
title: "救援队名称",
dataIndex: "teamName",
width: 200,
ellipsis: true,
},
{
title: "类型",
dataIndex: "teamTypeName",
width: 140,
width: 150,
align: "center",
ellipsis: true,
},
{
title: "负责人单位或部门",
dataIndex: "chargeOrgDept",
width: 200,
ellipsis: true,
},
{
title: "队长",
dataIndex: "captainName",
width: 120,
align: "center",
ellipsis: true,
},
{
title: "指挥人员",
dataIndex: "commandCrew",
width: 120,
align: "center",
ellipsis: true,
},
{
title: "所属区域或范围",
dataIndex: "regionScopeName",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
},
{
title: "队员人数",
dataIndex: "memberCount",
width: 100,
align: "center",
render: text => text || 0,
},
{ title: "负责人单位或部门", dataIndex: "chargeOrgDept", ellipsis: true },
{ title: "队长", dataIndex: "captainName", width: 120, align: "center" },
{ title: "指挥人员", dataIndex: "commandCrew", width: 120, align: "center" },
{ title: "队员人数", dataIndex: "memberCount", width: 110, align: "center" },
{
title: "操作",
fixed: "right",
width: 180,
width: 200,
align: "center",
render: (_, record) => (
<Space>
{/* {props.permission("jydgl-btn-view") && ( */}
<Space size={8}>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
{/* )} */}
{/* {props.permission("jydgl-btn-edit") && ( */}
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
{/* )} */}
{/* {props.permission("jydgl-btn-delete") && ( */}
<Button
type="link"
size="small"
danger
onClick={() => onDelete(record.id)}
>
删除
</Button>
{/* )} */}
</Space>
),
},

View File

@ -31,9 +31,22 @@ function View(props) {
// 队员表格列定义
const memberColumns = [
{ title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "队员", dataIndex: "personName" },
{ title: "队员电话", dataIndex: "personPhone" },
{
title: "序号",
width: 80,
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "队员姓名",
dataIndex: "personName",
render: text => text || "-",
},
{
title: "队员电话",
dataIndex: "personPhone",
render: text => text || "-",
},
];
return (
@ -43,14 +56,14 @@ function View(props) {
isShowFooter={false}
>
{detail && (
<>
<Card title="基本信息" style={{ marginBottom: 24, marginTop: 24 }}>
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Descriptions
bordered
column={2}
contentStyle={{ backgroundColor: "#fff" }}
labelStyle={{
width: "180px",
width: "200px",
backgroundColor: "#fafafa",
fontWeight: "normal",
}}
@ -58,18 +71,15 @@ function View(props) {
{
label: "救援队名称",
children: detail.teamName || "-",
},
{
label: "负责人单位或部门",
children: detail.chargeOrgDept || "-",
span: 2,
},
{
label: "类型",
children: detail.teamTypeName || detail.teamType || "-",
},
{
label: "职责和任务范围",
children: detail.dutyScope || "-",
label: "负责人单位或部门",
children: detail.chargeOrgDept || "-",
},
{
label: "队长",
@ -91,6 +101,10 @@ function View(props) {
label: "所属区域或范围",
children: detail.regionScopeName || detail.regionScope || "-",
},
{
label: "职责和任务范围",
children: detail.dutyScope || "-",
},
]}
/>
</Card>
@ -100,17 +114,17 @@ function View(props) {
columns={memberColumns}
dataSource={detail.rescueMembers || []}
pagination={false}
rowKey={(record, index) => index}
rowKey={(record, index) => record.id || `member-${index}`}
locale={{ emptyText: "暂无队员信息" }}
/>
</Card>
<div style={{ marginTop: 24, textAlign: "center" }}>
<div style={{ textAlign: "center" }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>
</div>
</>
</div>
)}
</Page>
);

View File

@ -1,7 +1,8 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Card, Col, Form, Input, InputNumber, message, Row, Space } from "antd";
import { useEffect, useState } from "react";
import MapSelector from "zy-react-library/components/Map/MapSelector";
import Page from "zy-react-library/components/Page";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
@ -12,6 +13,9 @@ function Add(props) {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
const getData = async () => {
setLoading(true);
@ -31,6 +35,17 @@ function Add(props) {
query.id && getData();
}, []);
const openMap = () => {
setMapLng(form.getFieldValue("lng") || "");
setMapLat(form.getFieldValue("lat") || "");
setMapOpen(true);
};
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
setMapOpen(false);
};
const onFinish = async (values) => {
setSubmitting(true);
try {
@ -58,9 +73,9 @@ function Add(props) {
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, marginTop: 24 }}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Row gutter={24}>
@ -68,8 +83,6 @@ function Add(props) {
<Form.Item
label="消防水源名称"
name="waterSourceName"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入消防水源名称" },
{ max: 100, message: "消防水源名称不能超过100个字符" },
@ -78,15 +91,11 @@ function Add(props) {
<Input placeholder="请输入消防水源名称" />
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="消防水源状态"
name="waterSourceStatus"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请选择消防水源状态" }]}
>
<DictionarySelect
@ -102,49 +111,38 @@ function Add(props) {
<Form.Item
label="经度"
name="lng"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入经度" }]}
rules={[{ required: true, message: "请选择经度" }]}
>
<InputNumber
placeholder="请输入经度"
style={{ width: "100%" }}
min={-180}
max={180}
step={0.000001}
precision={6}
/>
<Input placeholder="请点击地图定位按钮选择" disabled />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="纬度"
name="lat"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入纬度" }]}
required
>
<InputNumber
placeholder="请输入纬度"
style={{ width: "100%" }}
min={-90}
max={90}
step={0.000001}
precision={6}
/>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="所属单位或部门"
name="belongOrgDept"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入所属单位或部门" },
{ max: 200, message: "所属单位或部门不能超过200个字符" },
@ -153,12 +151,11 @@ function Add(props) {
<Input placeholder="请输入所属单位或部门" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="水源位置"
name="waterLocation"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[
{ required: true, message: "请输入水源位置" },
{ max: 200, message: "水源位置不能超过200个字符" },
@ -174,8 +171,6 @@ function Add(props) {
<Form.Item
label="接口形式"
name="interfaceForm"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入接口形式" }]}
>
<Input placeholder="请输入接口形式" />
@ -186,8 +181,6 @@ function Add(props) {
<Form.Item
label="水源类型"
name="waterType"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入水源类型" }]}
>
<Input placeholder="请输入水源类型" />
@ -200,8 +193,6 @@ function Add(props) {
<Form.Item
label="水源编号"
name="waterCode"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入水源编号" }]}
>
<Input placeholder="请输入水源编号" />
@ -212,8 +203,6 @@ function Add(props) {
<Form.Item
label="吸水口规格"
name="suctionSpec"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入吸水口规格" }]}
>
<InputNumber
@ -230,8 +219,6 @@ function Add(props) {
<Form.Item
label="水源容量"
name="capacity"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入水源容量" }]}
>
<Input placeholder="请输入水源容量" />
@ -242,14 +229,11 @@ function Add(props) {
<Form.Item
label="供水能力"
name="supplyAbility"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入供水能力" }]}
>
<Input placeholder="请输入供水能力" />
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
@ -257,8 +241,6 @@ function Add(props) {
<Form.Item
label="设备清单"
name="equipmentList"
labelCol={{ span: 12 }}
wrapperCol={{ span: 12 }}
rules={[{ required: true, message: "请输入设备清单" }]}
>
<Input placeholder="请输入设备清单" />
@ -268,7 +250,7 @@ function Add(props) {
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
<Space>
<Space size={16}>
<Button onClick={() => props.history.goBack()}>
取消
</Button>
@ -278,6 +260,14 @@ function Add(props) {
</Space>
</Form.Item>
</Form>
<MapSelector
visible={mapOpen}
onClose={() => setMapOpen(false)}
longitude={mapLng}
latitude={mapLat}
onConfirm={handleMapConfirm}
/>
</Page>
);
}

View File

@ -1,7 +1,7 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message, Modal, Space } from "antd";
import { useEffect, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import Page from "zy-react-library/components/Page";
import Search from "zy-react-library/components/Search";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
@ -15,10 +15,34 @@ function List(props) {
const [form] = Form.useForm();
const query = useGetUrlQuery();
const { tableProps, getData } = useTable(props["waterSourceList"], { form });
const { tableProps, getData } = useTable(props["waterSourceList"], {
form,
params: () => (query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}),
useStorageQueryCriteria: false,
});
const [deleting, setDeleting] = useState(false);
const corpIdRef = useRef(query.eqCorpId);
const [statusDict, setStatusDict] = useState([]);
const searchOptions = useMemo(() => ([
{
name: "likeWaterSourceName",
label: "消防水源名称",
},
{
name: "eqWaterSourceStatus",
label: "消防水源状态",
render: (<DictionarySelect dictValue="fire_resource_water_type" />),
},
{
name: "likeBelongOrgDept",
label: "所属单位或部门",
},
{
name: "eqCorpId",
onlyForLabel: true,
},
]), []);
const { getDictionary } = useDictionary();
@ -38,15 +62,20 @@ function List(props) {
useEffect(() => {
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
getData();
if (corpIdRef.current !== query.eqCorpId) {
getData();
}
}
corpIdRef.current = query.eqCorpId;
}, [query.eqCorpId]);
const getStatusLabel = (record) => {
if (!record)
return "-";
if (record.sourceStatusName)
return record.sourceStatusName;
const match = statusDict.find(item => item.dictValue === record.waterSourceStatus);
return match?.dictLabel || record.sourceStatus || "-";
return match?.dictLabel || record.waterSourceStatus || "-";
};
const onDelete = (id) => {
@ -64,9 +93,12 @@ function List(props) {
setDeleting(true);
try {
await props["waterSourceDelete"]({ id });
message.success("删除");
message.success("删除成功");
getData();
}
catch (error) {
message.error("删除失败");
}
finally {
setDeleting(false);
}
@ -78,19 +110,12 @@ function List(props) {
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 8 }}
options={[
{ name: "likeWaterSourceName", label: "消防水源名称" },
{
name: "eqWaterSourceStatus",
label: "消防水源状态",
render: (<DictionarySelect dictValue="fire_resource_water_type" />),
},
{ name: "likeBelongOrgDept", label: "所属单位或部门" },
{ name: "eqCorpId", onlyForLabel: true },
]}
wrapperCol={{ span: 16 }}
options={searchOptions}
form={form}
onFinish={getData}
/>
<Table
toolBarRender={() => (
<Space>
@ -105,42 +130,60 @@ function List(props) {
</Space>
)}
columns={[
// { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{ title: "消防水源名称", dataIndex: "waterSourceName", ellipsis: true },
{
title: "消防水源名称",
dataIndex: "waterSourceName",
width: 200,
ellipsis: true,
},
{
title: "消防水源状态",
width: 140,
dataIndex: "waterSourceStatus",
width: 150,
align: "center",
ellipsis: true,
render: (_, record) => getStatusLabel(record),
},
{ title: "所属单位或部门", dataIndex: "belongOrgDept", ellipsis: true },
{ title: "水源位置", dataIndex: "waterLocation", ellipsis: true },
{
title: "水源位置",
dataIndex: "waterLocation",
width: 200,
ellipsis: true,
},
{
title: "所属单位或部门",
dataIndex: "belongOrgDept",
width: 200,
ellipsis: true,
},
{
title: "操作",
fixed: "right",
width: 180,
width: 200,
align: "center",
render: (_, record) => (
<Space>
<Space size={8}>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
<Button
type="link"
size="small"
danger
onClick={() => onDelete(record.id)}
>

View File

@ -1,6 +1,6 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Card, Col, Descriptions, message, Row } from "antd";
import { Button, Card, Descriptions, message } from "antd";
import { useEffect, useState } from "react";
import Page from "zy-react-library/components/Page";
import useDictionary from "zy-react-library/hooks/useDictionary";
@ -60,208 +60,80 @@ function View(props) {
isShowFooter={false}
>
{detail && (
<>
<Card title="基本信息" style={{ marginBottom: 24, marginTop: 24 }}>
<Row gutter={24}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "消防水源名称",
children: detail.waterSourceName || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "消防水源状态",
children: getStatusLabel(detail.waterSourceStatus),
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "经度",
children: detail.lng || "-",
},
]}
/>
</Col>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "纬度",
children: detail.lat || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "所属单位或部门",
children: detail.belongOrgDept || "-",
},
]}
/>
</Col>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "水源位置",
children: detail.waterLocation || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "接口形式",
children: detail.interfaceForm || "-",
},
]}
/>
</Col>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "水源类型",
children: detail.waterType || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "水源编号",
children: detail.waterCode || "-",
},
]}
/>
</Col>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "吸水口规格",
children: detail.suctionSpec || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "水源容量",
children: detail.capacity || "-",
},
]}
/>
</Col>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "供水能力",
children: detail.supplyAbility || "-",
},
]}
/>
</Col>
</Row>
<Row gutter={24} style={{ marginTop: 16 }}>
<Col span={12}>
<Descriptions
bordered
column={1}
labelStyle={{ width: "50%" }}
items={[
{
label: "设备清单",
children: detail.equipmentList || "-",
},
]}
/>
</Col>
</Row>
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Descriptions
bordered
column={2}
contentStyle={{ backgroundColor: "#fff" }}
labelStyle={{
width: "200px",
backgroundColor: "#fafafa",
fontWeight: "normal",
}}
items={[
{
label: "消防水源名称",
children: detail.waterSourceName || "-",
},
{
label: "消防水源状态",
children: getStatusLabel(detail.waterSourceStatus),
},
{
label: "经度",
children: detail.lng || "-",
},
{
label: "纬度",
children: detail.lat || "-",
},
{
label: "水源位置",
children: detail.waterLocation || "-",
},
{
label: "所属单位或部门",
children: detail.belongOrgDept || "-",
},
{
label: "接口形式",
children: detail.interfaceForm || "-",
},
{
label: "水源类型",
children: detail.waterType || "-",
},
{
label: "水源编号",
children: detail.waterCode || "-",
},
{
label: "吸水口规格",
children: detail.suctionSpec || "-",
},
{
label: "水源容量",
children: detail.capacity || "-",
},
{
label: "供水能力",
children: detail.supplyAbility || "-",
},
{
label: "设备清单",
children: detail.equipmentList || "-",
},
]}
/>
</Card>
<div style={{ marginTop: 24, textAlign: "center" }}>
<div style={{ textAlign: "center" }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>
</div>
</>
</div>
)}
</Page>
);

View File

@ -26,81 +26,80 @@ function FireResourceStats(props) {
}
};
// 渲染可点击的数量链接
const renderCountLink = (text, record, type) => {
const count = text || 0;
// 如果数量为0只显示数字不可点击
if (count === 0) {
return <span style={{ color: "#999" }}>0</span>;
}
return (
<a
style={{
color: "#1677ff",
fontWeight: 600,
cursor: "pointer",
}}
onClick={() => handleViewDetail(record, type)}
>
{count}
</a>
);
};
return (
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{ name: "corpName", label: "企业名称" },
{
name: "corpName",
label: "企业名称",
},
]}
form={form}
onFinish={getData}
/>
<Table
columns={[
// { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{
title: "企业名称",
dataIndex: "corpName",
width: 300,
ellipsis: true,
render: text => text || "一公司",
width: 200,
render: text => text || "-",
},
{
title: "消防救援队数",
dataIndex: "rescueTeamCount",
width: 140,
width: 150,
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
onClick={() => handleViewDetail(record, "rescueTeam")}
>
{text || 0}
</a>
),
render: (text, record) => renderCountLink(text, record, "rescueTeam"),
},
{
title: "消防控制室数",
dataIndex: "controlRoomCount",
width: 140,
width: 150,
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
onClick={() => handleViewDetail(record, "controlRoom")}
>
{text || 0}
</a>
),
render: (text, record) => renderCountLink(text, record, "controlRoom"),
},
{
title: "消防泵房数",
dataIndex: "pumpRoomCount",
width: 140,
width: 150,
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
onClick={() => handleViewDetail(record, "pumpRoom")}
>
{text || 0}
</a>
),
render: (text, record) => renderCountLink(text, record, "pumpRoom"),
},
{
title: "消防水源数",
dataIndex: "waterSourceCount",
width: 140,
width: 150,
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
onClick={() => handleViewDetail(record, "waterSource")}
>
{text || 0}
</a>
),
render: (text, record) => renderCountLink(text, record, "waterSource"),
},
]}
{...tableProps}