From e0dac3d2de9ac359167acf623435303e6c3fd150 Mon Sep 17 00:00:00 2001 From: fangjiakai <450850793@qq.com> Date: Fri, 19 Dec 2025 17:56:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(enclosedArea):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=B0=81=E9=97=AD=E5=8C=BA=E5=9F=9F=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现封闭区域的列表展示、新增、编辑、删除功能 - 支持封闭区域的父子层级结构展示与跳转 - 集成地图组件用于显示和选择封闭区域位置 - 提供查看详情弹窗,支持地理位置查看 - 封装通用表格与搜索组件提升复用性 - 添加权限控制字段便于后续权限配置接入 --- src/api/enclosedArea/index.js | 24 ++ .../Container/EnclosedArea/List/index.js | 248 +++++++++++++++ .../MkmjArea/FirstLevelArea/index.js | 16 + .../MkmjArea/SecondLevelArea/index.js | 16 + .../SuperviseSecondLevelArea/index.js | 17 + .../MkmjArea/components/Area/index.js | 301 ++++++++++++++++++ 6 files changed, 622 insertions(+) create mode 100644 src/api/enclosedArea/index.js create mode 100644 src/pages/Container/EnclosedArea/List/index.js create mode 100644 src/pages/Container/MkmjArea/FirstLevelArea/index.js create mode 100644 src/pages/Container/MkmjArea/SecondLevelArea/index.js create mode 100644 src/pages/Container/MkmjArea/SuperviseSecondLevelArea/index.js create mode 100644 src/pages/Container/MkmjArea/components/Area/index.js diff --git a/src/api/enclosedArea/index.js b/src/api/enclosedArea/index.js new file mode 100644 index 0000000..8f7e259 --- /dev/null +++ b/src/api/enclosedArea/index.js @@ -0,0 +1,24 @@ +import {declareRequest} from '@cqsjjb/jjb-dva-runtime'; + +export const enclosedAreaList = declareRequest( + 'enclosedAreaLoading', + 'Post > @/risk/enclosedArea/list', +); +export const enclosedAreaAdd = declareRequest( + 'enclosedAreaLoading', + 'Post > @/risk/enclosedArea/save' +); +export const enclosedAreaEdit = declareRequest( + 'enclosedAreaLoading', + 'Put > @/risk/enclosedArea/edit' +); +export const enclosedAreaDelete = declareRequest( + 'enclosedAreaLoading', + 'Delete > @/risk/enclosedArea/{id}' +); +export const enclosedAreaBatchDelete = declareRequest( + 'enclosedAreaLoading', + 'Delete > @/risk/enclosedArea/ids/{ids}' +); +export const enclosedAreaInfo = declareRequest('enclosedAreaLoading', 'Get > /risk/enclosedArea/{id}'); + diff --git a/src/pages/Container/EnclosedArea/List/index.js b/src/pages/Container/EnclosedArea/List/index.js new file mode 100644 index 0000000..e744f64 --- /dev/null +++ b/src/pages/Container/EnclosedArea/List/index.js @@ -0,0 +1,248 @@ +import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import { Button, Form, message, Modal, Space, Descriptions } from "antd"; +import { useEffect, useState } from "react"; +import FormBuilder from "zy-react-library/components/FormBuilder"; +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_ENCLOSEDAREA } from "~/enumerate/namespace"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import AddIcon from "zy-react-library/components/Icon/AddIcon"; +import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; +import Map from "zy-react-library/components/Map"; +import LocationIcon from "zy-react-library/components/Icon/LocationIcon"; +import MapSelector from "zy-react-library/components/Map/MapSelector"; + + +function EnclosedArea(props) { + const { parentId, parentName } = useGetUrlQuery(); + const [addModalVisible, setAddModalVisible] = useState(false); + const [infoModalVisible, setInfoModalVisible] = useState(false); + const [currentId, setCurrentId] = useState(""); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [form] = Form.useForm(); + const { tableProps, getData } = useTable(props["enclosedAreaList"], { + form, + params: { + eqParentId: parentId || 0, + } + }); + + const onDelete = async (record) => { + if (record.childCount > 0 || record.useCount > 0) + return message.warning("正在使用中的封闭区域不能删除"); + await props["enclosedAreaDelete"]({ id: record.id }); + message.success("删除成功"); + getData(); + }; + return ( +
+ {parentId && } + }, + ]} + /> + setSelectedRowKeys(selectedRowKeys), + }} + toolBarRender={() => ( + + + + )} + columns={[ + { + dataIndex: "name", title: "封闭区域名称", render: (_, record) => ( + + ), + }, + { dataIndex: "typeName", title: "封闭区域类型" }, + { + title: "操作", + align: "center", + width: 200, + render: (_, record) => ( + + + + + + ), + }, + ]} + {...tableProps} + /> + { + setAddModalVisible(false); + setCurrentId(""); + }} + getData={getData} + /> + + { + setInfoModalVisible(false); + setCurrentId(""); + }} + getData={getData} + /> + + ); +} + +function AddModalComponent(props) { + const [form] = Form.useForm(); + useEffect(() => { + if (props.currentId) { + props["enclosedAreaInfo"]({ id: props.currentId }).then((res) => { + form.setFieldsValue(res.data); + }); + } + }, [props.currentId]); + const onCancel = () => { + form.resetFields(); + props.onCancel(); + }; + const submit = async (values) => { + await props[!props.currentId ? "enclosedAreaAdd" : "enclosedAreaEdit"]({ ...values, id: props.currentId, parentId: props.parentId }); + onCancel(); + props.getData(); + }; + return ( + + {parentName}, + }, + { name: "name", label: "封闭区域名称" }, + { + name: "type", label: "封闭区域类型", render: ( + { + form.setFieldValue("typeName", label); + }} + /> + ), + }, + { name: "typeName", label: "封闭区域类型", onlyForLabel: true }, + { key: "map", customizeRender: true, render: }, + ]} + /> + + ); +} + +function InfoModalComponent(props) { + const [info, setInfo] = useState({}); + const [mapVisible, setMapVisible] = useState(false); + useEffect(() => { + if (props.currentId) { + props["enclosedAreaInfo"]({ id: props.currentId }).then((res) => { + setInfo(res.data); + }); + } + }, [props.currentId]); + + return ( + 关闭} + title="查看" + loading={props.enclosedArea.loading} + > + { + setMapVisible(true); + }} />, label: "位置" + }, + ]} + /> + + setMapVisible(false)} + longitude={info.longitude} + latitude={info.latitude} + disable={true} + /> + + ); +} + +const AddModal = Connect([NS_ENCLOSEDAREA], true)(AddModalComponent); +const InfoModal = Connect([NS_ENCLOSEDAREA], true)(InfoModalComponent); +export default Connect([NS_ENCLOSEDAREA], true)(EnclosedArea); + diff --git a/src/pages/Container/MkmjArea/FirstLevelArea/index.js b/src/pages/Container/MkmjArea/FirstLevelArea/index.js new file mode 100644 index 0000000..202a085 --- /dev/null +++ b/src/pages/Container/MkmjArea/FirstLevelArea/index.js @@ -0,0 +1,16 @@ +import Area from "../components/Area"; + +function AreaContainer(props) { + return ( + + ); +} + +export default AreaContainer; diff --git a/src/pages/Container/MkmjArea/SecondLevelArea/index.js b/src/pages/Container/MkmjArea/SecondLevelArea/index.js new file mode 100644 index 0000000..bc2e4db --- /dev/null +++ b/src/pages/Container/MkmjArea/SecondLevelArea/index.js @@ -0,0 +1,16 @@ +import Area from "../components/Area"; + +function AreaContainer(props) { + return ( + + ); +} + +export default AreaContainer; diff --git a/src/pages/Container/MkmjArea/SuperviseSecondLevelArea/index.js b/src/pages/Container/MkmjArea/SuperviseSecondLevelArea/index.js new file mode 100644 index 0000000..950f4e4 --- /dev/null +++ b/src/pages/Container/MkmjArea/SuperviseSecondLevelArea/index.js @@ -0,0 +1,17 @@ +import Area from "../components/Area"; + +function AreaContainer(props) { + return ( + + ); +} + +export default AreaContainer; diff --git a/src/pages/Container/MkmjArea/components/Area/index.js b/src/pages/Container/MkmjArea/components/Area/index.js new file mode 100644 index 0000000..228c880 --- /dev/null +++ b/src/pages/Container/MkmjArea/components/Area/index.js @@ -0,0 +1,301 @@ +import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import { Button, Form, message, Modal, Space, Descriptions } from "antd"; +import { useEffect, useState } from "react"; +import FormBuilder from "zy-react-library/components/FormBuilder"; +import Search from "zy-react-library/components/Search"; +import Table from "zy-react-library/components/Table"; +import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender"; +import useTable from "zy-react-library/hooks/useTable"; +import { NS_MKMJAREA } from "~/enumerate/namespace"; +import AddIcon from "zy-react-library/components/Icon/AddIcon"; +import DeleteIcon from "zy-react-library/components/Icon/DeleteIcon"; +import LocationIcon from "zy-react-library/components/Icon/LocationIcon"; +import DictionarySelect from "zy-react-library/components/Select/Dictionary"; +import Map from "zy-react-library/components/Map"; +import MapSelector from "zy-react-library/components/Map/MapSelector"; +import { getLabelName } from "zy-react-library/utils" + +const AREA_TYPE = [ + { name: "人行口门", bianma: "1" }, + { name: "车行口门", bianma: "2" }, + { name: "综合口门", bianma: "3" }, +] + +const AREA_STATUS = [ + { name: "停用", bianma: "0" }, + { name: "正常", bianma: "1" }, + { name: "暂时关闭", bianma: "2" }, +] + +function MkmjArea(props) { + const [addModalVisible, setAddModalVisible] = useState(false); + const [infoModalVisible, setInfoModalVisible] = useState(false); + const [currentId, setCurrentId] = useState(""); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [form] = Form.useForm(); + const { tableProps, getData } = useTable(props["mkmjAreaList"], { + form, + params: { + eqAreaLevel: props.areaLevel, + } + }); + + const onDelete = async (record) => { + if (record.videoNum > 0 || record.passageNum > 0) + return message.warning("正在使用中的口门不能删除"); + await props["mkmjAreaDelete"]({ id: record.id }); + message.success("删除成功"); + getData(); + }; + + return ( +
+ }, + ]} + /> +
setSelectedRowKeys(selectedRowKeys), + }} + toolBarRender={() => ( + + + + )} + columns={[ + { dataIndex: "areaParentName", title: "所属区域" }, + { + dataIndex: "areaType", title: "口门类型", render: (_, record) => { + return record.areaType === 1 ? "人行口门" : record.areaType === 2 ? "车行口门" : "综合口门"; + } + }, + { dataIndex: "areaName", title: "口门名称" }, + { + dataIndex: "location", title: "口门位置", render: (_, record) => { + return `${record.latitude || ""}--${record.longitude || ""}`; + } + }, + { dataIndex: "corpInfoName", title: "管辖单位", hidden: props.areaLevel === 1 }, + { + dataIndex: "videoNum", title: "视频个数", render: (_, record) => { + return record.videoNum || 0; + } + }, + { + dataIndex: "areaStatus", title: "口门状态", render: (_, record) => { + return record.areaStatus === 0 ? "停用" : record.areaStatus === 1 ? "正常" : "暂时关闭"; + } + }, + { + title: "操作", + align: "center", + width: 200, + render: (_, record) => ( + + + + + + + + ), + }, + ]} + {...tableProps} + /> + {addModalVisible && { + setAddModalVisible(false); + setCurrentId(""); + }} + getData={getData} + />} + + {infoModalVisible && { + setInfoModalVisible(false); + setCurrentId(""); + }} + getData={getData} + />} + + ); +} + +function AddModalComponent(props) { + const [form] = Form.useForm(); + const [corpInfoList, setCorpInfoList] = useState([]); + + useEffect(() => { + props["getCorpInfoList"]({}).then((res) => { + setCorpInfoList(res.data || []); + }); + + if (props.currentId) { + props["mkmjAreaInfo"]({ id: props.currentId }).then((res) => { + form.setFieldsValue({ + ...res.data, + areaType: res.data.areaType + "", + areaStatus: res.data.areaStatus + "", + }); + }); + } + }, [props.currentId]); + const onCancel = () => { + form.resetFields(); + props.onCancel(); + }; + const submit = async (values) => { + await props[!props.currentId ? "mkmjAreaAdd" : "mkmjAreaEdit"]({ ...values, areaLevel: props.areaLevel, id: props.currentId }); + onCancel(); + props.getData(); + }; + return ( + + form.setFieldValue("areaParentName", label)} /> }, + { name: "areaParentName", label: "所属区域", onlyForLabel: true }, + { + name: "corpInfoId", label: "管辖单位", render: FORM_ITEM_RENDER_ENUM.SELECT, items: corpInfoList, + itemsField: { valueKey: "id", labelKey: "corpName" }, + componentProps: { onChange: (value) => form.setFieldValue("corpInfoName", getLabelName({ status: value, list: corpInfoList, idKey: "id", nameKey: "corpName" })) }, + hidden: !(props.areaLevel === 2 && props.isSupervise), + }, + { name: "corpInfoName", label: "管辖单位", onlyForLabel: true }, + { name: "areaName", label: "口门名称" }, + { name: "areaType", label: "口门类型", render: FORM_ITEM_RENDER_ENUM.SELECT, items: AREA_TYPE }, + { name: "areaRange", label: "口门位置" }, + { key: "map", customizeRender: true, render: }, + { name: "areaStatus", label: "口门状态", render: FORM_ITEM_RENDER_ENUM.SELECT, items: AREA_STATUS } + + ]} + /> + + ); +} + +function InfoModalComponent(props) { + const [info, setInfo] = useState({}); + const [mapVisible, setMapVisible] = useState(false); + + useEffect(() => { + if (props.currentId) { + props["mkmjAreaInfo"]({ id: props.currentId }).then((res) => { + setInfo(res.data); + }); + } + }, [props.currentId]); + + return ( + 关闭} + title="查看" + loading={props.mkmjArea.loading} + > + { + setMapVisible(true); + }} />, label: "位置" + }, + ]} + /> + + setMapVisible(false)} + longitude={info.longitude} + latitude={info.latitude} + disable={true} + /> + + ); +} + +const AddModal = Connect([NS_MKMJAREA], true)(AddModalComponent); +const InfoModal = Connect([NS_MKMJAREA], true)(InfoModalComponent); +export default Connect([NS_MKMJAREA], true)(MkmjArea); +