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={() => (
+
+ } onClick={() => setAddModalVisible(true)}>新增
+
+ )}
+ 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={() => (
+
+ } onClick={() => setAddModalVisible(true)}>新增
+
+ )}
+ 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);
+