Browse Source

虚拟单位重组功能开发

dev-V1.0.1
庄锐波 6 months ago
parent
commit
31efb8a7d0
  1. 262
      doc/执法码二期部署与网络架构图.drawio
  2. 2
      script/sql/zfjd-refactoring-v1/005-2-重新整理二期菜单结构.sql
  3. 27
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java
  4. 51
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/UnitUserVo.java
  5. 16
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java
  6. 19
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java
  7. 33
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java
  8. 35
      zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml
  9. 37
      zdxt-web-client/zdxt-admin-plus-ui/.env.development-zrb-cust
  10. 1
      zdxt-web-client/zdxt-admin-plus-ui/package.json
  11. 29
      zdxt-web-client/zdxt-admin-plus-ui/src/api/efcode/virtualUnit/index.ts
  12. 14
      zdxt-web-client/zdxt-admin-plus-ui/src/api/efcode/virtualUnit/types.ts
  13. 383
      zdxt-web-client/zdxt-admin-plus-ui/src/views/efcode/virtualUnit/unitUserManager.vue
  14. 2
      zdxt-web-client/zdxt-admin-plus-ui/vite.config.ts

262
doc/执法码二期部署与网络架构图.drawio

@ -0,0 +1,262 @@
<mxfile host="Electron" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36">
<diagram name="Page-1" id="c37626ed-c26b-45fb-9056-f9ebc6bb27b6">
<mxGraphModel dx="3334" dy="2219" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" background="none" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="b-FJFzzGnGtQVewlCTX0-26" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="400" />
<mxPoint x="490" y="788" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-95" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-26" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="-0.5815" y="2" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-1" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="企业端前端服务器" vertex="1">
<mxGeometry height="75" width="51" x="212" y="370" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-27" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="700" />
<mxPoint x="490" y="787" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-31" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-27" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="-0.4042" y="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-2" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="执法端前端服务器" vertex="1">
<mxGeometry height="75" width="51" x="210" y="660" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-34" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-22">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="870" y="788" />
<mxPoint x="870" y="408" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-38" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-34" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="0.4177" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-35" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-23">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-37" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-35" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="0.407" y="5" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-36" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-25">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="870" y="788" />
<mxPoint x="870" y="1138" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-39" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-36" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="0.0262" y="3" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-3" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="执法端二期内部网关服务器" vertex="1">
<mxGeometry height="75" width="51" x="630" y="750" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-14" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:ngnix&lt;/li&gt;&lt;li&gt;部署:企业端APP[zdxt-ent-app]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:互联网&lt;/span&gt;&lt;/li&gt;&lt;li&gt;EIP:&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:12001&lt;/li&gt;&lt;li&gt;协议:HTTP&lt;/li&gt;&lt;li&gt;待完成工作:企业端APP开发&lt;/li&gt;&lt;li&gt;待完成工作:NG转发规则配置&lt;/li&gt;&lt;li&gt;待完成工作:与深i企前端接入&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="170" width="280" x="80" y="200" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-15" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:ngnix&lt;/li&gt;&lt;li&gt;部署:执法端APP[zdxt-enf-app]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:互联网&lt;/span&gt;&lt;/li&gt;&lt;li&gt;EIP:&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:12002&lt;/li&gt;&lt;li&gt;协议:HTTP&lt;/li&gt;&lt;li&gt;待完成工作:执法端APP开发&lt;/li&gt;&lt;li&gt;待完成工作:NG转发规则配置&lt;/li&gt;&lt;li&gt;待完成工作:与深政易前端接入&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="160" width="280" x="80" y="500" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-28" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="960" />
<mxPoint x="490" y="788" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-32" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-28" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="-0.5615" y="2" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-16" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="监督端前端服务器" vertex="1">
<mxGeometry height="75" width="51" x="210" y="930" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-17" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:ngnix&lt;/li&gt;&lt;li&gt;部署:监督端APP[zdxt-sup-app]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:互联网&lt;/span&gt;&lt;/li&gt;&lt;li&gt;EIP:&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:12003&lt;/li&gt;&lt;li&gt;协议:HTTP&lt;/li&gt;&lt;li&gt;待完成工作:监督端APP开发&lt;/li&gt;&lt;li&gt;待完成工作:NG转发规则配置&lt;/li&gt;&lt;li&gt;待完成工作:与深政易前端接入&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="150" width="280" x="80" y="780" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-29" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="490" y="1230" />
<mxPoint x="490" y="788" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-33" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-29" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="HTTP请求" vertex="1">
<mxGeometry relative="1" x="-0.6786" y="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-18" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="监督端前端服务器" vertex="1">
<mxGeometry height="75" width="51" x="210" y="1200" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-19" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:ngnix&lt;/li&gt;&lt;li&gt;部署:监督端Web[zdxt-sup-web]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:政务外网&lt;/span&gt;&lt;/li&gt;&lt;li&gt;EIP:&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:12004&lt;/li&gt;&lt;li&gt;协议:HTTP&lt;/li&gt;&lt;li&gt;待完成工作:监督端Web开发&lt;/li&gt;&lt;li&gt;待完成工作:NG转发规则配置&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="150" width="280" x="80" y="1050" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-20" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;依赖环境:JDK17&lt;/li&gt;&lt;li&gt;部署:网关服务[zdxt-gateway-web-server.jar]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:&lt;/span&gt;政务外网&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:17000&lt;/li&gt;&lt;li&gt;待完成工作:转发服务规则配置&lt;/li&gt;&lt;li&gt;待完成工作:白名单限制功能开发和配置[系统统一在这里设置白名单就可以]&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="140" width="300" x="531" y="610" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-22" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="企业端后端服务器" vertex="1">
<mxGeometry height="75" width="51" x="1030" y="370" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-23" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="执法端后端服务器" vertex="1">
<mxGeometry height="75" width="51" x="1030" y="750" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-25" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="监督端后端服务器" vertex="1">
<mxGeometry height="75" width="51" x="1030" y="1100" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-40" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;依赖环境:JDK17&lt;/li&gt;&lt;li&gt;部署:企业端后端服务[zdxt-ent-ep.jar]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:&lt;/span&gt;政务外网&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:18000&lt;/li&gt;&lt;li&gt;待完成工作:企业端服务端功能开发&lt;/li&gt;&lt;li&gt;待完成工作:与深i企的后端对接&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="140" width="300" x="910" y="230" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-43" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="代理出口服务器" vertex="1">
<mxGeometry height="75" width="51" x="1454.5" y="170" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-44" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:ngnix&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:19000&lt;/li&gt;&lt;li&gt;待完成工作:NG转发规则配置&lt;/li&gt;&lt;li&gt;备注:将所有出口的请求全部放到这个服务器,内部通过这个服务器中转.以后做网络策略和与外部申请开通配置就可以集中到这里&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="140" width="300" x="1560" y="170" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-49" parent="1" style="ellipse;whiteSpace=wrap;html=1;" value="深i企的获取企业信息接口" vertex="1">
<mxGeometry height="70" width="160" x="1120" y="-130" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-50" parent="1" style="ellipse;whiteSpace=wrap;html=1;" value="市统一认证数据" vertex="1">
<mxGeometry height="80" width="160" x="1345.5" y="-130" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-51" parent="1" style="ellipse;whiteSpace=wrap;html=1;" value="短信接口" vertex="1">
<mxGeometry height="80" width="120" x="1560" y="-130" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-52" parent="1" style="ellipse;whiteSpace=wrap;html=1;" value="易平台" vertex="1">
<mxGeometry height="80" width="120" x="1760" y="-120" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-53" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="DATAX数据同步服务器" vertex="1">
<mxGeometry height="75" width="51" x="1980" y="730" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-54" parent="1" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" value="执法码系统主库" vertex="1">
<mxGeometry height="140" width="110" x="1720" y="510" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-55" parent="1" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" value="执法码数据前缀库" vertex="1">
<mxGeometry height="140" width="110" x="1720" y="830" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-56" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="Redis&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;服务器&lt;/span&gt;" vertex="1">
<mxGeometry height="75" width="51" x="1384.5" y="1080" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-66" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-57" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="b-FJFzzGnGtQVewlCTX0-58">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-67" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-66" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="做文件备份" vertex="1">
<mxGeometry relative="1" x="-0.0786" y="4" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-57" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;文件服务器(主)&lt;/span&gt;" vertex="1">
<mxGeometry height="75" width="51" x="1410" y="735" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-58" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="文件服务器(备)" vertex="1">
<mxGeometry height="75" width="51" x="1599" y="735" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-59" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;部署:Redis&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:&lt;/span&gt;政务外网&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:6379&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="70" width="210" x="1330" y="1005" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-77" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="3台后端服务器需要采用相同设置" vertex="1">
<mxGeometry height="792.5" width="30" x="1220" y="360" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-78" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-77" style="endArrow=classic;html=1;rounded=0;exitX=1.008;exitY=0.932;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-56" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1220" y="1140" as="sourcePoint" />
<mxPoint x="1270" y="1090" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-79" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-77" style="endArrow=classic;html=1;rounded=0;exitX=1.109;exitY=0.072;exitDx=0;exitDy=0;exitPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-43" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1310" y="470" as="sourcePoint" />
<mxPoint x="1360" y="420" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-81" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-43" style="endArrow=classic;html=1;rounded=0;entryX=0.642;entryY=0.952;entryDx=0;entryDy=0;entryPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-49" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1280" y="80" as="sourcePoint" />
<mxPoint x="1330" y="30" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-82" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-43" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="b-FJFzzGnGtQVewlCTX0-50" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1450" y="130" as="sourcePoint" />
<mxPoint x="1500" y="80" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-83" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-43" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="b-FJFzzGnGtQVewlCTX0-51" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1573" y="340" as="sourcePoint" />
<mxPoint x="1530" y="120" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-85" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-43" style="endArrow=classic;html=1;rounded=0;entryX=0.387;entryY=0.964;entryDx=0;entryDy=0;entryPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-52" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1580" y="110" as="sourcePoint" />
<mxPoint x="1630" y="60" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-86" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-77" style="endArrow=classic;html=1;rounded=0;exitX=0.92;exitY=0.518;exitDx=0;exitDy=0;exitPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-57" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1150" y="840" as="sourcePoint" />
<mxPoint x="1200" y="790" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-87" connectable="0" parent="b-FJFzzGnGtQVewlCTX0-86" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="通过NFS挂载成本地磁盘" vertex="1">
<mxGeometry relative="1" x="0.1294" as="geometry">
<mxPoint x="-11" y="-8" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-88" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;依赖环境:JDK17&lt;/li&gt;&lt;li&gt;部署:执法端后端服务[zdxt-enf-ep.jar]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:&lt;/span&gt;政务外网&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:18001&lt;/li&gt;&lt;li&gt;待完成工作:企业端服务端功能开发&lt;/li&gt;&lt;li&gt;待完成工作:&lt;span style=&quot;text-align: center;&quot;&gt;市统一认证数据&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="140" width="300" x="890" y="600" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-89" parent="1" style="rounded=0;whiteSpace=wrap;html=1;align=left;" value="&lt;ul&gt;&lt;li&gt;依赖环境:JDK17&lt;/li&gt;&lt;li&gt;部署:监督端后端服务[zdxt-enf-ep.jar]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;所在网络:&lt;/span&gt;政务外网&lt;/li&gt;&lt;li&gt;内部IP:&lt;/li&gt;&lt;li&gt;开放端口:18002&lt;/li&gt;&lt;li&gt;待完成工作:监督端服务端功能开发&lt;/li&gt;&lt;li&gt;待完成工作:&lt;span style=&quot;text-align: center;&quot;&gt;市统一认证数据,易平台&lt;/span&gt;&lt;/li&gt;&lt;li&gt;定时同步任务在这里开启,其他2个服务不要开启定时任务&lt;/li&gt;&lt;/ul&gt;" vertex="1">
<mxGeometry height="140" width="300" x="905.5" y="960" as="geometry" />
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-90" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-53" style="endArrow=classic;html=1;rounded=0;" target="b-FJFzzGnGtQVewlCTX0-55" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1910" y="730" as="sourcePoint" />
<mxPoint x="1960" y="680" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-91" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-53" style="endArrow=classic;html=1;rounded=0;entryX=0.965;entryY=0.626;entryDx=0;entryDy=0;entryPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-54" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1981" y="720" as="sourcePoint" />
<mxPoint x="2031" y="670" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-92" edge="1" parent="1" source="b-FJFzzGnGtQVewlCTX0-77" style="endArrow=classic;html=1;rounded=0;exitX=1.02;exitY=0.28;exitDx=0;exitDy=0;exitPerimeter=0;" target="b-FJFzzGnGtQVewlCTX0-54" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="1380" y="570" as="sourcePoint" />
<mxPoint x="1430" y="520" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="b-FJFzzGnGtQVewlCTX0-93" parent="1" style="sketch=0;html=1;pointerEvents=1;dashed=0;fillColor=#036897;strokeColor=#ffffff;strokeWidth=2;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.cisco.buildings.branch_office;" value="后备用" vertex="1">
<mxGeometry height="75" width="51" x="1030" y="1380" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

