1、修复bug

master
shenzhidan 2026-02-27 08:30:45 +08:00
parent 6dad9b5b43
commit 8dd9cfddd7
16 changed files with 1000 additions and 841 deletions

View File

@ -7,6 +7,7 @@ import "../blessed_by_buddha";
require("antd/dist/reset.css");
require("zy-react-library/css/common.less");
require("./styles/search-actions-right.less");
dayjs.locale("zh-cn");
setJJBCommonAntdMessage(message);

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, Form, Input, InputNumber, message, Row, Space, Table } from "antd";
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";
@ -13,6 +13,20 @@ import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import useUploadFile from "zy-react-library/hooks/useUploadFile";
import { NS_CONTROL_ROOM } from "~/enumerate/namespace";
// 手机号验证正则
const MOBILE_PATTERN = /^1[3-9]\d{9}$/;
// 手机号验证函数
const validatePhone = (rule, value) => {
if (!value) {
return Promise.resolve();
}
if (MOBILE_PATTERN.test(value)) {
return Promise.resolve();
}
return Promise.reject(new Error("请输入正确的手机号"));
};
function Add(props) {
const query = useGetUrlQuery();
const [form] = Form.useForm();
@ -22,10 +36,24 @@ function Add(props) {
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
// 设备信息列表
const [deviceList, setDeviceList] = useState([]);
// 人员信息列表
const [personnelList, setPersonnelList] = useState([]);
// 设备列表
const createEmptyDevice = () => ({
key: `${Date.now()}-${Math.random()}`,
deviceName: "",
deviceModel: "",
deviceQty: undefined,
deviceLocation: "",
});
const [devices, setDevices] = useState([createEmptyDevice()]);
// 人员列表
const createEmptyPerson = () => ({
key: `${Date.now()}-${Math.random()}`,
personName: "",
personPhone: "",
dutyDesc: "",
});
const [persons, setPersons] = useState([createEmptyPerson()]);
// 文件上传相关hooks
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
@ -53,12 +81,33 @@ function Add(props) {
// 设置设备列表
if (data.devices && data.devices.length > 0) {
setDeviceList(data.devices.map((item, index) => ({ ...item, key: item.id || index })));
const deviceList = data.devices.map((item, index) => ({ ...item, key: item.id || index }));
setDevices(deviceList);
// 同步设置Form的设备数据
form.setFieldValue('devicesForm', deviceList.map(d => ({
deviceName: d.deviceName,
deviceModel: d.deviceModel,
deviceQty: d.deviceQty,
deviceLocation: d.deviceLocation,
})));
}
else {
setDevices([createEmptyDevice()]);
}
// 设置人员列表
if (data.persons && data.persons.length > 0) {
setPersonnelList(data.persons.map((item, index) => ({ ...item, key: item.id || index })));
const personList = data.persons.map((item, index) => ({ ...item, key: item.id || index }));
setPersons(personList);
// 同步设置Form的人员数据
form.setFieldValue('personsForm', personList.map(p => ({
personName: p.personName,
personPhone: p.personPhone,
dutyDesc: p.dutyDesc,
})));
}
else {
setPersons([createEmptyPerson()]);
}
}
catch (error) {
@ -85,43 +134,67 @@ function Add(props) {
setMapOpen(false);
};
// 设备相关操作
const addDevice = () => {
const newDevices = [...devices, createEmptyDevice()];
setDevices(newDevices);
// 同步更新Form
const formDevices = form.getFieldValue('devicesForm') || [];
form.setFieldValue('devicesForm', [...formDevices, { deviceName: '', deviceModel: '', deviceQty: undefined, deviceLocation: '' }]);
};
const removeDevice = (key) => {
const index = devices.findIndex(item => item.key === key);
const newDevices = devices.filter(item => item.key !== key);
setDevices(newDevices);
// 同步更新Form
const formDevices = form.getFieldValue('devicesForm') || [];
formDevices.splice(index, 1);
form.setFieldValue('devicesForm', [...formDevices]);
};
const updateDevice = (key, field, value) => {
const index = devices.findIndex(item => item.key === key);
setDevices(
devices.map(item => (item.key === key ? { ...item, [field]: value } : item)),
);
// 同步更新Form并触发校验
form.setFieldValue(['devicesForm', index, field], value);
};
// 人员相关操作
const addPerson = () => {
const newPersons = [...persons, createEmptyPerson()];
setPersons(newPersons);
// 同步更新Form
const formPersons = form.getFieldValue('personsForm') || [];
form.setFieldValue('personsForm', [...formPersons, { personName: '', personPhone: '', dutyDesc: '' }]);
};
const removePerson = (key) => {
if (persons.length === 1) {
message.warning("至少保留一条人员数据");
return;
}
const index = persons.findIndex(item => item.key === key);
const newPersons = persons.filter(item => item.key !== key);
setPersons(newPersons);
// 同步更新Form
const formPersons = form.getFieldValue('personsForm') || [];
formPersons.splice(index, 1);
form.setFieldValue('personsForm', [...formPersons]);
};
const updatePerson = (key, field, value) => {
const index = persons.findIndex(item => item.key === key);
setPersons(
persons.map(item => (item.key === key ? { ...item, [field]: value } : item)),
);
// 同步更新Form并触发校验
form.setFieldValue(['personsForm', index, field], value);
};
const onFinish = async (values) => {
// 验证设备列表
if (deviceList.length === 0) {
message.warning("请至少添加一条设备信息");
return;
}
// 验证人员列表
if (personnelList.length === 0) {
message.warning("请至少添加一条人员信息");
return;
}
// 验证设备列表是否填写完整
const invalidDevice = deviceList.find(
item => !item.deviceName || !item.deviceModel || !item.deviceQty || !item.deviceLocation,
);
if (invalidDevice) {
message.warning("请完善设备信息");
return;
}
// 验证人员列表是否填写完整
const invalidPersonnel = personnelList.find(
item => !item.personName || !item.personPhone,
);
if (invalidPersonnel) {
message.warning("请完善人员信息");
return;
}
// 验证图片是否上传
if (!values.roomImages || values.roomImages.length === 0) {
message.warning("请上传消防控制室图片");
return;
}
setSubmitting(true);
try {
// 先删除标记删除的文件
@ -129,36 +202,42 @@ function Add(props) {
await deleteFile({ single: false, files: deleteFiles });
}
// 上传图片文件获取业务IDroom_id
const { id: roomId } = await uploadFile({
single: false,
files: values.roomImages,
params: {
type: UPLOAD_FILE_TYPE_ENUM[302],
foreignKey: values.roomId,
},
});
let roomId = values.roomId;
if (values.roomImages && values.roomImages.length > 0) {
// 上传图片文件获取业务IDroom_id
const { id: uploadedRoomId } = await uploadFile({
single: false,
files: values.roomImages,
params: {
type: UPLOAD_FILE_TYPE_ENUM[302],
foreignKey: values.roomId,
},
});
roomId = uploadedRoomId;
}
const apiMethod = query.id ? props["controlRoomUpdate"] : props["controlRoomAdd"];
// 构建提交参数
// 过滤掉空的设备信息
const validDevices = devices.filter(
device => device.deviceName || device.deviceModel || device.deviceQty || device.deviceLocation,
);
const params = {
...values,
roomId,
// 设备列表:去掉前端添加的 key
devices: deviceList.map(({ key, ...device }) => ({
devices: validDevices.map(({ key, ...device }) => ({
deviceName: device.deviceName,
deviceModel: device.deviceModel,
deviceQty: device.deviceQty,
deviceLocation: device.deviceLocation,
...(device.id && { id: device.id }),
})),
// 人员列表:去掉前端添加的 key
persons: personnelList.map(({ key, ...personnel }) => ({
personName: personnel.personName,
personPhone: personnel.personPhone,
dutyDesc: personnel.dutyDesc || "",
...(personnel.id && { id: personnel.id }),
persons: persons.map(({ key, ...person }) => ({
personName: person.personName,
personPhone: person.personPhone,
dutyDesc: person.dutyDesc,
...(person.id && { id: person.id }),
})),
};
@ -179,189 +258,19 @@ function Add(props) {
}
};
// 设备列表相关操作
const addDevice = () => {
const newDevice = {
key: Date.now(),
deviceName: "",
deviceModel: "",
deviceQty: null,
deviceLocation: "",
};
setDeviceList([...deviceList, newDevice]);
};
const removeDevice = (key) => {
setDeviceList(deviceList.filter(item => item.key !== key));
};
const updateDevice = (key, field, value) => {
setDeviceList(
deviceList.map(item => (item.key === key ? { ...item, [field]: value } : item)),
);
};
// 人员列表相关操作
const addPersonnel = () => {
const newPersonnel = {
key: Date.now(),
personName: "",
personPhone: "",
dutyDesc: "",
};
setPersonnelList([...personnelList, newPersonnel]);
};
const removePersonnel = (key) => {
setPersonnelList(personnelList.filter(item => item.key !== key));
};
const updatePersonnel = (key, field, value) => {
setPersonnelList(
personnelList.map(item => (item.key === key ? { ...item, [field]: value } : item)),
);
};
// 设备表格列定义
const deviceColumns = [
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备名称
</>),
dataIndex: "deviceName",
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备名称"
onChange={e => updateDevice(record.key, "deviceName", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备型号
</>),
dataIndex: "deviceModel",
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备型号"
onChange={e => updateDevice(record.key, "deviceModel", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备数量
</>),
dataIndex: "deviceQty",
render: (text, record) => (
<InputNumber
value={text}
placeholder="请输入设备数量"
min={1}
style={{ width: "100%" }}
onChange={value => updateDevice(record.key, "deviceQty", value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备位置
</>),
dataIndex: "deviceLocation",
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备位置"
onChange={e => updateDevice(record.key, "deviceLocation", e.target.value)}
/>
),
},
{
title: "操作",
width: 80,
align: "center",
render: (_, record) => (
<Button type="link" danger onClick={() => removeDevice(record.key)}>
删除
</Button>
),
},
];
// 人员表格列定义
const personnelColumns = [
{
title: (<>
<span style={{ color: "red" }}>*</span>
人员姓名
</>),
dataIndex: "personName",
render: (text, record) => (
<Input
value={text}
placeholder="请输入人员姓名"
onChange={e => updatePersonnel(record.key, "personName", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
人员手机号
</>),
dataIndex: "personPhone",
render: (text, record) => (
<Input
value={text}
placeholder="请输入人员手机号"
maxLength={11}
onChange={e => updatePersonnel(record.key, "personPhone", e.target.value)}
/>
),
},
{
title: "人员值班情况",
dataIndex: "dutyDesc",
render: (text, record) => (
<Input
value={text}
placeholder="请输入人员值班情况"
onChange={e => updatePersonnel(record.key, "dutyDesc", e.target.value)}
/>
),
},
{
title: "操作",
width: 80,
align: "center",
render: (_, record) => (
<Button type="link" danger onClick={() => removePersonnel(record.key)}>
删除
</Button>
),
},
];
return (
<Page
headerTitle={query.id ? "编辑消防控制室" : "新增消防控制室"}
loading={loading || uploadFileLoading || deleteFileLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
>
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
{/* 添加隐藏字段保存 roomId */}
<Form.Item name="roomId" hidden>
<Input />
@ -374,7 +283,7 @@ function Add(props) {
name="roomName"
rules={[
{ required: true, message: "请输入消防控制室名称" },
{ max: 100, message: "消防控制室名称不能超过100个字符" },
{ max: 50, message: "消防控制室名称不能超过50个字符" },
]}
>
<Input placeholder="请输入消防控制室名称" />
@ -415,10 +324,17 @@ function Add(props) {
name="principalPhone"
rules={[
{ required: true, message: "请输入负责人手机号" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
{ validator: validatePhone },
]}
>
<Input placeholder="请输入负责人手机号" maxLength={11} />
<Input
placeholder="请输入负责人手机号"
maxLength={11}
onChange={e => {
const value = e.target.value.replace(/\D/g, '');
form.setFieldValue('principalPhone', value);
}}
/>
</Form.Item>
</Col>
</Row>
@ -437,7 +353,7 @@ function Add(props) {
<Col span={12}>
<Form.Item
label="纬度"
required
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
@ -462,14 +378,14 @@ function Add(props) {
name="roomImages"
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防控制室图片" }]}
extra="默认上传4个,目前支持jpg、jpeg、png格式,单张图片不超过5mb"
>
<Upload
fileType="image"
maxCount={4}
maxSize={5}
size={5}
accept=".jpg,.jpeg,.png"
tipContent="默认上限4个且只支持jpg、jpeg、png格式单张且不超过5mb"
listType="picture-card"
onGetRemoveFile={(file) => {
setDeleteFiles([...deleteFiles, file]);
}}
@ -481,41 +397,173 @@ function Add(props) {
<Card
title="设备信息"
style={{ marginTop: 24, boxShadow: 'none' }}
bordered={false}
extra={(
<Button type="primary" onClick={addDevice}>
新增
</Button>
)}
style={{ marginBottom: 24 }}
>
<Table
columns={deviceColumns}
dataSource={deviceList}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无设备信息,请点击新增按钮添加" }}
/>
{devices.map((device, index) => (
<div key={device.key} style={{ marginBottom: 16 }}>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="设备名称"
name={['devicesForm', index, 'deviceName']}
rules={[
{ required: true, message: "请输入设备名称" },
{ max: 50, message: "设备名称不能超过50个字符" },
]}
>
<Input
placeholder="请输入设备名称"
onChange={e => updateDevice(device.key, "deviceName", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="设备型号"
name={['devicesForm', index, 'deviceModel']}
rules={[
{ required: true, message: "请输入设备型号" },
{ max: 50, message: "设备型号不能超过50个字符" },
]}
>
<Input
placeholder="请输入设备型号"
onChange={e => updateDevice(device.key, "deviceModel", e.target.value)}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="设备数量"
name={['devicesForm', index, 'deviceQty']}
rules={[{ required: true, message: "请输入设备数量" }]}
>
<InputNumber
placeholder="请输入设备数量"
min={1}
style={{ width: "100%" }}
onChange={value => updateDevice(device.key, "deviceQty", value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="设备位置"
required
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name={['devicesForm', index, 'deviceLocation']}
rules={[
{ required: true, message: "请输入设备位置" },
{ max: 50, message: "设备位置不能超过50个字符" },
]}
noStyle
>
<Input
placeholder="请输入设备位置"
onChange={e => updateDevice(device.key, "deviceLocation", e.target.value)}
/>
</Form.Item>
<Button danger onClick={() => removeDevice(device.key)}>
删除
</Button>
</Space.Compact>
</Form.Item>
</Col>
</Row>
</div>
))}
</Card>
<Card
title="人员信息"
style={{ marginTop: 24, boxShadow: 'none' }}
bordered={false}
extra={(
<Button type="primary" onClick={addPersonnel}>
<Button type="primary" onClick={addPerson}>
新增
</Button>
)}
style={{ marginBottom: 24 }}
>
<Table
columns={personnelColumns}
dataSource={personnelList}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无人员信息,请点击新增按钮添加" }}
/>
{persons.map((person, index) => (
<div key={person.key} style={{ marginBottom: 16 }}>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="人员姓名"
name={['personsForm', index, 'personName']}
rules={[
{ required: true, message: "请输入人员姓名" },
{ max: 50, message: "人员姓名不能超过50个字符" },
]}
>
<Input
placeholder="请输入人员姓名"
onChange={e => updatePerson(person.key, "personName", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="人员手机号"
name={['personsForm', index, 'personPhone']}
rules={[
{ required: true, message: "请输入人员手机号" },
{ validator: validatePhone },
]}
>
<Input
placeholder="请输入人员手机号"
maxLength={11}
onChange={e => {
const value = e.target.value.replace(/\D/g, '');
updatePerson(person.key, "personPhone", value);
form.setFieldValue(['personsForm', index, 'personPhone'], value);
}}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="人员值班情况"
name={['personsForm', index, 'dutyDesc']}
rules={[
{ required: true, message: "请输入人员值班情况" },
{ max: 50, message: "人员值班情况不能超过50个字符" },
]}
>
<Input
placeholder="请输入人员值班情况"
onChange={e => updatePerson(person.key, "dutyDesc", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<div style={{ textAlign: 'right', paddingTop: 30 }}>
{index > 0 && (
<Button danger onClick={() => removePerson(person.key)}>
删除
</Button>
)}
</div>
</Col>
</Row>
</div>
))}
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center", marginTop: 24 }}>
<Space size={16}>
<Button onClick={() => props.history.goBack()}>
取消

View File

@ -14,8 +14,47 @@ import { NS_CONTROL_ROOM } from "~/enumerate/namespace";
function List(props) {
const [form] = Form.useForm();
const query = useGetUrlQuery();
const normalizeBackPath = (path) => {
if (!path)
return "";
try {
const url = new URL(path, window.location.origin);
const appPrefix = `/${window.process?.env?.appIdentifier || "fireResource"}`;
let pathname = url.pathname;
if (pathname.startsWith(`${appPrefix}/`))
pathname = pathname.slice(appPrefix.length);
else if (pathname === appPrefix)
pathname = "/";
return `${pathname}${url.search}`;
}
catch (error) {
return path;
}
};
const isFromSupervision = !!query.eqCorpId;
const supervisionBackPath = normalizeBackPath(query.backPath
|| props.location?.state?.backPath
|| window.sessionStorage.getItem("supervisionFireResourceStatsBackPath")
|| "");
const pageHistory = isFromSupervision
? {
...props.history,
goBack: () => {
if (supervisionBackPath) {
props.history.push(supervisionBackPath);
return true;
}
window.history.back();
return true;
},
}
: props.history;
const { tableProps, getData } = useTable(props["controlRoomList"], { form });
const { tableProps, getData } = useTable(props["controlRoomList"], {
form,
params: () => (query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}),
});
const handleSearch = values => getData(query.eqCorpId ? { ...values, eqCorpId: query.eqCorpId } : values);
const [deleting, setDeleting] = useState(false);
const [statusDict, setStatusDict] = useState([]);
@ -96,7 +135,11 @@ function List(props) {
};
return (
<Page isShowAllAction={false}>
<Page
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
@ -116,7 +159,8 @@ function List(props) {
},
]}
form={form}
onFinish={getData}
values={query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}}
onFinish={handleSearch}
/>
<Table

View File

@ -93,14 +93,13 @@ function View(props) {
const deviceColumns = [
{
title: "序号",
width: 80,
width: 150,
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "设备名称",
dataIndex: "deviceName",
width: 180,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -108,7 +107,6 @@ function View(props) {
{
title: "设备型号",
dataIndex: "deviceModel",
width: 180,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -116,7 +114,6 @@ function View(props) {
{
title: "设备数量",
dataIndex: "deviceQty",
width: 120,
align: "center",
render: text => text || 0,
},
@ -133,14 +130,14 @@ function View(props) {
const personnelColumns = [
{
title: "序号",
width: 80,
width: 150,
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "人员姓名",
dataIndex: "personName",
width: 160,
width: 420,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -148,7 +145,7 @@ function View(props) {
{
title: "人员手机号",
dataIndex: "personPhone",
width: 180,
width: 420,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -164,13 +161,13 @@ function View(props) {
return (
<Page
headerTitle="查看消防控制室"
loading={loading || dictLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
>
{detail && (
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<div>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
<Descriptions
bordered
column={2}
@ -218,8 +215,9 @@ function View(props) {
/>
</Card>
<Card title="设备信息" style={{ marginBottom: 24 }}>
<Card title="设备信息" style={{ marginTop: 24, boxShadow: 'none' }} bordered={false}>
<Table
bordered
columns={deviceColumns}
dataSource={detail.devices || []}
pagination={false}
@ -228,8 +226,9 @@ function View(props) {
/>
</Card>
<Card title="人员信息" style={{ marginBottom: 24 }}>
<Card title="人员信息" style={{ marginTop: 24, boxShadow: 'none' }} bordered={false}>
<Table
bordered
columns={personnelColumns}
dataSource={detail.persons || []}
pagination={false}
@ -238,7 +237,7 @@ function View(props) {
/>
</Card>
<div style={{ textAlign: "center" }}>
<div style={{ textAlign: "center", marginTop: 24 }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>

View File

@ -52,7 +52,7 @@ function FireResourceStats(props) {
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff", fontWeight: 600 }}
onClick={() => handleViewDetail(record, "rescueTeam")}
>
{text || 0}
@ -66,7 +66,7 @@ function FireResourceStats(props) {
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff", fontWeight: 600 }}
onClick={() => handleViewDetail(record, "controlRoom")}
>
{text || 0}
@ -80,7 +80,7 @@ function FireResourceStats(props) {
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff", fontWeight: 600 }}
onClick={() => handleViewDetail(record, "pumpRoom")}
>
{text || 0}
@ -94,7 +94,7 @@ function FireResourceStats(props) {
align: "center",
render: (text, record) => (
<a
style={{ color: "#1677ff", fontWeight: 600, textDecoration: "underline" }}
style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff", fontWeight: 600 }}
onClick={() => handleViewDetail(record, "waterSource")}
>
{text || 0}
@ -109,3 +109,4 @@ function FireResourceStats(props) {
}
export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats));

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, Form, Input, message, Row, Space, Table } from "antd";
import { Button, Card, Col, Form, Input, 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";
@ -13,6 +13,20 @@ import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import useUploadFile from "zy-react-library/hooks/useUploadFile";
import { NS_PUMP_ROOM } from "~/enumerate/namespace";
// 手机号验证正则
const MOBILE_PATTERN = /^1[3-9]\d{9}$/;
// 手机号验证函数
const validatePhone = (rule, value) => {
if (!value) {
return Promise.resolve();
}
if (MOBILE_PATTERN.test(value)) {
return Promise.resolve();
}
return Promise.reject(new Error("请输入正确的手机号"));
};
function Add(props) {
const query = useGetUrlQuery();
const [form] = Form.useForm();
@ -23,7 +37,16 @@ function Add(props) {
const [mapLat, setMapLat] = useState("");
// 设备信息列表
const [devices, setDeviceList] = useState([]);
const createEmptyDevice = () => ({
key: `${Date.now()}-${Math.random()}`,
deviceCode: "",
deviceName: "",
deviceCategory: "",
chargeUnit: "",
deviceLocation: "",
paramsSpec: "",
});
const [devices, setDeviceList] = useState([createEmptyDevice()]);
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
@ -47,7 +70,19 @@ function Add(props) {
// 设置设备列表
if (data.devices && data.devices.length > 0) {
setDeviceList(data.devices.map((item, index) => ({ ...item, key: item.id || index })));
const deviceList = data.devices.map((item, index) => ({ ...item, key: item.id || index }));
setDeviceList(deviceList);
// 同步设置Form的设备数据
form.setFieldValue('devicesForm', deviceList.map(d => ({
deviceCode: d.deviceCode,
deviceName: d.deviceName,
deviceCategory: d.deviceCategory,
chargeUnit: d.chargeUnit,
deviceLocation: d.deviceLocation,
paramsSpec: d.paramsSpec,
})));
} else {
setDeviceList([createEmptyDevice()]);
}
}
catch (error) {
@ -74,48 +109,37 @@ function Add(props) {
};
const onFinish = async (values) => {
// 验证设备列表
if (devices.length === 0) {
message.warning("请至少添加一条设备信息");
return;
}
// 验证设备列表是否填写完整
const invalidDevice = devices.find(
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("请上传消防泵房图片");
return;
}
setSubmitting(true);
try {
if (deleteFiles.length > 0) {
await deleteFile({ single: false, files: deleteFiles });
}
const { id: pumpRoomId } = await uploadFile({
single: false,
files: values.roomImages,
params: {
type: UPLOAD_FILE_TYPE_ENUM[302],
foreignKey: values.roomId || values.pumpRoomId || query.id,
},
});
let pumpRoomId = values.pumpRoomId || values.roomId || query.id;
if (values.roomImages && values.roomImages.length > 0) {
const { id: uploadedPumpRoomId } = await uploadFile({
single: false,
files: values.roomImages,
params: {
type: UPLOAD_FILE_TYPE_ENUM[302],
foreignKey: values.roomId || values.pumpRoomId || query.id,
},
});
pumpRoomId = uploadedPumpRoomId;
}
const apiMethod = query.id ? props["pumpRoomUpdate"] : props["pumpRoomAdd"];
// 过滤掉空的设备信息
const validDevices = devices.filter(
device => device.deviceCode || device.deviceName || device.deviceCategory ||
device.chargeUnit || device.deviceLocation || device.paramsSpec,
);
const params = {
...values,
pumpRoomId,
devices: devices.map(({ key, ...device }) => ({
devices: validDevices.map(({ key, ...device }) => ({
deviceCode: device.deviceCode,
deviceName: device.deviceName,
deviceCategory: device.deviceCategory,
@ -143,146 +167,52 @@ function Add(props) {
// 设备列表相关操作
const addDevice = () => {
const newDevice = {
key: Date.now(),
deviceCode: "",
deviceName: "",
deviceCategory: "",
chargeUnit: "",
deviceLocation: "",
paramsSpec: "",
};
setDeviceList([...devices, newDevice]);
const newDevices = [...devices, createEmptyDevice()];
setDeviceList(newDevices);
// 同步更新Form
const formDevices = form.getFieldValue('devicesForm') || [];
form.setFieldValue('devicesForm', [...formDevices, {
deviceCode: '',
deviceName: '',
deviceCategory: '',
chargeUnit: '',
deviceLocation: '',
paramsSpec: ''
}]);
};
const removeDevice = (key) => {
setDeviceList(devices.filter(item => item.key !== key));
const index = devices.findIndex(item => item.key === key);
const newDevices = devices.filter(item => item.key !== key);
setDeviceList(newDevices);
// 同步更新Form
const formDevices = form.getFieldValue('devicesForm') || [];
formDevices.splice(index, 1);
form.setFieldValue('devicesForm', [...formDevices]);
};
const updateDevice = (key, field, value) => {
const index = devices.findIndex(item => item.key === key);
setDeviceList(
devices.map(item => (item.key === key ? { ...item, [field]: value } : item)),
);
// 同步更新Form并触发校验
form.setFieldValue(['devicesForm', index, field], value);
};
// 设备表格列定义
const deviceColumns = [
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备编号
</>),
dataIndex: "deviceCode",
width: 150,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备编号"
onChange={e => updateDevice(record.key, "deviceCode", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备名称
</>),
dataIndex: "deviceName",
width: 150,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备名称"
onChange={e => updateDevice(record.key, "deviceName", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
设备分类
</>),
dataIndex: "deviceCategory",
width: 150,
render: (text, record) => (
<Input
value={text}
placeholder="请输入设备分类"
onChange={e => updateDevice(record.key, "deviceCategory", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
负责单位
</>),
dataIndex: "chargeUnit",
width: 150,
render: (text, record) => (
<Input
value={text}
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="请输入具体位置"
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: 100,
align: "center",
render: (_, record) => (
<Button type="link" danger onClick={() => removeDevice(record.key)}>
删除
</Button>
),
},
];
return (
<Page
headerTitle={query.id ? "编辑消防泵房" : "新增消防泵房"}
loading={loading || uploadFileLoading || deleteFileLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
>
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
<Form.Item name="pumpRoomId" hidden>
<Input />
</Form.Item>
@ -294,7 +224,7 @@ function Add(props) {
name="pumpRoomName"
rules={[
{ required: true, message: "请输入消防泵房名称" },
{ max: 100, message: "消防泵房名称不能超过100个字符" },
{ max: 50, message: "消防泵房名称不能超过50个字符" },
]}
>
<Input placeholder="请输入消防泵房名称" />
@ -335,10 +265,17 @@ function Add(props) {
name="principalPhone"
rules={[
{ required: true, message: "请输入负责人手机号" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
{ validator: validatePhone },
]}
>
<Input placeholder="请输入负责人手机号" maxLength={11} />
<Input
placeholder="请输入负责人手机号"
maxLength={11}
onChange={e => {
const value = e.target.value.replace(/\D/g, '');
form.setFieldValue('principalPhone', value);
}}
/>
</Form.Item>
</Col>
</Row>
@ -357,7 +294,7 @@ function Add(props) {
<Col span={12}>
<Form.Item
label="纬度"
required
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
@ -382,14 +319,13 @@ function Add(props) {
name="roomImages"
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防泵房图片" }]}
extra="默认上传4个,目前支持jpg、jpeg、png格式,单张图片不超过5mb"
>
<Upload
fileType="image"
maxCount={4}
maxSize={5}
size={5}
accept=".jpg,.jpeg,.png"
tipContent="默认上限4个且只支持jpg、jpeg、png格式单张且不超过5mb"
onGetRemoveFile={(file) => {
setDeleteFiles([...deleteFiles, file]);
}}
@ -406,18 +342,122 @@ function Add(props) {
新增
</Button>
)}
style={{ marginBottom: 24 }}
style={{ marginTop: 24, boxShadow: 'none' }}
bordered={false}
>
<Table
columns={deviceColumns}
dataSource={devices}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无设备信息,请点击新增按钮添加" }}
/>
{devices.map((device, index) => (
<div key={device.key} style={{ marginBottom: 16 }}>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="设备编号"
name={['devicesForm', index, 'deviceCode']}
rules={[
{ required: true, message: "请输入设备编号" },
{ max: 50, message: "设备编号不能超过50个字符" },
]}
>
<Input
placeholder="请输入设备编号"
onChange={e => updateDevice(device.key, "deviceCode", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="设备名称"
name={['devicesForm', index, 'deviceName']}
rules={[
{ required: true, message: "请输入设备名称" },
{ max: 50, message: "设备名称不能超过50个字符" },
]}
>
<Input
placeholder="请输入设备名称"
onChange={e => updateDevice(device.key, "deviceName", e.target.value)}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="设备分类"
name={['devicesForm', index, 'deviceCategory']}
rules={[
{ required: true, message: "请输入设备分类" },
{ max: 50, message: "设备分类不能超过50个字符" },
]}
>
<Input
placeholder="请输入设备分类"
onChange={e => updateDevice(device.key, "deviceCategory", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="负责单位"
name={['devicesForm', index, 'chargeUnit']}
rules={[
{ required: true, message: "请输入负责单位" },
{ max: 50, message: "负责单位不能超过50个字符" },
]}
>
<Input
placeholder="请输入负责单位"
onChange={e => updateDevice(device.key, "chargeUnit", e.target.value)}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="具体位置"
name={['devicesForm', index, 'deviceLocation']}
rules={[
{ required: true, message: "请输入具体位置" },
{ max: 50, message: "具体位置不能超过50个字符" },
]}
>
<Input
placeholder="请输入具体位置"
onChange={e => updateDevice(device.key, "deviceLocation", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="设备参数和规格"
required
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name={['devicesForm', index, 'paramsSpec']}
rules={[
{ required: true, message: "请输入设备参数和规格" },
{ max: 50, message: "设备参数和规格不能超过50个字符" },
]}
noStyle
>
<Input
placeholder="请输入设备参数和规格"
onChange={e => updateDevice(device.key, "paramsSpec", e.target.value)}
/>
</Form.Item>
<Button danger onClick={() => removeDevice(device.key)}>
删除
</Button>
</Space.Compact>
</Form.Item>
</Col>
</Row>
</div>
))}
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center", marginTop: 24 }}>
<Space size={16}>
<Button onClick={() => props.history.goBack()}>
取消

View File

@ -1,4 +1,4 @@
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, Form, message, Modal, Space } from "antd";
import { useEffect, useState } from "react";
@ -15,7 +15,47 @@ function List(props) {
const [form] = Form.useForm();
const query = useGetUrlQuery();
const { tableProps, getData } = useTable(props["pumpRoomList"], { form });
const normalizeBackPath = (path) => {
if (!path) return "";
try {
const url = new URL(path, window.location.origin);
const appPrefix = `/${window.process?.env?.appIdentifier || "fireResource"}`;
let pathname = url.pathname;
if (pathname.startsWith(`${appPrefix}/`)) pathname = pathname.slice(appPrefix.length);
else if (pathname === appPrefix) pathname = "/";
return `${pathname}${url.search}`;
} catch (error) {
return path;
}
};
const isFromSupervision = !!query.eqCorpId;
const supervisionBackPath = normalizeBackPath(
query.backPath
|| props.location?.state?.backPath
|| window.sessionStorage.getItem("supervisionFireResourceStatsBackPath")
|| "",
);
const pageHistory = isFromSupervision
? {
...props.history,
goBack: () => {
if (supervisionBackPath) {
props.history.push(supervisionBackPath);
return true;
}
window.history.back();
return true;
},
}
: props.history;
const { tableProps, getData } = useTable(props["pumpRoomList"], {
form,
params: () => (query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}),
});
const handleSearch = values => getData(query.eqCorpId ? { ...values, eqCorpId: query.eqCorpId } : values);
const [deleting, setDeleting] = useState(false);
const [statusDict, setStatusDict] = useState([]);
@ -23,19 +63,15 @@ function List(props) {
const { getDictionary } = useDictionary();
// 一次性初始化字典和表单
useEffect(() => {
const init = async () => {
// 加载字典
try {
const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" });
setStatusDict(Array.isArray(dict) ? dict : []);
}
catch (error) {
} catch (error) {
setStatusDict([]);
}
// 设置表单初始值并加载数据
if (query.eqCorpId) {
form.setFieldsValue({ eqCorpId: query.eqCorpId });
}
@ -44,12 +80,9 @@ function List(props) {
setInitialized(true);
};
if (!initialized) {
init();
}
if (!initialized) init();
}, []);
// 监听 eqCorpId 变化
useEffect(() => {
if (initialized && query.eqCorpId) {
const currentCorpId = form.getFieldValue("eqCorpId");
@ -84,11 +117,9 @@ function List(props) {
await props["pumpRoomDelete"]({ id });
message.success("删除成功");
getData();
}
catch (error) {
} catch (error) {
message.error("删除失败");
}
finally {
} finally {
setDeleting(false);
}
},
@ -96,109 +127,41 @@ function List(props) {
};
return (
<Page isShowAllAction={false}>
<Page isShowAllAction={isFromSupervision} isShowFooter={false} history={pageHistory}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{
name: "likePumpRoomName",
label: "消防泵房名称",
},
{
name: "eqPumpRoomStatus",
label: "消防泵房状态",
render: (<DictionarySelect dictValue="fire_resource_contro_root_type" />),
},
{
name: "eqCorpId",
onlyForLabel: true,
},
{ name: "likePumpRoomName", label: "消防泵房名称" },
{ name: "eqPumpRoomStatus", label: "消防泵房状态", render: (<DictionarySelect dictValue="fire_resource_contro_root_type" />) },
{ name: "eqCorpId", onlyForLabel: true },
]}
form={form}
onFinish={getData}
values={query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}}
onFinish={handleSearch}
/>
<Table
toolBarRender={() => (
<Space>
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
</Space>
)}
columns={[
{
title: "消防泵房名称",
dataIndex: "pumpRoomName",
width: 200,
ellipsis: true,
},
{
title: "消防泵房状态",
width: 150,
align: "center",
ellipsis: true,
render: (_, record) => getStatusLabel(record),
},
{
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: "pumpRoomName", width: 200, ellipsis: true },
{ title: "消防泵房状态", width: 150, align: "center", ellipsis: true, render: (_, record) => getStatusLabel(record) },
{ 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: "操作",
width: 200,
align: "center",
render: (_, record) => (
<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)}
>
删除
</Button>
<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)}>删除</Button>
</Space>
),
},

View File

@ -103,7 +103,6 @@ function View(props) {
{
title: "设备编号",
dataIndex: "deviceCode",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -111,7 +110,6 @@ function View(props) {
{
title: "设备名称",
dataIndex: "deviceName",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -119,7 +117,6 @@ function View(props) {
{
title: "设备分类",
dataIndex: "deviceCategory",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -127,7 +124,6 @@ function View(props) {
{
title: "负责单位",
dataIndex: "chargeUnit",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -135,7 +131,6 @@ function View(props) {
{
title: "具体位置",
dataIndex: "deviceLocation",
width: 150,
align: "center",
ellipsis: true,
render: text => text || "-",
@ -151,13 +146,13 @@ function View(props) {
return (
<Page
headerTitle="查看消防泵房"
loading={loading || getFileLoading}
isShowFooter={false}
isShowBack={false}
>
{detail && (
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<div>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
<Descriptions
bordered
column={2}
@ -206,18 +201,18 @@ function View(props) {
/>
</Card>
<Card title="设备信息" style={{ marginBottom: 24 }}>
<Card title="设备信息" style={{ marginTop: 24, boxShadow: 'none' }} bordered={false}>
<Table
bordered
columns={deviceColumns}
dataSource={detail.devices || []}
pagination={false}
rowKey={(record, index) => record.id || `device-${index}`}
scroll={{ x: 1000 }}
locale={{ emptyText: "暂无设备信息" }}
/>
</Card>
<div style={{ textAlign: "center" }}>
<div style={{ textAlign: "center", marginTop: 24 }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>

View File

@ -1,6 +1,6 @@
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, DatePicker, Form, Input, message, Row, Space, Table } from "antd";
import { Button, Card, Col, DatePicker, Form, Input, message, Row, Space } from "antd";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import Page from "zy-react-library/components/Page";
@ -8,6 +8,22 @@ import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import { NS_RESCUE_TEAM } from "~/enumerate/namespace";
// 手机号验证正则
const MOBILE_PATTERN = /^1[3-9]\d{9}$/;
// 固话验证正则(支持区号-号码格式023-12345678 或 直接号码)
const LANDLINE_PATTERN = /^(\d{3,4}-?)?\d{7,8}$/;
// 手机号或固话验证函数
const validatePhone = (rule, value) => {
if (!value) {
return Promise.resolve();
}
if (MOBILE_PATTERN.test(value) || LANDLINE_PATTERN.test(value)) {
return Promise.resolve();
}
return Promise.reject(new Error("请输入正确的手机号或固话"));
};
function Add(props) {
const query = useGetUrlQuery();
const [form] = Form.useForm();
@ -15,7 +31,14 @@ function Add(props) {
const [submitting, setSubmitting] = useState(false);
// 消防队员列表
const [rescueMembers, setRescueMembers] = useState([]);
const createEmptyMember = () => ({
key: `${Date.now()}-${Math.random()}`,
personName: "",
personPhone: "",
dutyDesc: "",
roleCode: 1,
});
const [rescueMembers, setRescueMembers] = useState([createEmptyMember()]);
// 添加状态保存字典显示名称
const [teamTypeName, setTeamTypeName] = useState("");
@ -43,7 +66,16 @@ function Add(props) {
// 设置消防队员列表
if (data.rescueMembers && data.rescueMembers.length > 0) {
setRescueMembers(data.rescueMembers.map((item, index) => ({ ...item, key: item.id || index })));
const members = data.rescueMembers.map((item, index) => ({ ...item, key: item.id || index }));
setRescueMembers(members);
// 同步设置Form的队员数据
form.setFieldValue('rescueMembersForm', members.map(m => ({
personName: m.personName,
personPhone: m.personPhone,
})));
}
else {
setRescueMembers([createEmptyMember()]);
}
}
catch (error) {
@ -65,15 +97,6 @@ function Add(props) {
return;
}
// 验证消防队员必填项
const invalidMember = rescueMembers.find(
item => !item.personName || !item.personPhone,
);
if (invalidMember) {
message.warning("请完善消防队员信息");
return;
}
setSubmitting(true);
try {
const apiMethod = query.id ? props["rescueTeamUpdate"] : props["rescueTeamAdd"];
@ -119,18 +142,21 @@ function Add(props) {
// 消防队员相关操作
const addMember = () => {
const newMember = {
key: Date.now(),
personName: "",
personPhone: "",
dutyDesc: "",
roleCode: 1,
};
setRescueMembers([...rescueMembers, newMember]);
const newMembers = [...rescueMembers, createEmptyMember()];
setRescueMembers(newMembers);
// 同步更新Form
const formMembers = form.getFieldValue('rescueMembersForm') || [];
form.setFieldValue('rescueMembersForm', [...formMembers, { personName: '', personPhone: '' }]);
};
const removeMember = (key) => {
setRescueMembers(rescueMembers.filter(item => item.key !== key));
const index = rescueMembers.findIndex(item => item.key === key);
const newMembers = rescueMembers.filter(item => item.key !== key);
setRescueMembers(newMembers);
// 同步更新Form
const formMembers = form.getFieldValue('rescueMembersForm') || [];
formMembers.splice(index, 1);
form.setFieldValue('rescueMembersForm', [...formMembers]);
};
const updateMember = (key, field, value) => {
@ -139,63 +165,20 @@ function Add(props) {
);
};
// 消防队员表格列定义
const memberColumns = [
{
title: (<>
<span style={{ color: "red" }}>*</span>
队员姓名
</>),
dataIndex: "personName",
render: (text, record) => (
<Input
value={text}
placeholder="请输入队员姓名"
onChange={e => updateMember(record.key, "personName", e.target.value)}
/>
),
},
{
title: (<>
<span style={{ color: "red" }}>*</span>
队员电话
</>),
dataIndex: "personPhone",
render: (text, record) => (
<Input
value={text}
placeholder="请输入队员电话"
maxLength={11}
onChange={e => updateMember(record.key, "personPhone", e.target.value)}
/>
),
},
{
title: "操作",
width: 80,
align: "center",
render: (_, record) => (
<Button type="link" danger onClick={() => removeMember(record.key)}>
删除
</Button>
),
},
];
return (
<Page
headerTitle={query.id ? "编辑救援队" : "新增救援队"}
loading={loading}
isShowFooter={false}
isShowBack={false}
>
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Card title="基本信息" bordered={false}>
<Form.Item name="teamId" hidden>
<Input />
</Form.Item>
@ -210,7 +193,7 @@ function Add(props) {
wrapperCol={{ span: 21 }}
rules={[
{ required: true, message: "请输入救援队名称" },
{ max: 100, message: "救援队名称不能超过100个字符" },
{ max: 50, message: "救援队名称不能超过50个字符" },
]}
>
<Input placeholder="请输入救援队名称" />
@ -242,7 +225,7 @@ function Add(props) {
name="chargeOrgDept"
rules={[
{ required: true, message: "请输入负责人单位或部门" },
{ max: 200, message: "负责人单位或部门不能超过200个字符" },
{ max: 50, message: "负责人单位或部门不能超过50个字符" },
]}
>
<Input placeholder="请输入负责人单位或部门" />
@ -270,11 +253,18 @@ function Add(props) {
label="队长电话"
name="captainPhone"
rules={[
{ required: true, message: "请输入队长电话" },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" },
{ validator: validatePhone },
]}
>
<Input placeholder="请输入队长电话" maxLength={11} />
<Input
placeholder="请输入队长电话"
maxLength={20}
onChange={e => {
// 只允许输入数字和连字符
const value = e.target.value.replace(/[^\d-]/g, '');
form.setFieldValue('captainPhone', value);
}}
/>
</Form.Item>
</Col>
</Row>
@ -298,7 +288,6 @@ function Add(props) {
<Form.Item
label="建立日期"
name="establishDate"
rules={[{ required: true, message: "请选择建立日期" }]}
>
<DatePicker
placeholder="请选择日期"
@ -332,8 +321,7 @@ function Add(props) {
label="职责和任务范围"
name="dutyScope"
rules={[
{ required: true, message: "请输入职责和任务范围" },
{ max: 500, message: "职责和任务范围不能超过500个字符" },
{ max: 50, message: "职责和任务范围不能超过50个字符" },
]}
>
<Input placeholder="请输入职责和任务范围" />
@ -349,18 +337,66 @@ function Add(props) {
新增
</Button>
)}
style={{ marginBottom: 24 }}
style={{ marginTop: 24 }}
bordered={false}
>
<Table
columns={memberColumns}
dataSource={rescueMembers}
pagination={false}
rowKey="key"
locale={{ emptyText: "暂无队员信息,请点击新增按钮添加" }}
/>
{rescueMembers.map((member, index) => (
<Row gutter={24} key={member.key} style={{ marginBottom: 16 }}>
<Col span={12}>
<Form.Item
label={`队员${index + 1}`}
name={['rescueMembersForm', index, 'personName']}
rules={[
{ required: true, message: "请输入队员姓名" },
{ max: 50, message: "队员姓名不能超过50个字符" },
]}
>
<Input
placeholder="请输入队员姓名"
onChange={e => updateMember(member.key, "personName", e.target.value)}
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={`队员${index + 1}电话`}
required
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
name={['rescueMembersForm', index, 'personPhone']}
rules={[
{ required: true, message: "请输入队员电话" },
{ validator: validatePhone },
]}
noStyle
>
<Input
placeholder="请输入队员电话"
maxLength={20}
onChange={e => {
const value = e.target.value.replace(/[^\d-]/g, '');
updateMember(member.key, "personPhone", value);
form.setFieldValue(['rescueMembersForm', index, 'personPhone'], value);
}}
/>
</Form.Item>
{index !== 0 && (
<Button
danger
onClick={() => removeMember(member.key)}
>
删除
</Button>
)}
</Space.Compact>
</Form.Item>
</Col>
</Row>
))}
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center", marginTop: 24 }}>
<Space size={16}>
<Button onClick={() => props.history.goBack()}>
取消

View File

@ -1,4 +1,4 @@
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, Form, message, Modal, Space } from "antd";
import { useEffect, useState } from "react";
@ -14,12 +14,51 @@ function List(props) {
const [form] = Form.useForm();
const query = useGetUrlQuery();
const { tableProps, getData } = useTable(props["rescueTeamList"], { form });
const normalizeBackPath = (path) => {
if (!path) return "";
try {
const url = new URL(path, window.location.origin);
const appPrefix = `/${window.process?.env?.appIdentifier || "fireResource"}`;
let pathname = url.pathname;
if (pathname.startsWith(`${appPrefix}/`)) pathname = pathname.slice(appPrefix.length);
else if (pathname === appPrefix) pathname = "/";
return `${pathname}${url.search}`;
} catch (error) {
return path;
}
};
const isFromSupervision = !!query.eqCorpId;
const supervisionBackPath = normalizeBackPath(
query.backPath
|| props.location?.state?.backPath
|| window.sessionStorage.getItem("supervisionFireResourceStatsBackPath")
|| "",
);
const pageHistory = isFromSupervision
? {
...props.history,
goBack: () => {
if (supervisionBackPath) {
props.history.push(supervisionBackPath);
return true;
}
window.history.back();
return true;
},
}
: props.history;
const { tableProps, getData } = useTable(props["rescueTeamList"], {
form,
params: () => (query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}),
});
const handleSearch = values => getData(query.eqCorpId ? { ...values, eqCorpId: query.eqCorpId } : values);
const [deleting, setDeleting] = useState(false);
const [initialized, setInitialized] = useState(false);
// 一次性初始化表单
useEffect(() => {
if (!initialized) {
if (query.eqCorpId) {
@ -30,7 +69,6 @@ function List(props) {
}
}, []);
// 监听 eqCorpId 变化
useEffect(() => {
if (initialized && query.eqCorpId) {
const currentCorpId = form.getFieldValue("eqCorpId");
@ -58,11 +96,9 @@ function List(props) {
await props["rescueTeamDelete"]({ id });
message.success("删除成功");
getData();
}
catch (error) {
} catch (error) {
message.error("删除失败");
}
finally {
} finally {
setDeleting(false);
}
},
@ -70,136 +106,46 @@ function List(props) {
};
return (
<Page isShowAllAction={false}>
<Page isShowAllAction={isFromSupervision} isShowFooter={false} history={pageHistory}>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={[
{
name: "likeTeamName",
label: "救援队名称",
},
{
name: "eqTeamType",
label: "类型",
render: (<DictionarySelect dictValue="fire_resource_team_type" />),
},
{
name: "likeChargeOrgDept",
label: "负责人单位或部门",
},
{
name: "likeCaptainName",
label: "队长",
},
{
name: "eqRegionScope",
label: "所属区域或范围",
render: (<DictionarySelect dictValue="fire_resource_area_scope" />),
},
{
name: "eqCorpId",
onlyForLabel: true,
},
{ name: "likeTeamName", label: "救援队名称" },
{ name: "eqTeamType", label: "类型", render: (<DictionarySelect dictValue="fire_resource_team_type" />) },
{ name: "likeChargeOrgDept", label: "负责人单位或部门" },
{ name: "likeCaptainName", label: "队长" },
{ name: "eqRegionScope", label: "所属区域或范围", render: (<DictionarySelect dictValue="fire_resource_area_scope" />) },
{ name: "eqCorpId", onlyForLabel: true },
]}
form={form}
onFinish={getData}
values={query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}}
onFinish={handleSearch}
/>
<Table
toolBarRender={() => (
<Space>
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
</Space>
)}
columns={[
{
title: "救援队名称",
dataIndex: "teamName",
width: 200,
ellipsis: true,
},
{
title: "类型",
dataIndex: "teamTypeName",
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: "teamName", width: 200, ellipsis: true },
{ title: "类型", dataIndex: "teamTypeName", 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: "操作",
width: 200,
align: "center",
render: (_, record) => (
<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)}
>
删除
</Button>
<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)}>删除</Button>
</Space>
),
},

View File

@ -33,31 +33,35 @@ function View(props) {
const memberColumns = [
{
title: "序号",
width: 80,
width: 10,
align: "center",
render: (_, __, index) => index + 1,
},
{
title: "队员姓名",
title: "队员",
dataIndex: "personName",
align: "center",
width: 140,
render: text => text || "-",
},
{
title: "队员电话",
dataIndex: "personPhone",
align: "center",
width: 140,
render: text => text || "-",
},
];
return (
<Page
headerTitle="查看救援队"
loading={loading}
isShowFooter={false}
isShowBack={false}
>
{detail && (
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<div>
<Card title="基本信息" bordered={false}>
<Descriptions
bordered
column={2}
@ -109,8 +113,9 @@ function View(props) {
/>
</Card>
<Card title="队员信息" style={{ marginBottom: 24 }}>
<Card title="队员信息" style={{ marginTop: 24 }} bordered={false}>
<Table
bordered
columns={memberColumns}
dataSource={detail.rescueMembers || []}
pagination={false}
@ -119,7 +124,7 @@ function View(props) {
/>
</Card>
<div style={{ textAlign: "center" }}>
<div style={{ textAlign: "center", marginTop: 24 }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>

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, Form, Input, InputNumber, message, Row, Space } from "antd";
import { Button, Card, Col, Form, Input, 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";
@ -66,18 +66,17 @@ function Add(props) {
return (
<Page
headerTitle={query.id ? "编辑消防水源" : "新增消防水源"}
loading={loading}
isShowFooter={false}
isShowBack={false}
>
<Form
form={form}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
onFinish={onFinish}
style={{ maxWidth: 1200, margin: "24px auto" }}
>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
<Row gutter={24}>
<Col span={12}>
<Form.Item
@ -85,7 +84,7 @@ function Add(props) {
name="waterSourceName"
rules={[
{ required: true, message: "请输入消防水源名称" },
{ max: 100, message: "消防水源名称不能超过100个字符" },
{ max: 50, message: "消防水源名称不能超过50个字符" },
]}
>
<Input placeholder="请输入消防水源名称" />
@ -120,7 +119,7 @@ function Add(props) {
<Col span={12}>
<Form.Item
label="纬度"
required
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item
@ -145,7 +144,7 @@ function Add(props) {
name="belongOrgDept"
rules={[
{ required: true, message: "请输入所属单位或部门" },
{ max: 200, message: "所属单位或部门不能超过200个字符" },
{ max: 50, message: "所属单位或部门不能超过50个字符" },
]}
>
<Input placeholder="请输入所属单位或部门" />
@ -158,7 +157,7 @@ function Add(props) {
name="waterLocation"
rules={[
{ required: true, message: "请输入水源位置" },
{ max: 200, message: "水源位置不能超过200个字符" },
{ max: 50, message: "水源位置不能超过50个字符" },
]}
>
<Input placeholder="请输入水源位置" />
@ -171,7 +170,10 @@ function Add(props) {
<Form.Item
label="接口形式"
name="interfaceForm"
rules={[{ required: true, message: "请输入接口形式" }]}
rules={[
{ required: true, message: "请输入接口形式" },
{ max: 50, message: "接口形式不能超过50个字符" },
]}
>
<Input placeholder="请输入接口形式" />
</Form.Item>
@ -181,7 +183,10 @@ function Add(props) {
<Form.Item
label="水源类型"
name="waterType"
rules={[{ required: true, message: "请输入水源类型" }]}
rules={[
{ required: true, message: "请输入水源类型" },
{ max: 50, message: "水源类型不能超过50个字符" },
]}
>
<Input placeholder="请输入水源类型" />
</Form.Item>
@ -193,7 +198,10 @@ function Add(props) {
<Form.Item
label="水源编号"
name="waterCode"
rules={[{ required: true, message: "请输入水源编号" }]}
rules={[
{ required: true, message: "请输入水源编号" },
{ max: 50, message: "水源编号不能超过50个字符" },
]}
>
<Input placeholder="请输入水源编号" />
</Form.Item>
@ -205,11 +213,7 @@ function Add(props) {
name="suctionSpec"
rules={[{ required: true, message: "请输入吸水口规格" }]}
>
<InputNumber
placeholder="请输入吸水口规格"
style={{ width: "100%" }}
min={0}
/>
<Input placeholder="请输入吸水口规格" />
</Form.Item>
</Col>
</Row>
@ -219,7 +223,10 @@ function Add(props) {
<Form.Item
label="水源容量"
name="capacity"
rules={[{ required: true, message: "请输入水源容量" }]}
rules={[
{ required: true, message: "请输入水源容量" },
{ max: 50, message: "水源容量不能超过50个字符" },
]}
>
<Input placeholder="请输入水源容量" />
</Form.Item>
@ -229,7 +236,10 @@ function Add(props) {
<Form.Item
label="供水能力"
name="supplyAbility"
rules={[{ required: true, message: "请输入供水能力" }]}
rules={[
{ required: true, message: "请输入供水能力" },
{ max: 50, message: "供水能力不能超过50个字符" },
]}
>
<Input placeholder="请输入供水能力" />
</Form.Item>
@ -241,7 +251,10 @@ function Add(props) {
<Form.Item
label="设备清单"
name="equipmentList"
rules={[{ required: true, message: "请输入设备清单" }]}
rules={[
{ required: true, message: "请输入设备清单" },
{ max: 50, message: "设备清单不能超过50个字符" },
]}
>
<Input placeholder="请输入设备清单" />
</Form.Item>
@ -249,7 +262,7 @@ function Add(props) {
</Row>
</Card>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center" }}>
<Form.Item wrapperCol={{ span: 24 }} style={{ textAlign: "center", marginTop: 24 }}>
<Space size={16}>
<Button onClick={() => props.history.goBack()}>
取消

View File

@ -14,12 +14,48 @@ import { NS_WATER_SOURCE } from "~/enumerate/namespace";
function List(props) {
const [form] = Form.useForm();
const query = useGetUrlQuery();
const normalizeBackPath = (path) => {
if (!path)
return "";
try {
const url = new URL(path, window.location.origin);
const appPrefix = `/${window.process?.env?.appIdentifier || "fireResource"}`;
let pathname = url.pathname;
if (pathname.startsWith(`${appPrefix}/`))
pathname = pathname.slice(appPrefix.length);
else if (pathname === appPrefix)
pathname = "/";
return `${pathname}${url.search}`;
}
catch (error) {
return path;
}
};
const isFromSupervision = !!query.eqCorpId;
const supervisionBackPath = normalizeBackPath(query.backPath
|| props.location?.state?.backPath
|| window.sessionStorage.getItem("supervisionFireResourceStatsBackPath")
|| "");
const pageHistory = isFromSupervision
? {
...props.history,
goBack: () => {
if (supervisionBackPath) {
props.history.push(supervisionBackPath);
return true;
}
window.history.back();
return true;
},
}
: props.history;
const { tableProps, getData } = useTable(props["waterSourceList"], {
form,
params: () => (query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}),
useStorageQueryCriteria: false,
});
const handleSearch = values => getData(query.eqCorpId ? { ...values, eqCorpId: query.eqCorpId } : values);
const [deleting, setDeleting] = useState(false);
const corpIdRef = useRef(query.eqCorpId);
@ -107,13 +143,18 @@ function List(props) {
};
return (
<Page isShowAllAction={false}>
<Page
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
options={searchOptions}
form={form}
onFinish={getData}
values={query.eqCorpId ? { eqCorpId: query.eqCorpId } : {}}
onFinish={handleSearch}
/>
<Table

View File

@ -55,13 +55,13 @@ function View(props) {
return (
<Page
headerTitle="查看消防水源"
loading={loading}
isShowFooter={false}
isShowBack={false}
>
{detail && (
<div style={{ maxWidth: 1200, margin: "24px auto" }}>
<Card title="基本信息" style={{ marginBottom: 24 }}>
<div>
<Card title="基本信息" bordered={false} style={{ boxShadow: 'none' }}>
<Descriptions
bordered
column={2}
@ -128,7 +128,7 @@ function View(props) {
/>
</Card>
<div style={{ textAlign: "center" }}>
<div style={{ textAlign: "center", marginTop: 24 }}>
<Button onClick={() => props.history.goBack()}>
返回
</Button>

View File

@ -1,4 +1,4 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Form } from "antd";
import Page from "zy-react-library/components/Page";
@ -13,20 +13,58 @@ function FireResourceStats(props) {
const { tableProps, getData } = useTable(props["fireResourceStatsList"], { form });
const handleViewDetail = (record, type) => {
// 跳转到对应的详情列表页面
const routeMap = {
rescueTeam: "/container/branchCompany/rescueTeam/list",
controlRoom: "/container/branchCompany/controlRoom/list",
pumpRoom: "/container/branchCompany/pumpRoom/list",
waterSource: "/container/branchCompany/waterSource/list",
};
if (routeMap[type]) {
const corpId = record.corpId || record.companyId || "";
props.history.push(`${routeMap[type]}?corpId=${corpId}`);
const backPath = `${props.location?.pathname || window.location.pathname}${props.location?.search || window.location.search || ""}`;
window.sessionStorage.setItem("supervisionFireResourceStatsBackPath", backPath);
props.history.push({
pathname: routeMap[type],
search: `?eqCorpId=${corpId}&backPath=${encodeURIComponent(backPath)}`,
state: { backPath },
});
}
};
const renderCountLink = (text, record, type) => {
const fieldMap = {
rescueTeam: "rescueTeamCount",
controlRoom: "controlRoomCount",
pumpRoom: "pumpRoomCount",
waterSource: "waterSourceCount",
};
const rawCount = text ?? record?.[fieldMap[type]] ?? 0;
const count = rawCount === "" ? 0 : rawCount;
const isZero = count === 0 || count === "0";
if (isZero) {
return <span style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff" }}>0</span>;
}
return (
<span
role="button"
tabIndex={0}
style={{ color: "#1677ff", fontWeight: 600, WebkitTextFillColor: "#1677ff" }}
onClick={() => handleViewDetail(record, type)}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleViewDetail(record, type);
}
}}
>
{count}
</span>
);
};
return (
<Page isShowAllAction={false}>
<Search
@ -40,67 +78,39 @@ function FireResourceStats(props) {
<Table
columns={[
{ title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 },
{
title: "企业名称",
{
title: "企业名称",
dataIndex: "companyName",
ellipsis: true,
render: (text) => text || "一公司",
render: text => text || "一公司",
},
{
title: "消防救援队数",
{
title: "消防救援队数",
dataIndex: "rescueTeamCount",
width: 140,
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: "消防控制室数",
{
title: "消防控制室数",
dataIndex: "controlRoomCount",
width: 140,
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: "消防泵房数",
{
title: "消防泵房数",
dataIndex: "pumpRoomCount",
width: 140,
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: "消防水源数",
{
title: "消防水源数",
dataIndex: "waterSourceCount",
width: 140,
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}
@ -110,3 +120,4 @@ function FireResourceStats(props) {
}
export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats));

View File

@ -30,22 +30,37 @@ function FireResourceStats(props) {
const renderCountLink = (text, record, type) => {
const count = text || 0;
// 如果数量为0只显示数字不可点击
// 数量为0也保持蓝色展示
if (count === 0) {
return <span style={{ color: "#999" }}>0</span>;
return (
<span
style={{ color: "#1677ff", WebkitTextFillColor: "#1677ff", fontWeight: 600 }}
>
0
</span>
);
}
return (
<a
<span
role="button"
tabIndex={0}
style={{
color: "#1677ff",
WebkitTextFillColor: "#1677ff",
fontWeight: 600,
cursor: "pointer",
}}
onClick={() => handleViewDetail(record, type)}
onKeyDown={e => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleViewDetail(record, type);
}
}}
>
{count}
</a>
</span>
);
};
@ -109,3 +124,4 @@ function FireResourceStats(props) {
}
export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats));