diff --git a/jjb.config.js b/jjb.config.js index 972d8a1..06f0f31 100644 --- a/jjb.config.js +++ b/jjb.config.js @@ -9,17 +9,18 @@ module.exports = { // 应用后端分支名称,部署上线需要 javaGitBranch: "", // 接口服务地址 - API_HOST: "开发环境后端地址", + API_HOST: "http://192.168.20.100:30140", + // API_HOST: "http://127.0.0.1", }, production: { // 应用后端分支名称,部署上线需要 javaGitBranch: "", // 接口服务地址 - API_HOST: "", + API_HOST: "https://gbs-gateway.qhdsafety.com", }, }, // 应用唯一标识符 - appIdentifier: "唯一应用标识,与后端gateway相同", + appIdentifier: "fireResource", // 应用上下文注入全局变量 contextInject: { // 应用Key diff --git a/package.json b/package.json index 21b0ff1..8da261b 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "license": "MIT", "main": "index.js", "scripts": { - "serve": "node node_modules/@cqsjjb/scripts/webpack.dev.server.js", - "build": "node node_modules/@cqsjjb/scripts/webpack.build.js", + "serve": "node node_modules/@cqsjjb/scripts/rspack.dev.server.js", + "build": "node node_modules/@cqsjjb/scripts/rspack.build.js", "push": "jjb-cmd push java production", "clean-cache": "rimraf node_modules/.cache/webpack", "serve:development": "cross-env NODE_ENV=development npm run serve", @@ -30,12 +30,12 @@ "lodash-es": "^4.17.21", "react": "^18.2.0", "react-dom": "^18.2.0", - "zy-react-library": "latest" + "zy-react-library": "^1.1.41" }, "devDependencies": { "@antfu/eslint-config": "^5.4.1", "@babel/plugin-proposal-decorators": "^7.19.3", - "@cqsjjb/scripts": "latest", + "@cqsjjb/scripts": "2.0.0-rspack.1", "@eslint-react/eslint-plugin": "^2.2.2", "cross-env": "^7.0.3", "eslint": "^9.37.0", diff --git a/src/api/controlRoom/index.js b/src/api/controlRoom/index.js new file mode 100644 index 0000000..8c64a77 --- /dev/null +++ b/src/api/controlRoom/index.js @@ -0,0 +1,26 @@ +import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; + +export const controlRoomList = declareRequest( + "controlRoomLoading", + `Post >@/fireResource/controlRoom/list`, +); + +export const controlRoomDetail = declareRequest( + "controlRoomLoading", + `Get >/fireResource/controlRoom/{id}`, +); + +export const controlRoomAdd = declareRequest( + "controlRoomLoading", + `Post >@/fireResource/controlRoom/save`, +); + +export const controlRoomUpdate = declareRequest( + "controlRoomLoading", + `Put >@/fireResource/controlRoom/edit`, +); + +export const controlRoomDelete = declareRequest( + "controlRoomLoading", + `Delete >@/fireResource/controlRoom/{id}`, +); diff --git a/src/api/fireResourceStats/index.js b/src/api/fireResourceStats/index.js new file mode 100644 index 0000000..fc5062f --- /dev/null +++ b/src/api/fireResourceStats/index.js @@ -0,0 +1,6 @@ +import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; + +export const fireResourceStatsList = declareRequest( + "fireResourceStatsLoading", + `Post >@/fireResource/resource/list`, +); diff --git a/src/api/pumpRoom/index.js b/src/api/pumpRoom/index.js new file mode 100644 index 0000000..96d1fbe --- /dev/null +++ b/src/api/pumpRoom/index.js @@ -0,0 +1,26 @@ +import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; + +export const pumpRoomList = declareRequest( + "pumpRoomLoading", + `Post >@/fireResource/pumpRoom/list`, +); + +export const pumpRoomDetail = declareRequest( + "pumpRoomLoading", + `Get >/fireResource/pumpRoom/{id}`, +); + +export const pumpRoomAdd = declareRequest( + "pumpRoomLoading", + `Post >@/fireResource/pumpRoom/save`, +); + +export const pumpRoomUpdate = declareRequest( + "pumpRoomLoading", + `Put >@/fireResource/pumpRoom/edit`, +); + +export const pumpRoomDelete = declareRequest( + "pumpRoomLoading", + `Delete >@/fireResource/pumpRoom/{id}`, +); diff --git a/src/api/rescueTeam/index.js b/src/api/rescueTeam/index.js new file mode 100644 index 0000000..97ffc4b --- /dev/null +++ b/src/api/rescueTeam/index.js @@ -0,0 +1,26 @@ +import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; + +export const rescueTeamList = declareRequest( + "rescueTeamLoading", + `Post > @/fireResource/rescueTeam/list`, +); + +export const rescueTeamDetail = declareRequest( + "rescueTeamLoading", + `Get > /fireResource/rescueTeam/{id}`, +); + +export const rescueTeamAdd = declareRequest( + "rescueTeamLoading", + `Post >@/fireResource/rescueTeam/save`, +); + +export const rescueTeamUpdate = declareRequest( + "rescueTeamLoading", + `Put >@/fireResource/rescueTeam/edit`, +); + +export const rescueTeamDelete = declareRequest( + "rescueTeamLoading", + `Delete >@/fireResource/rescueTeam/{id}`, +); diff --git a/src/api/waterSource/index.js b/src/api/waterSource/index.js new file mode 100644 index 0000000..06b49d4 --- /dev/null +++ b/src/api/waterSource/index.js @@ -0,0 +1,26 @@ +import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; + +export const waterSourceList = declareRequest( + "waterSourceLoading", + `Post >@/fireResource/waterSource/list`, +); + +export const waterSourceDetail = declareRequest( + "waterSourceLoading", + `Get >/fireResource/waterSource/{id}`, +); + +export const waterSourceAdd = declareRequest( + "waterSourceLoading", + `Post >@/fireResource/waterSource/save`, +); + +export const waterSourceUpdate = declareRequest( + "waterSourceLoading", + `Put >@/fireResource/waterSource/edit`, +); + +export const waterSourceDelete = declareRequest( + "waterSourceLoading", + `Delete >@/fireResource/waterSource/{id}`, +); diff --git a/src/enumerate/namespace/index.js b/src/enumerate/namespace/index.js index b392d90..7a90786 100644 --- a/src/enumerate/namespace/index.js +++ b/src/enumerate/namespace/index.js @@ -5,3 +5,8 @@ import { defineNamespace } from "@cqsjjb/jjb-dva-runtime"; export const NS_GLOBAL = defineNamespace("global"); +export const NS_CONTROL_ROOM = defineNamespace("controlRoom"); +export const NS_RESCUE_TEAM = defineNamespace("rescueTeam"); +export const NS_PUMP_ROOM = defineNamespace("pumpRoom"); +export const NS_WATER_SOURCE = defineNamespace("waterSource"); +export const NS_FIRE_RESOURCE_STATS = defineNamespace("fireResourceStats"); diff --git a/src/pages/Container/BranchCompany/ControlRoom/Add/index.js b/src/pages/Container/BranchCompany/ControlRoom/Add/index.js new file mode 100644 index 0000000..563624d --- /dev/null +++ b/src/pages/Container/BranchCompany/ControlRoom/Add/index.js @@ -0,0 +1,534 @@ +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 Page from "zy-react-library/components/Page"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Upload from "zy-react-library/components/Upload"; +import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj"; +import useDeleteFile from "zy-react-library/hooks/useDeleteFile"; +import useGetFile from "zy-react-library/hooks/useGetFile"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import useUploadFile from "zy-react-library/hooks/useUploadFile"; +import { NS_CONTROL_ROOM } from "~/enumerate/namespace"; + +function Add(props) { + const query = useGetUrlQuery(); + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + + // 设备信息列表 + const [deviceList, setDeviceList] = useState([]); + // 人员信息列表 + const [personnelList, setPersonnelList] = useState([]); + + // 文件上传相关hooks + const { loading: uploadFileLoading, uploadFile } = useUploadFile(); + const { loading: deleteFileLoading, deleteFile } = useDeleteFile(); + const { loading: getFileLoading, getFile } = useGetFile(); + + // 保存要删除的文件列表 + const [deleteFiles, setDeleteFiles] = useState([]); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["controlRoomDetail"]({ id: query.id }); + + // ⭐ 如果有业务ID,查询图片文件 + if (data.roomId) { + const files = await getFile({ + eqType: UPLOAD_FILE_TYPE_ENUM[302], // 消防点检检查合格图片 + eqForeignKey: data.roomId, + }); + data.roomImages = files; + } + + form.setFieldsValue(data); + + // 设置设备列表 + if (data.devices && data.devices.length > 0) { + setDeviceList(data.devices.map((item, index) => ({ ...item, key: item.id || index }))); + } + + // 设置人员列表 + if (data.persons && data.persons.length > 0) { + setPersonnelList(data.persons.map((item, index) => ({ ...item, key: item.id || index }))); + } + } + catch (error) { + console.error("加载详情失败:", error); + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + 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 { + // ⭐ 先删除标记删除的文件 + if (deleteFiles.length > 0) { + await deleteFile({ single: false, files: deleteFiles }); + } + + // ⭐ 上传图片文件,获取业务ID(room_id) + const { id: roomId } = await uploadFile({ + single: false, + files: values.roomImages, + params: { + type: UPLOAD_FILE_TYPE_ENUM[302], // ⭐ 消防点检检查合格图片 + foreignKey: values.roomId, // 编辑时传入已有的 roomId + }, + }); + + const apiMethod = query.id ? props["controlRoomUpdate"] : props["controlRoomAdd"]; + + // 构建提交参数 + const params = { + ...values, + roomId, // ⭐ 使用上传返回的业务ID + // 设备列表:去掉前端添加的 key + devices: deviceList.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 }), + })), + }; + + if (query.id) { + params.id = query.id; + } + + await apiMethod(params); + message.success(query.id ? "修改成功" : "新增成功"); + props.history.goBack(); + } + catch (error) { + console.error("提交失败:", error); + message.error(query.id ? "修改失败" : "新增失败"); + } + finally { + setSubmitting(false); + } + }; + + // 设备列表相关操作 + 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: (<> + * + 设备名称 + ), + dataIndex: "deviceName", + render: (text, record) => ( + updateDevice(record.key, "deviceName", e.target.value)} + /> + ), + }, + { + title: (<> + * + 设备型号 + ), + dataIndex: "deviceModel", + render: (text, record) => ( + updateDevice(record.key, "deviceModel", e.target.value)} + /> + ), + }, + { + title: (<> + * + 设备数量 + ), + dataIndex: "deviceQty", + render: (text, record) => ( + updateDevice(record.key, "deviceQty", value)} + /> + ), + }, + { + title: (<> + * + 设备位置 + ), + dataIndex: "deviceLocation", + render: (text, record) => ( + updateDevice(record.key, "deviceLocation", e.target.value)} + /> + ), + }, + { + title: "操作", + width: 80, + align: "center", + render: (_, record) => ( + + ), + }, + ]; + + // 人员表格列定义 + const personnelColumns = [ + { + title: (<> + * + 人员姓名 + ), + dataIndex: "personName", + render: (text, record) => ( + updatePersonnel(record.key, "personName", e.target.value)} + /> + ), + }, + { + title: (<> + * + 人员手机号 + ), + dataIndex: "personPhone", + render: (text, record) => ( + updatePersonnel(record.key, "personPhone", e.target.value)} + /> + ), + }, + { + title: "人员值班情况", + dataIndex: "dutyDesc", + render: (text, record) => ( + updatePersonnel(record.key, "dutyDesc", e.target.value)} + /> + ), + }, + { + title: "操作", + width: 80, + align: "center", + render: (_, record) => ( + + ), + }, + ]; + + return ( + +
+ + {/* 添加隐藏字段保存 roomId */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + setDeleteFiles([...deleteFiles, file]); + }} + /> + + + + + + + 新增 + + )} + style={{ marginBottom: 24 }} + > + + + + + 新增 + + )} + style={{ marginBottom: 24 }} + > +
+ + + + + + + + + + + ); +} + +export default Connect([NS_CONTROL_ROOM], true)(Permission(Add)); diff --git a/src/pages/Container/BranchCompany/ControlRoom/List/index.js b/src/pages/Container/BranchCompany/ControlRoom/List/index.js new file mode 100644 index 0000000..3f94a62 --- /dev/null +++ b/src/pages/Container/BranchCompany/ControlRoom/List/index.js @@ -0,0 +1,184 @@ +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 Page from "zy-react-library/components/Page"; +import Search from "zy-react-library/components/Search"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Table from "zy-react-library/components/Table"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_CONTROL_ROOM } from "~/enumerate/namespace"; + +function List(props) { + const [form] = Form.useForm(); + const query = useGetUrlQuery(); + + const { tableProps, getData } = useTable(props["controlRoomList"], { form }); + + const [deleting, setDeleting] = useState(false); + const [statusDict, setStatusDict] = useState([]); + + 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 () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + const getStatusLabel = (record) => { + if (record.roomStatusName) + return record.roomStatusName; + const match = statusDict.find(item => item.dictValue === record.roomStatus); + return match?.dictLabel || record.roomStatus || "-"; + }; + + const onDelete = (id) => { + Modal.confirm({ + title: "确认删除", + content: "删除后不可恢复,确认继续?", + okText: "确认", + cancelText: "取消", + okButtonProps: { danger: true, loading: deleting }, + onOk: async () => { + if (!props["controlRoomDelete"]) { + message.warning("未接入 controlRoomDelete effect"); + return; + } + setDeleting(true); + try { + await props["controlRoomDelete"]({ id: String(id) }); + message.success("已删除"); + getData(); + } + finally { + setDeleting(false); + } + }, + }); + }; + + return ( + + ), + span: 4, + formItemProps: { style: { marginLeft: 16 } }, + }, + { name: "eqCorpId", onlyForLabel: true }, + ]} + form={form} + onFinish={getData} + /> +
( + + {/* {props.permission("xfkzs-btn-add") && ( */} + + {/* )} */} + + )} + columns={[ + // { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 }, + { title: "消防控制室名称", dataIndex: "roomName", ellipsis: true, width: 140 }, + { + title: "消防控制室状态", + width: 140, + align: "center", + 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: "操作", + fixed: "right", + width: 180, + render: (_, record) => ( + + {/* {props.permission("xfkzs-btn-view") && ( */} + + {/* )} */} + + {/* {props.permission("xfkzs-btn-edit") && ( */} + + {/* )} */} + + {/* {props.permission("xfkzs-btn-delete") && ( */} + + {/* )} */} + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_CONTROL_ROOM], true)(Permission(List)); diff --git a/src/pages/Container/BranchCompany/ControlRoom/View/index.js b/src/pages/Container/BranchCompany/ControlRoom/View/index.js new file mode 100644 index 0000000..b99e8c9 --- /dev/null +++ b/src/pages/Container/BranchCompany/ControlRoom/View/index.js @@ -0,0 +1,247 @@ +import { Permission } from "@cqsjjb/jjb-common-decorator/permission"; +import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import { Button, Card, Descriptions, Image, message, Space, Table } from "antd"; +import { useEffect, useState } from "react"; +import Page from "zy-react-library/components/Page"; +import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetFile from "zy-react-library/hooks/useGetFile"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import { NS_CONTROL_ROOM } from "~/enumerate/namespace"; + +function View(props) { + const query = useGetUrlQuery(); + 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(); + + const getData = async () => { + setLoading(true); + 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 }; + } + + setDetail(nextDetail); + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, [query.id]); + + useEffect(() => { + const fetchDict = async () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + useEffect(() => { + if (!detail) + 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 ?? "-"); + + const deviceColumns = [ + { + title: "序号", + width: 80, + align: "center", + render: (_, __, index) => index + 1, + }, + { + title: "设备名称", + dataIndex: "deviceName", + width: 180, + align: "center", + ellipsis: true, + }, + { + title: "设备型号", + dataIndex: "deviceModel", + width: 180, + align: "center", + ellipsis: true, + }, + { + title: "设备数量", + dataIndex: "deviceQty", + align: "center", + width: 120, + }, + { + title: "设备位置", + dataIndex: "deviceLocation", + align: "center", + ellipsis: true, + width: 240, + }, + ]; + + const personnelColumns = [ + { + title: "序号", + width: 80, + align: "center", + render: (_, __, index) => index + 1, + }, + { + title: "人员姓名", + dataIndex: "personName", + width: 160, + align: "center", + ellipsis: true, + }, + { + title: "人员手机号", + dataIndex: "personPhone", + width: 180, + align: "center", + ellipsis: true, + }, + { + title: "人员值班情况", + render: (_, record) => record.dutyDesc || "-", + align: "center", + ellipsis: true, + width: 240, + }, + ]; + + return ( + + {detail && ( + <> + + 0 + ? ( + + + {detail.roomImages.map((img, index) => ( + + ))} + + + ) + : ( + "无" + ), + span: 2, + }, + ]} + /> + + + +
index} + locale={{ emptyText: "暂无设备信息" }} + bordered + tableLayout="fixed" + /> + + + +
index} + locale={{ emptyText: "暂无人员信息" }} + bordered + tableLayout="fixed" + /> + + +
+ +
+ + )} + + ); +} + +export default Connect([NS_CONTROL_ROOM], true)(Permission(View)); diff --git a/src/pages/Container/BranchCompany/ControlRoom/index.js b/src/pages/Container/BranchCompany/ControlRoom/index.js new file mode 100644 index 0000000..2b33b01 --- /dev/null +++ b/src/pages/Container/BranchCompany/ControlRoom/index.js @@ -0,0 +1,18 @@ +import { Route, Switch } from "react-router-dom"; +import Add from "./Add"; +import List from "./List"; +import View from "./View"; + +function ControlRoom() { + return ( +
+ + + + + +
+ ); +} + +export default ControlRoom; diff --git a/src/pages/Container/BranchCompany/FireResourceStats/index.js b/src/pages/Container/BranchCompany/FireResourceStats/index.js new file mode 100644 index 0000000..1fe4816 --- /dev/null +++ b/src/pages/Container/BranchCompany/FireResourceStats/index.js @@ -0,0 +1,111 @@ +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"; +import Search from "zy-react-library/components/Search"; +import Table from "zy-react-library/components/Table"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_FIRE_RESOURCE_STATS } from "~/enumerate/namespace"; + +function FireResourceStats(props) { + const [form] = Form.useForm(); + + 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]}?eqCorpId=${corpId}`); + } + }; + + return ( + + +
index + 1 }, + { + title: "企业名称", + dataIndex: "companyName", + ellipsis: true, + render: text => text || "一公司", + }, + { + title: "消防救援队数", + dataIndex: "rescueTeamCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "rescueTeam")} + > + {text || 0} + + ), + }, + { + title: "消防控制室数", + dataIndex: "controlRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "controlRoom")} + > + {text || 0} + + ), + }, + { + title: "消防泵房数", + dataIndex: "pumpRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "pumpRoom")} + > + {text || 0} + + ), + }, + { + title: "消防水源数", + dataIndex: "waterSourceCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "waterSource")} + > + {text || 0} + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats)); diff --git a/src/pages/Container/BranchCompany/PumpRoom/Add/index.js b/src/pages/Container/BranchCompany/PumpRoom/Add/index.js new file mode 100644 index 0000000..65425cf --- /dev/null +++ b/src/pages/Container/BranchCompany/PumpRoom/Add/index.js @@ -0,0 +1,414 @@ +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 Page from "zy-react-library/components/Page"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Upload from "zy-react-library/components/Upload"; +import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj"; +import useDeleteFile from "zy-react-library/hooks/useDeleteFile"; +import useGetFile from "zy-react-library/hooks/useGetFile"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import useUploadFile from "zy-react-library/hooks/useUploadFile"; +import { NS_PUMP_ROOM } from "~/enumerate/namespace"; + +function Add(props) { + const query = useGetUrlQuery(); + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + + // 设备信息列表 + const [devices, setDeviceList] = useState([]); + + const { loading: uploadFileLoading, uploadFile } = useUploadFile(); + const { loading: deleteFileLoading, deleteFile } = useDeleteFile(); + const { loading: getFileLoading, getFile } = useGetFile(); + + const [deleteFiles, setDeleteFiles] = useState([]); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["pumpRoomDetail"]({ id: query.id }); + const roomKey = data.roomId || data.pumpRoomId || data.id; + if (roomKey) { + const files = await getFile({ + eqType: UPLOAD_FILE_TYPE_ENUM[302], + eqForeignKey: roomKey, + }); + data.roomImages = files; + } + form.setFieldsValue(data); + + // 设置设备列表 + if (data.devices && data.devices.length > 0) { + setDeviceList(data.devices.map((item, index) => ({ ...item, key: index }))); + } + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + const onFinish = async (values) => { + // 验证设备列表 + if (devices.length === 0) { + message.warning("请至少添加一条设备信息"); + return; + } + + // 验证设备列表是否填写完整 + const invalidDevice = devices.find( + item => !item.deviceName || !item.deviceModel || !item.deviceQty || !item.deviceLocation, + ); + 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, + }, + }); + + const apiMethod = query.id ? props["pumpRoomUpdate"] : props["pumpRoomAdd"]; + const params = { + ...values, + pumpRoomId, + devices: devices.map(({ key, ...device }) => ({ + deviceCode: device.deviceCode, + deviceName: device.deviceName, + deviceModel: device.deviceModel, + deviceQty: device.deviceQty, + deviceLocation: device.deviceLocation, + ...(device.id && { id: device.id }), + })), + }; + if (query.id) { + params.id = query.id; + } + + await apiMethod(params); + message.success(query.id ? "修改成功" : "新增成功"); + props.history.goBack(); + } + catch (error) { + message.error(query.id ? "修改失败" : "新增失败"); + } + finally { + setSubmitting(false); + } + }; + + // 设备列表相关操作 + const addDevice = () => { + const newDevice = { + key: Date.now(), + deviceName: "", + deviceModel: "", + deviceQty: null, + deviceLocation: "", + }; + setDeviceList([...devices, newDevice]); + }; + + const removeDevice = (key) => { + setDeviceList(devices.filter(item => item.key !== key)); + }; + + const updateDevice = (key, field, value) => { + setDeviceList( + devices.map(item => (item.key === key ? { ...item, [field]: value } : item)), + ); + }; + + // 设备表格列定义 + const deviceColumns = [ + { + title: (<> + * + 设备编号 + ), + dataIndex: "deviceCode", + render: (text, record) => ( + updateDevice(record.key, "deviceCode", e.target.value)} + /> + ), + }, + { + title: (<> + * + 设备名称 + ), + dataIndex: "deviceName", + render: (text, record) => ( + updateDevice(record.key, "deviceName", e.target.value)} + /> + ), + }, + { + title: (<> + * + 设备型号 + ), + dataIndex: "deviceModel", + render: (text, record) => ( + updateDevice(record.key, "deviceModel", e.target.value)} + /> + ), + }, + { + title: (<> + * + 设备数量 + ), + dataIndex: "deviceQty", + render: (text, record) => ( + updateDevice(record.key, "deviceQty", value)} + /> + ), + }, + { + title: (<> + * + 设备位置 + ), + dataIndex: "deviceLocation", + render: (text, record) => ( + updateDevice(record.key, "deviceLocation", e.target.value)} + /> + ), + }, + { + title: "操作", + width: 80, + align: "center", + render: (_, record) => ( + + ), + }, + ]; + + return ( + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + setDeleteFiles([...deleteFiles, file]); + }} + /> + + + + + + + + 新增 + + )} + style={{ marginBottom: 24 }} + > +
+ + + + + + + + + + + + ); +} + +export default Connect([NS_PUMP_ROOM], true)(Permission(Add)); diff --git a/src/pages/Container/BranchCompany/PumpRoom/List/index.js b/src/pages/Container/BranchCompany/PumpRoom/List/index.js new file mode 100644 index 0000000..2be7ea6 --- /dev/null +++ b/src/pages/Container/BranchCompany/PumpRoom/List/index.js @@ -0,0 +1,158 @@ +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 Page from "zy-react-library/components/Page"; +import Search from "zy-react-library/components/Search"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Table from "zy-react-library/components/Table"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_PUMP_ROOM } from "~/enumerate/namespace"; + +function List(props) { + const [form] = Form.useForm(); + const query = useGetUrlQuery(); + + const { tableProps, getData } = useTable(props["pumpRoomList"], { form }); + + const [deleting, setDeleting] = useState(false); + const [statusDict, setStatusDict] = useState([]); + + const { getDictionary } = useDictionary(); + + useEffect(() => { + const fetchDict = async () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + useEffect(() => { + if (query.eqCorpId) { + form.setFieldsValue({ eqCorpId: query.eqCorpId }); + getData(); + } + }, [query.eqCorpId]); + + const getStatusLabel = (record) => { + 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: "确认删除", + content: "删除后不可恢复,确认继续?", + okText: "确认", + cancelText: "取消", + okButtonProps: { danger: true, loading: deleting }, + onOk: async () => { + if (!props["pumpRoomDelete"]) { + message.warning("未接入 pumpRoomDelete effect"); + return; + } + setDeleting(true); + try { + await props["pumpRoomDelete"]({ id }); + message.success("已删除"); + getData(); + } + finally { + setDeleting(false); + } + }, + }); + }; + + return ( + + ), + }, + { name: "eqCorpId", onlyForLabel: true }, + ]} + form={form} + onFinish={getData} + /> +
( + + + + )} + columns={[ + // { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 }, + { title: "消防泵房名称", dataIndex: "pumpRoomName", ellipsis: true, width: 120 }, + { + title: "消防泵房状态", + width: 140, + align: "center", + render: (_, record) => getStatusLabel(record), + }, + { title: "负责人", dataIndex: "principalName", width: 120 }, + { title: "负责人手机号", dataIndex: "principalPhone", width: 140 }, + { title: "设备数", dataIndex: "deviceCount", width: 100, align: "center" }, + { + title: "操作", + fixed: "right", + width: 180, + render: (_, record) => ( + + + + + + + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_PUMP_ROOM], true)(Permission(List)); diff --git a/src/pages/Container/BranchCompany/PumpRoom/View/index.js b/src/pages/Container/BranchCompany/PumpRoom/View/index.js new file mode 100644 index 0000000..480917c --- /dev/null +++ b/src/pages/Container/BranchCompany/PumpRoom/View/index.js @@ -0,0 +1,166 @@ +import { Permission } from "@cqsjjb/jjb-common-decorator/permission"; +import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import { Button, Card, Descriptions, Image, message, Space, Table } from "antd"; +import { useEffect, useState } from "react"; +import Page from "zy-react-library/components/Page"; +import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetFile from "zy-react-library/hooks/useGetFile"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import { NS_PUMP_ROOM } from "~/enumerate/namespace"; + +function View(props) { + const query = useGetUrlQuery(); + const [loading, setLoading] = useState(false); + const [detail, setDetail] = useState(null); + const [statusDict, setStatusDict] = useState([]); + + const { getDictionary } = useDictionary(); + const { loading: getFileLoading, getFile } = useGetFile(); + + useEffect(() => { + const fetchDict = async () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_contro_root_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + const getStatusLabel = (record) => { + if (!record) + return "-"; + if (record.roomStatusName) + return record.roomStatusName; + const match = statusDict.find(item => item.dictValue === record.pumpRoomStatus); + return match?.dictLabel || record.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 }; + } + setDetail(nextDetail); + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + // 设备表格列定义 + 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" }, + ]; + + return ( + + {detail && ( + <> + + 0 + ? ( + + + {detail.roomImages.map((img, index) => ( + + ))} + + + ) + : ( + "无" + ), + span: 2, + }, + ]} + /> + + + +
index} + locale={{ emptyText: "暂无设备信息" }} + /> + + +
+ +
+ + )} + + ); +} + +export default Connect([NS_PUMP_ROOM], true)(Permission(View)); diff --git a/src/pages/Container/BranchCompany/PumpRoom/index.js b/src/pages/Container/BranchCompany/PumpRoom/index.js new file mode 100644 index 0000000..a885bad --- /dev/null +++ b/src/pages/Container/BranchCompany/PumpRoom/index.js @@ -0,0 +1,5 @@ +function Index(props) { + return (
{props.children}
); +} + +export default Index; diff --git a/src/pages/Container/BranchCompany/RescueTeam/Add/index.js b/src/pages/Container/BranchCompany/RescueTeam/Add/index.js new file mode 100644 index 0000000..06ada0e --- /dev/null +++ b/src/pages/Container/BranchCompany/RescueTeam/Add/index.js @@ -0,0 +1,407 @@ +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 dayjs from "dayjs"; +import { useEffect, useState } from "react"; +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"; +import { NS_RESCUE_TEAM } from "~/enumerate/namespace"; + +function Add(props) { + const query = useGetUrlQuery(); + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + + // 消防队员列表 + const [rescueMembers, setRescueMembers] = useState([]); + + // ⭐ 添加状态保存字典显示名称 + const [teamTypeName, setTeamTypeName] = useState(""); + const [regionScopeName, setRegionScopeName] = useState(""); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["rescueTeamDetail"]({ id: query.id }); + + // 处理日期字段 + if (data.establishDate) { + data.establishDate = dayjs(data.establishDate); + } + + form.setFieldsValue(data); + + // ⭐ 设置字典显示名称 + if (data.teamTypeName) { + setTeamTypeName(data.teamTypeName); + } + if (data.regionScopeName) { + setRegionScopeName(data.regionScopeName); + } + + // 设置消防队员列表 + if (data.rescueMembers && data.rescueMembers.length > 0) { + setRescueMembers(data.rescueMembers.map((item, index) => ({ ...item, key: index }))); + } + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + const onFinish = async (values) => { + // 验证消防队员列表 + if (rescueMembers.length === 0) { + message.warning("请至少添加一名消防队员"); + 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"]; + + // 处理日期格式和提交参数 + const params = { + ...values, + establishDate: values.establishDate ? values.establishDate.format("YYYY-MM-DD") : null, + + // ⭐ 从状态中获取字典显示名称 + teamTypeName, + regionScopeName, + + // 队员数量 + memberCount: rescueMembers.length, + + // 队员列表:去掉前端添加的 key + rescueMembers: rescueMembers.map(({ key, ...member }) => ({ + personName: member.personName, + personPhone: member.personPhone, + dutyDesc: member.dutyDesc || "", + roleCode: member.roleCode || 1, + ...(member.id && { id: member.id }), + })), + }; + + if (query.id) { + params.id = query.id; + params.teamId = values.teamId; + } + + await apiMethod(params); + message.success(query.id ? "修改成功" : "新增成功"); + props.history.goBack(); + } + catch (error) { + message.error(query.id ? "修改失败" : "新增失败"); + } + finally { + setSubmitting(false); + } + }; + + // 消防队员相关操作 + const addMember = () => { + const newMember = { + key: Date.now(), + personName: "", + personPhone: "", + dutyDesc: "", + roleCode: 1, + }; + setRescueMembers([...rescueMembers, newMember]); + }; + + const removeMember = (key) => { + setRescueMembers(rescueMembers.filter(item => item.key !== key)); + }; + + const updateMember = (key, field, value) => { + setRescueMembers( + rescueMembers.map(item => (item.key === key ? { ...item, [field]: value } : item)), + ); + }; + + // 消防队员表格列定义 + const memberColumns = [ + { + title: (<> + * + 队员姓名 + ), + dataIndex: "personName", + render: (text, record) => ( + updateMember(record.key, "personName", e.target.value)} + /> + ), + }, + { + title: (<> + * + 队员电话 + ), + dataIndex: "personPhone", + render: (text, record) => ( + updateMember(record.key, "personPhone", e.target.value)} + /> + ), + }, + { + title: "操作", + width: 80, + align: "center", + render: (_, record) => ( + + ), + }, + ]; + + return ( + +
+ + + + {/* 第一行:救援队名称、类型 */} + +
+ + + + + + + + { + // ⭐ 监听选择事件,保存显示名称 + setTeamTypeName(option?.children || option?.label || ""); + }} + /> + + + + + {/* 第二行:队长、队长电话 */} + + + + + + + + + + + + + + + {/* 第三行:指挥人员、建立日期 */} + + + + + + + + + + + + + + + {/* 第四行:所属区域或范围、职责和任务范围 */} + + + + { + // ⭐ 监听选择事件,保存显示名称 + setRegionScopeName(option?.children || option?.label || ""); + }} + /> + + + + + + + + + + + {/* 第五行:负责人单位或部门(单独一行) */} + + + + + + + + + + + 新增 + + )} + style={{ marginBottom: 24 }} + > +
+ + + + + + + + + + + ); +} + +export default Connect([NS_RESCUE_TEAM], true)(Permission(Add)); diff --git a/src/pages/Container/BranchCompany/RescueTeam/List/index.js b/src/pages/Container/BranchCompany/RescueTeam/List/index.js new file mode 100644 index 0000000..6a3eddb --- /dev/null +++ b/src/pages/Container/BranchCompany/RescueTeam/List/index.js @@ -0,0 +1,147 @@ +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 Page from "zy-react-library/components/Page"; +import Search from "zy-react-library/components/Search"; +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) { + const [form] = Form.useForm(); + const query = useGetUrlQuery(); + + const { tableProps, getData } = useTable(props["rescueTeamList"], { form }); + + const [deleting, setDeleting] = useState(false); + + useEffect(() => { + if (query.eqCorpId) { + form.setFieldsValue({ eqCorpId: query.eqCorpId }); + getData(); + } + }, [query.eqCorpId]); + + const onDelete = (id) => { + Modal.confirm({ + title: "确认删除", + content: "删除后不可恢复,确认继续?", + okText: "确认", + cancelText: "取消", + okButtonProps: { danger: true, loading: deleting }, + onOk: async () => { + if (!props["rescueTeamDelete"]) { + message.warning("未接入 rescueTeamDelete effect"); + return; + } + setDeleting(true); + try { + await props["rescueTeamDelete"]({ id }); + message.success("已删除"); + getData(); + } + finally { + setDeleting(false); + } + }, + }); + }; + + return ( + + ), + }, + { name: "likeChargeOrgDept", label: "负责人单位或部门" }, + { name: "likeCaptainName", label: "队长" }, + { name: "eqCorpId", onlyForLabel: true }, + ]} + form={form} + onFinish={getData} + /> +
( + + {/* {props.permission("jydgl-btn-add") && ( */} + + {/* )} */} + + )} + columns={[ + // { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 }, + { title: "救援队名称", dataIndex: "teamName", ellipsis: true }, + { + title: "类型", + dataIndex: "teamTypeName", + width: 140, + align: "center", + }, + { 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, + render: (_, record) => ( + + {/* {props.permission("jydgl-btn-view") && ( */} + + {/* )} */} + + {/* {props.permission("jydgl-btn-edit") && ( */} + + {/* )} */} + + {/* {props.permission("jydgl-btn-delete") && ( */} + + {/* )} */} + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_RESCUE_TEAM], true)(Permission(List)); diff --git a/src/pages/Container/BranchCompany/RescueTeam/View/index.js b/src/pages/Container/BranchCompany/RescueTeam/View/index.js new file mode 100644 index 0000000..da1fb97 --- /dev/null +++ b/src/pages/Container/BranchCompany/RescueTeam/View/index.js @@ -0,0 +1,119 @@ +import { Permission } from "@cqsjjb/jjb-common-decorator/permission"; +import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import { Button, Card, Descriptions, message, Table } from "antd"; +import { useEffect, useState } from "react"; +import Page from "zy-react-library/components/Page"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import { NS_RESCUE_TEAM } from "~/enumerate/namespace"; + +function View(props) { + const query = useGetUrlQuery(); + const [loading, setLoading] = useState(false); + const [detail, setDetail] = useState(null); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["rescueTeamDetail"]({ id: query.id }); + setDetail(data); + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + // 队员表格列定义 + const memberColumns = [ + { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 }, + { title: "队员", dataIndex: "personName" }, + { title: "队员电话", dataIndex: "personPhone" }, + ]; + + return ( + + {detail && ( + <> + + + + + +
index} + locale={{ emptyText: "暂无队员信息" }} + /> + + +
+ +
+ + )} + + ); +} + +export default Connect([NS_RESCUE_TEAM], true)(Permission(View)); diff --git a/src/pages/Container/BranchCompany/RescueTeam/index.js b/src/pages/Container/BranchCompany/RescueTeam/index.js new file mode 100644 index 0000000..ed6de56 --- /dev/null +++ b/src/pages/Container/BranchCompany/RescueTeam/index.js @@ -0,0 +1,4 @@ +function RescueTeam(props) { + return (
{props.children}
); +} +export default RescueTeam; diff --git a/src/pages/Container/BranchCompany/WaterSource/Add/index.js b/src/pages/Container/BranchCompany/WaterSource/Add/index.js new file mode 100644 index 0000000..93dd5d9 --- /dev/null +++ b/src/pages/Container/BranchCompany/WaterSource/Add/index.js @@ -0,0 +1,285 @@ +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 Page from "zy-react-library/components/Page"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import { NS_WATER_SOURCE } from "~/enumerate/namespace"; + +function Add(props) { + const query = useGetUrlQuery(); + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [submitting, setSubmitting] = useState(false); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["waterSourceDetail"]({ id: query.id }); + form.setFieldsValue(data); + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + const onFinish = async (values) => { + setSubmitting(true); + try { + const apiMethod = query.id ? props["waterSourceUpdate"] : props["waterSourceAdd"]; + const params = query.id ? { ...values, id: query.id } : values; + + await apiMethod(params); + message.success(query.id ? "修改成功" : "新增成功"); + props.history.goBack(); + } + catch (error) { + message.error(query.id ? "修改失败" : "新增失败"); + } + finally { + setSubmitting(false); + } + }; + + return ( + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +export default Connect([NS_WATER_SOURCE], true)(Permission(Add)); diff --git a/src/pages/Container/BranchCompany/WaterSource/List/index.js b/src/pages/Container/BranchCompany/WaterSource/List/index.js new file mode 100644 index 0000000..36eb366 --- /dev/null +++ b/src/pages/Container/BranchCompany/WaterSource/List/index.js @@ -0,0 +1,159 @@ +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 Page from "zy-react-library/components/Page"; +import Search from "zy-react-library/components/Search"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Table from "zy-react-library/components/Table"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_WATER_SOURCE } from "~/enumerate/namespace"; + +function List(props) { + const [form] = Form.useForm(); + const query = useGetUrlQuery(); + + const { tableProps, getData } = useTable(props["waterSourceList"], { form }); + + const [deleting, setDeleting] = useState(false); + const [statusDict, setStatusDict] = useState([]); + + const { getDictionary } = useDictionary(); + + useEffect(() => { + const fetchDict = async () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_water_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + useEffect(() => { + if (query.eqCorpId) { + form.setFieldsValue({ eqCorpId: query.eqCorpId }); + getData(); + } + }, [query.eqCorpId]); + + const getStatusLabel = (record) => { + if (record.sourceStatusName) + return record.sourceStatusName; + const match = statusDict.find(item => item.dictValue === record.waterSourceStatus); + return match?.dictLabel || record.sourceStatus || "-"; + }; + + const onDelete = (id) => { + Modal.confirm({ + title: "确认删除", + content: "删除后不可恢复,确认继续?", + okText: "确认", + cancelText: "取消", + okButtonProps: { danger: true, loading: deleting }, + onOk: async () => { + if (!props["waterSourceDelete"]) { + message.warning("未接入 waterSourceDelete effect"); + return; + } + setDeleting(true); + try { + await props["waterSourceDelete"]({ id }); + message.success("已删除"); + getData(); + } + finally { + setDeleting(false); + } + }, + }); + }; + + return ( + + ), + }, + { name: "likeBelongOrgDept", label: "所属单位或部门" }, + { name: "eqCorpId", onlyForLabel: true }, + ]} + form={form} + onFinish={getData} + /> +
( + + + + )} + columns={[ + // { title: "序号", width: 80, align: "center", render: (_, __, index) => index + 1 }, + { title: "消防水源名称", dataIndex: "waterSourceName", ellipsis: true }, + { + title: "消防水源状态", + width: 140, + align: "center", + render: (_, record) => getStatusLabel(record), + }, + { title: "所属单位或部门", dataIndex: "belongOrgDept", ellipsis: true }, + { title: "水源位置", dataIndex: "waterLocation", ellipsis: true }, + { + title: "操作", + fixed: "right", + width: 180, + render: (_, record) => ( + + + + + + + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_WATER_SOURCE], true)(Permission(List)); diff --git a/src/pages/Container/BranchCompany/WaterSource/View/index.js b/src/pages/Container/BranchCompany/WaterSource/View/index.js new file mode 100644 index 0000000..3e57c76 --- /dev/null +++ b/src/pages/Container/BranchCompany/WaterSource/View/index.js @@ -0,0 +1,270 @@ +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 { useEffect, useState } from "react"; +import Page from "zy-react-library/components/Page"; +import useDictionary from "zy-react-library/hooks/useDictionary"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import { NS_WATER_SOURCE } from "~/enumerate/namespace"; + +function View(props) { + const query = useGetUrlQuery(); + const [loading, setLoading] = useState(false); + const [detail, setDetail] = useState(null); + const [statusDict, setStatusDict] = useState([]); + + const { getDictionary } = useDictionary(); + + const getData = async () => { + setLoading(true); + try { + const { data } = await props["waterSourceDetail"]({ id: query.id }); + setDetail(data); + } + catch (error) { + message.error("加载详情失败"); + } + finally { + setLoading(false); + } + }; + + useEffect(() => { + query.id && getData(); + }, []); + + useEffect(() => { + const fetchDict = async () => { + try { + const dict = await getDictionary({ dictValue: "fire_resource_water_type" }); + setStatusDict(Array.isArray(dict) ? dict : []); + } + catch (error) { + setStatusDict([]); + } + }; + fetchDict(); + }, []); + + const getStatusLabel = (status) => { + if (!status) + return "-"; + const match = statusDict.find(item => item.dictValue === status); + return match?.dictLabel || status; + }; + + return ( + + {detail && ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + )} + + ); +} + +export default Connect([NS_WATER_SOURCE], true)(Permission(View)); diff --git a/src/pages/Container/BranchCompany/WaterSource/index.js b/src/pages/Container/BranchCompany/WaterSource/index.js new file mode 100644 index 0000000..a885bad --- /dev/null +++ b/src/pages/Container/BranchCompany/WaterSource/index.js @@ -0,0 +1,5 @@ +function Index(props) { + return (
{props.children}
); +} + +export default Index; diff --git a/src/pages/Container/BranchCompany/index.js b/src/pages/Container/BranchCompany/index.js new file mode 100644 index 0000000..3e9f496 --- /dev/null +++ b/src/pages/Container/BranchCompany/index.js @@ -0,0 +1,5 @@ +// 简单的路由容器 +function BranchCompany(props) { + return (
{props.children}
); +} +export default BranchCompany; diff --git a/src/pages/Container/Filiale/FireResourceStats/index.js b/src/pages/Container/Filiale/FireResourceStats/index.js new file mode 100644 index 0000000..80dca6c --- /dev/null +++ b/src/pages/Container/Filiale/FireResourceStats/index.js @@ -0,0 +1,112 @@ +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"; +import Search from "zy-react-library/components/Search"; +import Table from "zy-react-library/components/Table"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_FIRE_RESOURCE_STATS } from "~/enumerate/namespace"; + +function FireResourceStats(props) { + const [form] = Form.useForm(); + + 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}`); + } + }; + + return ( + + +
index + 1 }, + { + title: "企业名称", + dataIndex: "companyName", + ellipsis: true, + render: (text) => text || "一公司", + }, + { + title: "消防救援队数", + dataIndex: "rescueTeamCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "rescueTeam")} + > + {text || 0} + + ), + }, + { + title: "消防控制室数", + dataIndex: "controlRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "controlRoom")} + > + {text || 0} + + ), + }, + { + title: "消防泵房数", + dataIndex: "pumpRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "pumpRoom")} + > + {text || 0} + + ), + }, + { + title: "消防水源数", + dataIndex: "waterSourceCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "waterSource")} + > + {text || 0} + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats)); diff --git a/src/pages/Container/Filiale/FireTeam/index.js b/src/pages/Container/Filiale/FireTeam/index.js new file mode 100644 index 0000000..ad41cf3 --- /dev/null +++ b/src/pages/Container/Filiale/FireTeam/index.js @@ -0,0 +1,274 @@ +import { + ColumnHeightOutlined, + FullscreenOutlined, + PlusOutlined, + ReloadOutlined, + SearchOutlined, + SettingOutlined, +} from "@ant-design/icons"; +import { + Button, + Card, + Form, + Input, + message, + Select, + Space, + Table, + Tooltip, + Typography, +} from "antd"; +// RescueTeamPage.jsx +// 依赖:antd@5 +import React, { useMemo, useState } from "react"; + +const { Text } = Typography; + +export default function RescueTeamPage() { + const [form] = Form.useForm(); + + // mock 数据(你接后端时直接替换为接口) + const [data, setData] = useState([ + { + id: 1, + name: "救援队名称示例", + type: "专职消防队", + org: "负责单位示例", + leader: "张三", + commander: "李四", + memberCount: 5, + }, + ]); + + const columns = useMemo( + () => [ + { + title: "序号", + dataIndex: "idx", + width: 80, + align: "center", + render: (_, __, index) => index + 1, + }, + { title: "救援队名称", dataIndex: "name", ellipsis: true }, + { title: "类型", dataIndex: "type", width: 140, align: "center" }, + { title: "负责人单位或部门", dataIndex: "org", ellipsis: true }, + { title: "队长", dataIndex: "leader", width: 120, align: "center" }, + { title: "指挥人员", dataIndex: "commander", width: 120, align: "center" }, + { + title: "队员人数", + dataIndex: "memberCount", + width: 110, + align: "center", + }, + { + title: "操作", + key: "actions", + width: 220, + align: "center", + render: (_, record) => ( + + { + message.info(`查看:${record.name}`); + }} + > + 查看 + + { + message.info(`编辑:${record.name}`); + }} + > + 编辑 + + { + setData(prev => prev.filter(x => x.id !== record.id)); + message.success("已删除"); + }} + > + 删除 + + + ), + }, + ], + [setData], + ); + + const onSearch = async () => { + const values = await form.validateFields().catch(() => null); + if (!values) + return; + + // 这里接你的查询接口:values 里包含所有筛选条件 + // 示例:仅做前端过滤演示 + const { name, type, org, region, leader } = values; + const source = [ + { + id: 1, + name: "救援队名称示例", + type: "专职消防队", + org: "负责单位示例", + leader: "张三", + commander: "李四", + memberCount: 5, + }, + ]; + const filtered = source.filter((r) => { + const okName = !name || r.name.includes(name); + const okType = !type || r.type === type; + const okOrg = !org || r.org.includes(org); + const okLeader = !leader || r.leader.includes(leader); + // region 只是占位,后端一般按行政区划过滤 + const okRegion = !region || region === "内容待提供"; + return okName && okType && okOrg && okLeader && okRegion; + }); + setData(filtered); + }; + + const onReset = () => { + form.resetFields(); + // 你可以选择是否立刻拉取列表 + onSearch(); + }; + + const onCreate = () => { + message.info("新增:打开新增弹窗/跳转新增页"); + }; + + return ( +
+
+ {/* 顶部筛选 */} + +
+
+ + + + + + + + + + * + 所属区域范围 + + )} + name="region" + style={{ marginBottom: 0 }} + rules={[{ required: true, message: "请选择所属区域范围" }]} + > + + +
+
+
+
+
+ + + + {/* 列表区 */} + + {/* 工具条 */} +
+ + + +
+ +
+ + + + ); +} diff --git a/src/pages/Container/Supervision/FireResourceStats/index.js b/src/pages/Container/Supervision/FireResourceStats/index.js new file mode 100644 index 0000000..14b2d8d --- /dev/null +++ b/src/pages/Container/Supervision/FireResourceStats/index.js @@ -0,0 +1,112 @@ +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"; +import Search from "zy-react-library/components/Search"; +import Table from "zy-react-library/components/Table"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_FIRE_RESOURCE_STATS } from "~/enumerate/namespace"; + +function FireResourceStats(props) { + const [form] = Form.useForm(); + + 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]}?eqCorpId=${corpId}`); + } + }; + + return ( + + +
index + 1 }, + { + title: "企业名称", + dataIndex: "corpName", + ellipsis: true, + render: text => text || "一公司", + width: 200, + }, + { + title: "消防救援队数", + dataIndex: "rescueTeamCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "rescueTeam")} + > + {text || 0} + + ), + }, + { + title: "消防控制室数", + dataIndex: "controlRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "controlRoom")} + > + {text || 0} + + ), + }, + { + title: "消防泵房数", + dataIndex: "pumpRoomCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "pumpRoom")} + > + {text || 0} + + ), + }, + { + title: "消防水源数", + dataIndex: "waterSourceCount", + width: 140, + align: "center", + render: (text, record) => ( + handleViewDetail(record, "waterSource")} + > + {text || 0} + + ), + }, + ]} + {...tableProps} + /> + + ); +} + +export default Connect([NS_FIRE_RESOURCE_STATS], true)(Permission(FireResourceStats)); diff --git a/src/pages/Container/Supervision/index.js b/src/pages/Container/Supervision/index.js new file mode 100644 index 0000000..e75052e --- /dev/null +++ b/src/pages/Container/Supervision/index.js @@ -0,0 +1,5 @@ +function Index(props) { + return (
{props.children}
); +} + +export default Index;