2
script/sql/zfjd-refactoring-v1/005-2-重新整理二期菜单结构.sql

@ -45,7 +45,7 @@ INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component,
-- 执法码单位与人员 子菜单 (parent_id = 2002)
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, url, target, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, system_code, type) VALUES (2010, '执法单位设置', 2002, 1, 'unitBuilder', 'efcode/virtualUnit/unitBuilder', '', 1, 0, '#', '', 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, '2026-03-31 20:14:46', null, null, '执法单位设置菜单', 'authService', null);
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, url, target, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, system_code, type) VALUES (2011, '执法人员设置', 2002, 2, 'efuser', '', '', 1, 0, '#', '', 'C', '0', '0', 'efcode:user:list', 'user', 103, 1, '2026-03-31 20:14:46', null, null, '执法人员设置菜单', 'authService', null);
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, url, target, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, system_code, type) VALUES (2011, '执法人员设置', 2002, 2, 'efuser', 'efcode/virtualUnit/unitUserManager', '', 1, 0, '#', '', 'C', '0', '0', 'efcode:user:list', 'user', 103, 1, '2026-03-31 20:14:46', null, null, '执法人员设置菜单', 'authService', null);
-- 机构与权限管理 辅助隐藏页面
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, url, target, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark, system_code, type) VALUES (2020, '分配用户', 20, 4, 'role-auth/user/:roleId', 'system/role/authUser', '', 1, 1, '#', '', 'C', '1', '0', 'system:role:edit', '#', 103, 1, '2026-03-31 20:14:46', null, null, '/system/role', 'authService', null);

