1、增加二级页面标题

2、修改新增编辑页按钮样式
3、数据显示异常
4、测试bug
master
shenzhidan 2026-02-28 13:56:10 +08:00
parent 8dd9cfddd7
commit 627166fccb
13 changed files with 354 additions and 191 deletions

View File

@ -24,3 +24,8 @@ export const rescueTeamDelete = declareRequest(
"rescueTeamLoading",
`Delete >@/fireResource/rescueTeam/{id}`,
);
export const rescueTeamCheckName = declareRequest(
"rescueTeamLoading",
`Post >@/fireResource/rescueTeam/checkName`,
);

View File

@ -35,6 +35,7 @@ function Add(props) {
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
const pageTitle = query.id ? "编辑" : "新增";
// 设备列表
const createEmptyDevice = () => ({
@ -131,6 +132,7 @@ function Add(props) {
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
form.validateFields(["lng", "lat"]).catch(() => {});
setMapOpen(false);
};
@ -144,6 +146,10 @@ function Add(props) {
};
const removeDevice = (key) => {
if (devices.length <= 1) {
message.warning("设备信息至少保留一条");
return;
}
const index = devices.findIndex(item => item.key === key);
const newDevices = devices.filter(item => item.key !== key);
setDevices(newDevices);
@ -172,8 +178,8 @@ function Add(props) {
};
const removePerson = (key) => {
if (persons.length === 1) {
message.warning("至少保留一条人员数据");
if (persons.length <= 1) {
message.warning("人员信息至少保留一条");
return;
}
const index = persons.findIndex(item => item.key === key);
@ -222,6 +228,19 @@ function Add(props) {
const validDevices = devices.filter(
device => device.deviceName || device.deviceModel || device.deviceQty || device.deviceLocation,
);
const validPersons = persons.filter(
person => person.personName || person.personPhone || person.dutyDesc,
);
if (validDevices.length === 0) {
message.warning("设备信息至少保留一条");
return;
}
if (validPersons.length === 0) {
message.warning("人员信息至少保留一条");
return;
}
const params = {
...values,
@ -233,7 +252,7 @@ function Add(props) {
deviceLocation: device.deviceLocation,
...(device.id && { id: device.id }),
})),
persons: persons.map(({ key, ...person }) => ({
persons: validPersons.map(({ key, ...person }) => ({
personName: person.personName,
personPhone: person.personPhone,
dutyDesc: person.dutyDesc,
@ -262,7 +281,7 @@ function Add(props) {
<Page
loading={loading || uploadFileLoading || deleteFileLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
<Form
form={form}
@ -351,22 +370,30 @@ function Add(props) {
</Col>
<Col span={12}>
<Form.Item
label="纬度"
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item noStyle shouldUpdate>
{() => (
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
label="纬度"
required
validateStatus={form.getFieldError("lat").length ? "error" : ""}
help={form.getFieldError("lat")[0]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击定位按钮选择" disabled />
</Form.Item>
</div>
<Button type="primary" onClick={openMap}>
点击定位
</Button>
</div>
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
)}
</Form.Item>
</Col>
</Row>
@ -378,6 +405,7 @@ function Add(props) {
name="roomImages"
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防控制室图片" }]}
>
<Upload
fileType="image"
@ -459,24 +487,28 @@ function Add(props) {
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>
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<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>
</div>
{devices.length > 1 && (
<Button type="primary" danger onClick={() => removeDevice(device.key)}>
删除
</Button>
)}
</div>
</Form.Item>
</Col>
</Row>
@ -551,8 +583,8 @@ function Add(props) {
</Col>
<Col span={12}>
<div style={{ textAlign: 'right', paddingTop: 30 }}>
{index > 0 && (
<Button danger onClick={() => removePerson(person.key)}>
{persons.length > 1 && (
<Button type="primary" danger onClick={() => removePerson(person.key)}>
删除
</Button>
)}

View File

@ -139,6 +139,7 @@ function List(props) {
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
headerTitle="消防控制室"
>
<Search
labelCol={{ span: 8 }}
@ -166,14 +167,16 @@ function List(props) {
<Table
toolBarRender={() => (
<Space>
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
{props.permission("xfkzs-add") && (
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
)}
</Space>
)}
columns={[
@ -224,34 +227,40 @@ function List(props) {
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>
{props.permission("xfkzs-info") && (
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
)}
{props.permission("xfkzs-update") && (
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
)}
{props.permission("xfkzs-remove") && (
<Button
type="link"
size="small"
danger
onClick={() => {
onDelete(record.id);
}}
>
删除
</Button>
)}
</Space>
),
},

View File

@ -16,6 +16,7 @@ function View(props) {
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState(null);
const [statusDict, setStatusDict] = useState([]);
const pageTitle = "查看";
const { loading: dictLoading, getDictionary } = useDictionary();
const { loading: getFileLoading, getFile } = useGetFile();
@ -163,7 +164,7 @@ function View(props) {
<Page
loading={loading || dictLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
{detail && (
<div>

View File

@ -35,6 +35,7 @@ function Add(props) {
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
const pageTitle = query.id ? "编辑" : "新增";
// 设备信息列表
const createEmptyDevice = () => ({
@ -105,6 +106,7 @@ function Add(props) {
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
form.validateFields(["lng", "lat"]).catch(() => {});
setMapOpen(false);
};
@ -136,6 +138,11 @@ function Add(props) {
device.chargeUnit || device.deviceLocation || device.paramsSpec,
);
if (validDevices.length === 0) {
message.warning("设备信息至少保留一条");
return;
}
const params = {
...values,
pumpRoomId,
@ -182,6 +189,10 @@ function Add(props) {
};
const removeDevice = (key) => {
if (devices.length <= 1) {
message.warning("设备信息至少保留一条");
return;
}
const index = devices.findIndex(item => item.key === key);
const newDevices = devices.filter(item => item.key !== key);
setDeviceList(newDevices);
@ -204,7 +215,7 @@ function Add(props) {
<Page
loading={loading || uploadFileLoading || deleteFileLoading || getFileLoading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
<Form
form={form}
@ -292,22 +303,30 @@ function Add(props) {
</Col>
<Col span={12}>
<Form.Item
label="纬度"
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item noStyle shouldUpdate>
{() => (
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
label="纬度"
required
validateStatus={form.getFieldError("lat").length ? "error" : ""}
help={form.getFieldError("lat")[0]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击定位按钮选择" disabled />
</Form.Item>
</div>
<Button type="primary" onClick={openMap}>
点击定位
</Button>
</div>
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
)}
</Form.Item>
</Col>
</Row>
@ -319,6 +338,7 @@ function Add(props) {
name="roomImages"
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
rules={[{ required: true, message: "请上传消防泵房图片" }]}
>
<Upload
fileType="image"
@ -432,24 +452,32 @@ function Add(props) {
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>
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<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>
</div>
{devices.length > 1 && (
<Button
type="primary"
danger
onClick={() => removeDevice(device.key)}
>
删除
</Button>
)}
</div>
</Form.Item>
</Col>
</Row>

View File

@ -127,7 +127,12 @@ function List(props) {
};
return (
<Page isShowAllAction={isFromSupervision} isShowFooter={false} history={pageHistory}>
<Page
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
headerTitle="消防泵房"
>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
@ -144,7 +149,9 @@ function List(props) {
<Table
toolBarRender={() => (
<Space>
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
{props.permission("xfbf-add") && (
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
)}
</Space>
)}
columns={[
@ -159,9 +166,15 @@ function List(props) {
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>
{props.permission("xfbf-info") && (
<Button type="link" size="small" onClick={() => props.history.push(`./view?id=${record.id}`)}>查看</Button>
)}
{props.permission("xfbf-update") && (
<Button type="link" size="small" onClick={() => props.history.push(`./add?id=${record.id}`)}>编辑</Button>
)}
{props.permission("xfbf-remove") && (
<Button type="link" size="small" danger onClick={() => onDelete(record.id)}>删除</Button>
)}
</Space>
),
},

View File

@ -16,6 +16,7 @@ function View(props) {
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState(null);
const [statusDict, setStatusDict] = useState([]);
const pageTitle = "查看";
const { getDictionary } = useDictionary();
const { loading: getFileLoading, getFile } = useGetFile();
@ -148,7 +149,7 @@ function View(props) {
<Page
loading={loading || getFileLoading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
{detail && (
<div>

View File

@ -29,6 +29,32 @@ function Add(props) {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const pageTitle = query.id ? "编辑" : "新增";
const validateTeamNameUnique = async (_, value) => {
const teamName = value?.trim();
if (!teamName) {
return Promise.resolve();
}
if (!props["rescueTeamCheckName"]) {
return Promise.resolve();
}
try {
const response = await props["rescueTeamCheckName"]({
teamName,
id: query.id,
});
if (response?.data) {
return Promise.reject(new Error("救援队名称已存在"));
}
return Promise.resolve();
}
catch (error) {
return Promise.reject(new Error("救援队名称校验失败"));
}
};
// 消防队员列表
const createEmptyMember = () => ({
@ -99,6 +125,7 @@ function Add(props) {
setSubmitting(true);
try {
await form.validateFields(["teamName"]);
const apiMethod = query.id ? props["rescueTeamUpdate"] : props["rescueTeamAdd"];
// 处理日期格式和提交参数
@ -133,6 +160,9 @@ function Add(props) {
props.history.goBack();
}
catch (error) {
if (error?.errorFields) {
return;
}
message.error(query.id ? "修改失败" : "新增失败");
}
finally {
@ -170,7 +200,7 @@ function Add(props) {
<Page
loading={loading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
<Form
form={form}
@ -191,12 +221,19 @@ function Add(props) {
name="teamName"
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
validateTrigger="onBlur"
rules={[
{ required: true, message: "请输入救援队名称" },
{ max: 50, message: "救援队名称不能超过50个字符" },
{ validator: validateTeamNameUnique },
]}
>
<Input placeholder="请输入救援队名称" />
<Input
placeholder="请输入救援队名称"
onBlur={e => {
form.setFieldValue("teamName", e.target.value?.trim());
}}
/>
</Form.Item>
</Col>
</Row>
@ -258,10 +295,10 @@ function Add(props) {
>
<Input
placeholder="请输入队长电话"
maxLength={20}
maxLength={11}
onChange={e => {
// 只允许输入数字和连字符
const value = e.target.value.replace(/[^\d-]/g, '');
const value = e.target.value.replace(/[^\d-]/g, '').slice(0, 11);
form.setFieldValue('captainPhone', value);
}}
/>
@ -362,34 +399,37 @@ function Add(props) {
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>
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<Form.Item
name={['rescueMembersForm', index, 'personPhone']}
rules={[
{ required: true, message: "请输入队员电话" },
{ validator: validatePhone },
]}
noStyle
>
<Input
placeholder="请输入队员电话"
maxLength={11}
onChange={e => {
const value = e.target.value.replace(/[^\d-]/g, '').slice(0, 11);
updateMember(member.key, "personPhone", value);
form.setFieldValue(['rescueMembersForm', index, 'personPhone'], value);
}}
/>
</Form.Item>
</div>
{index !== 0 && (
<Button
type="primary"
danger
onClick={() => removeMember(member.key)}
>
删除
</Button>
)}
</Space.Compact>
</div>
</Form.Item>
</Col>
</Row>

View File

@ -106,7 +106,12 @@ function List(props) {
};
return (
<Page isShowAllAction={isFromSupervision} isShowFooter={false} history={pageHistory}>
<Page
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
headerTitle="消防救援队"
>
<Search
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
@ -126,7 +131,9 @@ function List(props) {
<Table
toolBarRender={() => (
<Space>
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
{props.permission("xfjyd-add") && (
<Button type="primary" onClick={() => props.history.push("./add")}>新增</Button>
)}
</Space>
)}
columns={[
@ -143,9 +150,15 @@ function List(props) {
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>
{props.permission("xfjyd-info") && (
<Button type="link" size="small" onClick={() => props.history.push(`./view?id=${record.id}`)}>查看</Button>
)}
{props.permission("xfjyd-update") && (
<Button type="link" size="small" onClick={() => props.history.push(`./add?id=${record.id}`)}>编辑</Button>
)}
{props.permission("xfjyd-remove") && (
<Button type="link" size="small" danger onClick={() => onDelete(record.id)}>删除</Button>
)}
</Space>
),
},

View File

@ -10,6 +10,7 @@ function View(props) {
const query = useGetUrlQuery();
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState(null);
const pageTitle = "查看";
const getData = async () => {
setLoading(true);
@ -57,7 +58,7 @@ function View(props) {
<Page
loading={loading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
{detail && (
<div>

View File

@ -16,6 +16,7 @@ function Add(props) {
const [mapOpen, setMapOpen] = useState(false);
const [mapLng, setMapLng] = useState("");
const [mapLat, setMapLat] = useState("");
const pageTitle = query.id ? "编辑" : "新增";
const getData = async () => {
setLoading(true);
@ -43,6 +44,7 @@ function Add(props) {
const handleMapConfirm = (lng, lat) => {
form.setFieldsValue({ lng, lat });
form.validateFields(["lng", "lat"]).catch(() => {});
setMapOpen(false);
};
@ -68,7 +70,7 @@ function Add(props) {
<Page
loading={loading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
<Form
form={form}
@ -117,22 +119,30 @@ function Add(props) {
</Col>
<Col span={12}>
<Form.Item
label="纬度"
rules={[{ required: true, message: "请选择纬度" }]}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item noStyle shouldUpdate>
{() => (
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
label="纬度"
required
validateStatus={form.getFieldError("lat").length ? "error" : ""}
help={form.getFieldError("lat")[0]}
>
<Input placeholder="请点击地图定位按钮选择" disabled style={{ flex: 1 }} />
<div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
<div style={{ flex: 1 }}>
<Form.Item
name="lat"
noStyle
rules={[{ required: true, message: "请选择纬度" }]}
>
<Input placeholder="请点击定位按钮选择" disabled />
</Form.Item>
</div>
<Button type="primary" onClick={openMap}>
点击定位
</Button>
</div>
</Form.Item>
<Button type="primary" onClick={openMap}>
地图定位
</Button>
</Space.Compact>
)}
</Form.Item>
</Col>
</Row>

View File

@ -147,6 +147,7 @@ function List(props) {
isShowAllAction={isFromSupervision}
isShowFooter={false}
history={pageHistory}
headerTitle="消防水源"
>
<Search
labelCol={{ span: 8 }}
@ -160,14 +161,16 @@ function List(props) {
<Table
toolBarRender={() => (
<Space>
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
{props.permission("xfsy-add") && (
<Button
type="primary"
onClick={() => {
props.history.push("./add");
}}
>
新增
</Button>
)}
</Space>
)}
columns={[
@ -204,32 +207,38 @@ function List(props) {
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>
{props.permission("xfsy-info") && (
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./view?id=${record.id}`);
}}
>
查看
</Button>
)}
{props.permission("xfsy-update") && (
<Button
type="link"
size="small"
onClick={() => {
props.history.push(`./add?id=${record.id}`);
}}
>
编辑
</Button>
)}
{props.permission("xfsy-remove") && (
<Button
type="link"
size="small"
danger
onClick={() => onDelete(record.id)}
>
删除
</Button>
)}
</Space>
),
},

View File

@ -12,6 +12,7 @@ function View(props) {
const [loading, setLoading] = useState(false);
const [detail, setDetail] = useState(null);
const [statusDict, setStatusDict] = useState([]);
const pageTitle = "查看";
const { getDictionary } = useDictionary();
@ -57,7 +58,7 @@ function View(props) {
<Page
loading={loading}
isShowFooter={false}
isShowBack={false}
headerTitle={pageTitle}
>
{detail && (
<div>