27
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/EfcodeVirtualUnitController.java

@ -18,6 +18,7 @@ import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo;
import com.zdxt.enforcementcode.domain.vo.UnitUserVo;
import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo;
import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@ -55,6 +56,32 @@ public class EfcodeVirtualUnitController extends BaseController {
return R.ok(efcodeVirtualUnitService.queryTreeList());
}
/**
* 查询业务可见的虚拟单位树列表(vir_show_at_business='1')
*/
@SaCheckPermission("enforcementcode:virtualUnit:list")
@GetMapping("/businessTreeList")
public R<List<EfcodeVirtualUnitVo>> businessTreeList() {
return R.ok(efcodeVirtualUnitService.queryBusinessTreeList());
}
/**
* 根据虚拟单位分页查询关联人员列表
*
* @param sysDeptId 虚拟单位对应的部门ID
* @param keyword 搜索关键字
* @param globalSearch 是否全局搜索
*/
@SaCheckPermission("enforcementcode:virtualUnit:list")
@GetMapping("/users")
public TableDataInfo<UnitUserVo> queryUsers(
@RequestParam(required = false) String sysDeptId,
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "false") boolean globalSearch,
PageQuery pageQuery) {
return efcodeVirtualUnitService.queryUsersBySysDeptId(sysDeptId, keyword, globalSearch, pageQuery);
}
/**
* 导出虚拟单位树列表
*/

51
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/UnitUserVo.java

@ -0,0 +1,51 @@
package com.zdxt.enforcementcode.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 虚拟单位人员列表VO(无@Translation,避免N+1查询)
*/
@Data
public class UnitUserVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
private Long userId;
/**
* 部门ID
*/
private String deptId;
/**
* 用户账号
*/
private String userName;
/**
* 姓名
*/
private String fullname;
/**
* 手机号(市认证同步)
*/
private String mobileNumber;
/**
* 部门路径(来自sys_dept.zzDisplayPath,已去除"深圳市/"前缀)
*/
private String zzDisplayPath;
/**
* 是否为下级部门用户
*/
private Boolean isSubDeptUser;
}

16
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EfcodeVirtualUnitMapper.java

@ -1,8 +1,12 @@
package com.zdxt.enforcementcode.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit;
import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo;
import com.zdxt.enforcementcode.domain.vo.UnitUserVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
@ -14,4 +18,16 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@Mapper
public interface EfcodeVirtualUnitMapper extends BaseMapperPlus<EfcodeVirtualUnit, EfcodeVirtualUnitVo> {
/**
* 查询虚拟单位关联的人员列表
*
* @param sysDeptId 虚拟单位对应的部门ID
* @param keyword 搜索关键字
* @param globalSearch 是否全局搜索
* @return 人员列表
*/
IPage<UnitUserVo> selectUnitUsers(Page<UnitUserVo> page,
@Param("sysDeptId") String sysDeptId,
@Param("keyword") String keyword,
@Param("globalSearch") boolean globalSearch);
}

19
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeVirtualUnitService.java

@ -1,6 +1,7 @@
package com.zdxt.enforcementcode.service;
import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo;
import com.zdxt.enforcementcode.domain.vo.UnitUserVo;
import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
@ -73,6 +74,24 @@ public interface IEfcodeVirtualUnitService {
*/
List<EfcodeVirtualUnitVo> queryTreeList();
/**
* 查询业务可见的虚拟单位树列表(vir_show_at_business='1')
*
* @return 虚拟单位树列表
*/
List<EfcodeVirtualUnitVo> queryBusinessTreeList();
/**
* 根据虚拟单位的sysDeptId分页查询关联人员列表
*
* @param sysDeptId 虚拟单位对应的部门ID
* @param keyword 搜索关键字(可选)
* @param globalSearch 是否全局搜索
* @param pageQuery 分页参数
* @return 人员分页列表
*/
TableDataInfo<UnitUserVo> queryUsersBySysDeptId(String sysDeptId, String keyword, boolean globalSearch, PageQuery pageQuery);
/**
* 是否存在子节点
*

33
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeVirtualUnitServiceImpl.java

@ -1,7 +1,6 @@
package com.zdxt.enforcementcode.service.impl;
import com.zdxt.enforcementcode.mapper.SrzDeptMapper;
import com.zdxt.enforcementcode.service.ISrzDeptService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@ -15,17 +14,16 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.zdxt.enforcementcode.domain.bo.EfcodeVirtualUnitBo;
import com.zdxt.enforcementcode.domain.vo.EfcodeVirtualUnitVo;
import com.zdxt.enforcementcode.domain.vo.UnitUserVo;
import com.zdxt.enforcementcode.domain.EfcodeVirtualUnit;
import com.zdxt.enforcementcode.mapper.EfcodeVirtualUnitMapper;
import com.zdxt.enforcementcode.service.IEfcodeVirtualUnitService;
import org.dromara.system.domain.SysDept;
import org.dromara.system.mapper.SysDeptMapper;
import com.zdxt.enforcementcode.domain.vo.SrzDeptVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -217,6 +215,31 @@ public class EfcodeVirtualUnitServiceImpl implements IEfcodeVirtualUnitService {
return baseMapper.selectVoList(lqw);
}
/**
* 查询业务可见的虚拟单位树列表(vir_show_at_business='1')
*/
@Override
public List<EfcodeVirtualUnitVo> queryBusinessTreeList() {
LambdaQueryWrapper<EfcodeVirtualUnit> lqw = Wrappers.lambdaQuery();
lqw.eq(EfcodeVirtualUnit::getVirShowAtBusiness, "是");
lqw.orderByAsc(EfcodeVirtualUnit::getCustOrderNum);
lqw.orderByAsc(EfcodeVirtualUnit::getOrderNum);
return baseMapper.selectVoList(lqw);
}
/**
* 根据虚拟单位的sysDeptId分页查询关联人员列表
* SQL实现参见 EfcodeVirtualUnitMapper.xml#selectUnitUsers
*/
@Override
public TableDataInfo<UnitUserVo> queryUsersBySysDeptId(String sysDeptId, String keyword, boolean globalSearch, PageQuery pageQuery) {
if (!globalSearch && StringUtils.isBlank(sysDeptId)) {
return TableDataInfo.build(new Page<>());
}
IPage<UnitUserVo> page = baseMapper.selectUnitUsers(pageQuery.build(), sysDeptId, keyword, globalSearch);
return TableDataInfo.build(page);
}
/**
* 是否存在子节点
*/

35
zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml

@ -3,4 +3,39 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zdxt.enforcementcode.mapper.EfcodeVirtualUnitMapper">
<!-- 查询虚拟单位关联的人员列表 -->
<select id="selectUnitUsers" resultType="com.zdxt.enforcementcode.domain.vo.UnitUserVo">
SELECT
u.user_id AS userId,
u.dept_id AS deptId,
u.user_name AS userName,
u.fullname AS fullname,
u.mobileNumber AS mobileNumber,
REPLACE(COALESCE(d.zzDisplayPath, ''), '深圳市/', '') AS zzDisplayPath,
<choose>
<when test="!globalSearch and sysDeptId != null and sysDeptId != ''">
CASE WHEN u.dept_id != #{sysDeptId} THEN 1 ELSE 0 END AS isSubDeptUser
</when>
<otherwise>
0 AS isSubDeptUser
</otherwise>
</choose>
FROM sys_user u
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE u.del_flag = '0'
<if test="!globalSearch and sysDeptId != null and sysDeptId != ''">
AND (u.dept_id = #{sysDeptId} OR u.dept_id IN (
SELECT t.dept_id FROM sys_dept t WHERE t.del_flag = '0' AND FIND_IN_SET(#{sysDeptId}, t.ancestors)
))
</if>
<if test="keyword != null and keyword != ''">
AND (
u.fullname LIKE CONCAT('%', #{keyword}, '%')
OR u.user_name LIKE CONCAT('%', #{keyword}, '%')
OR u.mobileNumber LIKE CONCAT('%', #{keyword}, '%')
)
</if>
ORDER BY u.dept_id ASC, u.user_id ASC
</select>
</mapper>

37
zdxt-web-client/zdxt-admin-plus-ui/.env.development-zrb-cust

@ -0,0 +1,37 @@
VITE_APP_PROXY_TARGET = 'http://localhost:17000/sup-ep'
# 页面标题
VITE_APP_TITLE = zdxt-Vue-Plus多租户管理系统
VITE_APP_LOGO_TITLE = 行政执法监督码
# 开发环境配置
VITE_APP_ENV = 'development'
# 开发环境
VITE_APP_BASE_API = '/dev-api'
# 应用访问路径 例如使用前缀 /admin/
VITE_APP_CONTEXT_PATH = '/'
# 监控地址
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
# SnailJob 控制台地址
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
VITE_APP_PORT = 12004
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
VITE_APP_ENCRYPT = true
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
# websocket 开关 默认使用sse推送
VITE_APP_WEBSOCKET = false
# sse 开关
VITE_APP_SSE = true

1
zdxt-web-client/zdxt-admin-plus-ui/package.json

@ -8,6 +8,7 @@
"type": "module",
"scripts": {
"vite-server-web-supervision-dev": "vite serve --mode development",
"vite-server-web-supervision-dev-zrb": "vite serve --mode development-zrb-cust",
"build-zdxt-admin-plus-ui:prod": "vite build --mode production --outDir dist/prod",
"build-zdxt-admin-plus-ui:dev": "vite build --mode development --outDir dist/dev",
"zdxt-admin-plus-ui-preview": "vite preview --outDir dist/prod",

29
zdxt-web-client/zdxt-admin-plus-ui/src/api/efcode/virtualUnit/index.ts

@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { VirtualUnitVo, VirtualUnitForm } from './types';
import { VirtualUnitVo, VirtualUnitForm, UnitUserVo } from './types';
/**
* 查询虚拟单位树列表(树结构)
@ -53,3 +53,30 @@ export const delVirtualUnit = (virId: string) => {
method: 'delete'
});
};
/**
* 查询业务可见的虚拟单位树列表
*/
export const getBusinessTreeList = (): AxiosPromise<VirtualUnitVo[]> => {
return request({
url: '/enforcementcode/virtualUnit/businessTreeList',
method: 'get'
});
};
/**
* 查询虚拟单位关联人员列表(分页)
*/
export const getUnitUsers = (params: {
sysDeptId?: string;
keyword?: string;
globalSearch?: boolean;
pageNum?: number;
pageSize?: number;
}) => {
return request({
url: '/enforcementcode/virtualUnit/users',
method: 'get',
params
});
};

14
zdxt-web-client/zdxt-admin-plus-ui/src/api/efcode/virtualUnit/types.ts

@ -44,3 +44,17 @@ export interface VirtualUnitForm {
orderNum?: number;
custOrderNum?: number;
}
/**
* 虚拟单位人员VO(复用SysUserVo字段)
*/
export interface UnitUserVo {
userId: number;
fullname: string;
userName: string;
mobileNumber: string;
deptId: string;
zzDisplayPath: string;
isSubDeptUser: boolean;
[key: string]: any;
}

383
zdxt-web-client/zdxt-admin-plus-ui/src/views/efcode/virtualUnit/unitUserManager.vue

@ -0,0 +1,383 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { Search } from '@element-plus/icons-vue';
import { getBusinessTreeList, getUnitUsers } from '@/api/efcode/virtualUnit';
import type { VirtualUnitVo, UnitUserVo } from '@/api/efcode/virtualUnit/types';
/** ============ 左侧虚拟单位树 ============ */
interface TreeNode extends VirtualUnitVo {
children?: TreeNode[];
}
const treeData = ref<TreeNode[]>([]);
const treeLoading = ref(false);
const selectedNode = ref<TreeNode | null>(null);
const defaultExpandedKeys = ref<string[]>([]);
const treeSearchKeyword = ref('');
/** 搜索过滤后的树数据 */
const filteredTreeData = computed(() => {
const keyword = treeSearchKeyword.value.trim();
if (!keyword) return treeData.value;
return filterTreeNodes(treeData.value, keyword);
});
/** 过滤树节点:匹配的节点+祖先+子孙全部展示 */
const filterTreeNodes = (nodes: TreeNode[], keyword: string): TreeNode[] => {
const result: TreeNode[] = [];
for (const node of nodes) {
const selfMatch = node.virName?.includes(keyword);
if (selfMatch) {
// 自身匹配:保留自身及全部子孙
result.push(node);
} else if (node.children) {
// 自身不匹配:递归查看子节点
const filteredChildren = filterTreeNodes(node.children, keyword);
if (filteredChildren.length > 0) {
// 子孙有匹配,保留当前节点作为祖先
result.push({ ...node, children: filteredChildren });
}
}
}
return result;
};
/** 搜索时展开所有过滤后的节点 */
const filteredExpandedKeys = computed(() => {
const keyword = treeSearchKeyword.value.trim();
if (!keyword) return defaultExpandedKeys.value;
const keys: string[] = [];
const collect = (nodes: TreeNode[]) => {
for (const node of nodes) {
if (node.children && node.children.length > 0) {
keys.push(node.virId);
collect(node.children);
}
}
};
collect(filteredTreeData.value);
return keys;
});
/** 高亮名称中的匹配文字 */
const highlightName = (name: string) => {
const keyword = treeSearchKeyword.value.trim();
if (!keyword || !name) return name;
const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return name.replace(new RegExp(`(${escaped})`, 'gi'), '<span class="search-match">$1</span>');
};
/** 将扁平列表构建为树结构 */
const buildTree = (list: VirtualUnitVo[]): TreeNode[] => {
const map = new Map<string, TreeNode>();
const roots: TreeNode[] = [];
for (const item of list) {
map.set(item.virId, { ...item, children: [] });
}
for (const item of list) {
const node = map.get(item.virId)!;
const parent = map.get(item.virParentId);
if (parent) {
parent.children!.push(node);
} else {
roots.push(node);
}
}
// 移除空children
const cleanEmpty = (nodes: TreeNode[]) => {
for (const node of nodes) {
if (node.children && node.children.length === 0) {
delete node.children;
} else if (node.children) {
cleanEmpty(node.children);
}
}
};
cleanEmpty(roots);
// 收集前3层节点key用于默认展开
defaultExpandedKeys.value = [];
const collectKeys = (nodes: TreeNode[], level: number) => {
if (level > 2) return;
for (const node of nodes) {
defaultExpandedKeys.value.push(node.virId);
if (node.children) {
collectKeys(node.children, level + 1);
}
}
};
collectKeys(roots, 1);
return roots;
};
/** 加载虚拟单位树 */
const loadTree = async () => {
treeLoading.value = true;
try {
const res = await getBusinessTreeList();
treeData.value = buildTree(res.data);
} finally {
treeLoading.value = false;
}
};
/** 左侧树行点击 */
const handleNodeClick = (row: TreeNode) => {
selectedNode.value = row;
};
/** 高亮当前选中行 */
const treeRowClassName = ({ row }: { row: TreeNode }) => {
if (selectedNode.value && row.virId === selectedNode.value.virId) {
return 'selected-row';
}
return '';
};
/** ============ 右侧人员列表 ============ */
const userList = ref<UnitUserVo[]>([]);
const userLoading = ref(false);
const userSearchKeyword = ref('');
const globalSearch = ref(false);
const userTotal = ref(0);
const userPageNum = ref(1);
const userPageSize = ref(16);
/** 加载人员列表 */
const loadUsers = async () => {
if (!globalSearch.value && !selectedNode.value?.sysDeptId) {
userList.value = [];
userTotal.value = 0;
return;
}
userLoading.value = true;
try {
const res = await getUnitUsers({
sysDeptId: globalSearch.value ? undefined : selectedNode.value?.sysDeptId,
keyword: userSearchKeyword.value.trim() || undefined,
globalSearch: globalSearch.value,
pageNum: userPageNum.value,
pageSize: userPageSize.value
});
userList.value = res.rows;
userTotal.value = res.total;
} finally {
userLoading.value = false;
}
};
/** 搜索 */
const handleSearch = () => {
userPageNum.value = 1;
loadUsers();
};
/** 分页切换 */
const handlePageChange = (page: number) => {
userPageNum.value = page;
loadUsers();
};
const handleSizeChange = (size: number) => {
userPageSize.value = size;
userPageNum.value = 1;
loadUsers();
};
/** 人员行样式:下级部门用户标记浅蓝色 */
const userRowClassName = ({ row }: { row: UnitUserVo }) => {
if (row.isSubDeptUser) {
return 'sub-dept-row';
}
return '';
};
/** 监听选中节点变化自动加载人员 */
watch(selectedNode, () => {
if (!globalSearch.value) {
userPageNum.value = 1;
loadUsers();
}
});
/** 监听全局搜索切换 */
watch(globalSearch, () => {
userPageNum.value = 1;
if (globalSearch.value) {
loadUsers();
} else if (selectedNode.value?.sysDeptId) {
loadUsers();
} else {
userList.value = [];
userTotal.value = 0;
}
});
onMounted(() => {
loadTree();
});
</script>
<template>
<div class="unit-user-manager">
<!-- 左侧:虚拟单位树 -->
<div class="left-panel">
<el-card shadow="hover">
<template #header>
<span class="panel-title">执法单位</span>
<el-input
v-model="treeSearchKeyword"
placeholder="搜索单位名称"
:prefix-icon="Search"
clearable
style="margin-top: 8px;"
/>
</template>
<el-table
:data="filteredTreeData"
row-key="virId"
border
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:default-expand-all="false"
:expand-row-keys="filteredExpandedKeys"
highlight-current-row
:row-class-name="treeRowClassName"
v-loading="treeLoading"
@row-click="handleNodeClick"
max-height="calc(100vh - 240px)"
>
<el-table-column prop="virName" label="单位名称" min-width="200" show-overflow-tooltip>
<template #default="{ row }">
<span v-html="highlightName(row.virName)"></span>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<!-- 右侧:人员列表 -->
<div class="right-panel">
<el-card shadow="hover">
<template #header>
<div class="right-header">
<span class="panel-title">
执法人员
<el-tag v-if="selectedNode && !globalSearch" type="info" size="small" style="margin-left: 8px;">
{{ selectedNode.virName }}
</el-tag>
<el-tag v-if="globalSearch" type="warning" size="small" style="margin-left: 8px;">
全局搜索
</el-tag>
</span>
<div class="search-bar">
<el-input
v-model="userSearchKeyword"
placeholder="姓名/账号/手机号"
:prefix-icon="Search"
clearable
style="width: 200px;"
@keyup.enter="handleSearch"
/>
<el-checkbox v-model="globalSearch" style="margin-left: 12px;">全局搜索</el-checkbox>
<el-button type="primary" style="margin-left: 8px;" @click="handleSearch">查询</el-button>
</div>
</div>
</template>
<el-table
:data="userList"
border
v-loading="userLoading"
:row-class-name="userRowClassName"
max-height="calc(100vh - 240px)"
>
<el-table-column type="index" label="#" width="50" align="center" :index="(i: number) => (userPageNum - 1) * userPageSize + i + 1" />
<el-table-column prop="fullname" label="姓名" min-width="100" show-overflow-tooltip />
<el-table-column prop="userName" label="账号" min-width="120" show-overflow-tooltip />
<el-table-column prop="zzDisplayPath" label="所属部门" min-width="330" show-overflow-tooltip />
<el-table-column label="设置" width="80" align="center">
<template #default>
<el-button type="primary" link size="small" disabled>设置</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-if="userTotal > 0"
style="margin-top: 12px; justify-content: flex-end;"
:current-page="userPageNum"
:page-size="userPageSize"
:page-sizes="[10, 20, 50]"
:total="userTotal"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</el-card>
</div>
</div>
</template>
<style scoped lang="scss">
.unit-user-manager {
display: flex;
gap: 12px;
padding: 12px;
height: calc(100vh - 100px);
}
.left-panel {
width: 360px;
flex-shrink: 0;
overflow: hidden;
}
.right-panel {
flex: 1;
min-width: 0;
overflow: hidden;
}
.panel-title {
font-weight: 600;
font-size: 15px;
}
.right-header {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
}
.search-bar {
display: flex;
align-items: center;
}
:deep(.el-table__row:hover) {
td.el-table__cell {
background-color: var(--el-color-primary-light-9) !important;
}
}
:deep(.selected-row) {
td.el-table__cell {
background-color: var(--el-color-primary-light-7) !important;
}
}
:deep(.sub-dept-row) {
td.el-table__cell {
background-color: #ecf5ff !important;
}
}
:deep(.search-match) {
color: #f56c6c;
font-weight: bold;
}
</style>

2
zdxt-web-client/zdxt-admin-plus-ui/vite.config.ts

@ -27,7 +27,7 @@ export default defineConfig(({ mode, command }) => {
open: true,
proxy: {
[env.VITE_APP_BASE_API]: {
target: 'http://localhost:8080',
target: env.VITE_APP_PROXY_TARGET || 'http://localhost:8080',
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')

Loading…
Cancel
Save