# 辅助审查系统

作者:于佳鑫

国土基线地址:http://52.83.103.252:8086/NatureResource/#/Portal

用户名/ 密码:*** / ***

运维地址:http://52.83.103.252:8086/dgpoms/#/pc/roleperm/domain

用户名/密码:*** / ***

业务库地址:*** / ***

# 依赖的支撑系统

image-20200915153917206

# 核心模块

核心模块

# 一、成果审查模块

先看下整个系统使用到的表和他们之间的关系吧,下面介绍的时候会提及到:

数据库设计

整个系统的核心是审查任务表,审查任务表中有一个核心的概念就是”五级三类“,“五级”为:国家级、省级、市级、县级、乡镇级,“三类”为:总规、控规、专规。审查任务的区域级别在数据库中采用 areaLevel 字段表示,规划类型采用 planType 表示。

image-20200915150106502

# 1.1 下面我们一起走下整个审查系统的流程吧:

image-20200915151214160

当点击新建任务的时候,会弹出选择成果包的对话框,选择对应的成果包进行上传即可。

注:此处上传成果包时的要求

  1. 此处上传的成果包是报批成果包(需要被审查的成果包)

报批成果包:链接: https://pan.baidu.com/s/1tL6BKvMMB8yhaM0Qf6s78g 密码: 6drb

  1. 仅能上传本级或下级行政区划的成果包。

那么怎样确定用户所属级别呢?

进入运维:

image-20200916094838953 image-20200916094925041

我们解压下成果包看下其中的“成果数据基本信息.txt”文件,其中规划类型和区域级别两个字段的来源已经在图上标注出来了。

image-20200915153100442

当点击“新建任务”的时候,“成果数据基本信息.txt”文件中的这些数据将会保存到项目表(ProjectInfo)中进行存储,同时会在审查任务表中新建一条记录与这个项目绑定,其中核心字段如下:reviewState(审查状态)、taskAreaLevel(任务是哪个级别的用户上传的)、rolesName(上传用户拥有的角色)。

image-20200915151957144

我们将用户上传的成果包的层级结构保存在成果树(CatalogNode)表中,每个文件上传至 mongoDB 中,文件的详细信息存在资源文件表(ResourceFile)中。

由于历史遗留问题,这部分涉及到了 CS 档案系统,而且代码质量不高,好在这部分代码比较稳定,所以只需要了解下面画的流程即可,不建议大家阅读代码。

新建审查任务

不启动机器审查也可以点进去查看,那么我们先点进去看一下,在最左侧两个按钮,“规划成果”和“审查依据”。

其中规划成果展示的就是用户上传的成果包中的信息,我们可以在这里对其进行预览(部分矢量数据需要结合模型计算才能实现预览,会在下一篇文章中提及到的)。

image-20200915162417838

审查依据中又分为工作依据和相关依据。

image-20200915162736599

其中工作依据是通过任务首页中的“上传工作依据”按钮进行上传的:

image-20200915163654267

注:上传工作依据的时候,需要调用全文检索系统进行文件索引的建立。

相关依据是在从档案系统同步成果包数据的时候同步过来的(看上面的流程图),数据来源为上传的成果包所在区域的上位和相邻区域的“规划文本”目录下的文件。

接下来,我们点击“启动机器审查”,那么机器审查到底是在做什么呢,这就又要引入一张表了:审查要点表(ReviewPoint),审查要点就是这个任务审查时需要考虑的要点,其中的数据来源全部来自于用户上传的成果包中(一些是成果包中的 excel、图片等文件,一些是通过成果包中的一些矢量数据,调用模型系统计算出来的数据),由于不同的区域级别和规划类型他们关注的要点也不同,所以在 ReviewPoint 表中也有这两个字段(belongAreaLevel、belongPlanType)来标识不同级别、规划类型的要点。

image-20200915154132386

上面说了审查要点的一部分是来自于模型计算的结果,所以在审查要点表中有一个字段 fromModelCalculation 来标识是否来自模型计算,另外还有一个字段 participateCalc 来控制是否参与模型计算(也就是点击“机器审查”时是否计算这个模型)。

注:启动模型计算这个地方逻辑过于复杂,准备独立成一个模块放到下一篇文章中介绍,下面你可以假设模型已经计算完成了。

接下来就开始人工审查的流程了,流程图如下:

image-20200915163745325

此时,我们可以点击进来,选择一个审查要点进行意见的填写:

image-20200915164018307

当意见填写完成之后,可以点击生成报告,生成报告之后才可以点击完成审查:

image-20200915164558336

完成审查时会将最近的审查报告复制一份到规划成果下,如下图:

image-20200915165109137

然后这个任务的整个生命周期就结束了,之后他就会进入“成果管理”中。

image-20200915165928781

# 1.2 常见问题

# 1)审查任务的查询

接口:/v5/reviewTask/page

**入参:**planType(规划类型)、level(区域等级,对应的 ProjectInfo 表中的 areaLevel 字段)、keyword(搜索关键词)、pageIndex、pageSize

代码逻辑:

---------- controller

  1. 对 planType 和 level 进行参数校验
  2. 获取当前登录用户所在区域代码和用户具有的角色,封装到 query 对象中,调用 service

---------- service

  1. 获取传过来 query 对象中的“用户所在区域代码”,调用 ims 系统获取区域代码所在层级(ReviewTask 表中的 taskAreaLevel)

  2. 调用 dmn 层,根据 planType、areaLevel、keyword、taskAreaLevel、roles 查询出符合条件的报批任务

  3. 采用“尾部去零法”过滤不是本级下的任务

  4. 因为需要展示成那种折叠的格式,所以需要根据 projectCode 进行分组折叠

  5. 使用分页工具类分页,返回 controller 层

---------- controller

  1. 直接返回

**常见迷惑点:**用户在页面上点击的市、县、乡对应的是 ProjectInfo 表的 areaLevel,而当前登录用户所处的级别对应的是 ReviewTask 表中的 taskAreaLevel,也就是说一个用户只能看到同一级别用户上传的市、县、乡的任务。

例 1:县级(taskAreaLevel)用户上传的县级(areaLevel)任务,市级(taskAreaLevel)用户是没法看到的

例 2:市级(taskAreaLevel)用户上传的县级(areaLevel)任务,市级(taskAreaLevel)用户是能看到的

注:当然还要考虑角色,查询的时候还要根据角色进行一次过滤。

# 2)向上提交

这个是个隐藏功能,我觉得产品在设计有缺陷,遇到问题再找我吧,不想讲了。

注:是否能看到向上提交是由前端控制的。

# 3)文件预览

image-20200917110103794

接口:/v2/fileUrl/{resourceId}

**入参:**resourceId(资源文件 id,对应的是 ResourceFile 表的 id)

代码逻辑:

注:此处的代码逻辑只讲 officeOnline 的预览,图片的预览没啥可讲的,mdb、gdb 的参见下一篇文章。

@GetMapping("/v2/fileUrl/{resourceId}")
@ApiOperation(value = "根据资源文件id,返回url实现文件预览", httpMethod = "GET")
public ResponseData getFileUrlByResourceId(@PathVariable(value = "resourceId") Long resourceId) {
  if (resourceId < 0) {
    throw new IllegalParameterException("输入的资源文件id错误!");
  }

  // 1)
  ResourceCommand<?> command = resourceCommandFactory.createCommand(resourceId);
  // 2)
  ResourceFileUrlVO<?> resourceFileUrlVO = CommandExecuteService.execute(command, resourceId, this.httpServletRequest);
  return ResponseUtil.success(resourceFileUrlVO);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

本部分代码采用了简单工厂和命令模式,第一句就是根据一系列判断条件找到合适的命令:

image-20200917110722375

第二句就是执行命令,没啥可说的,我们看具体的命令对象:OfficeOnlineCommand

/**
 * 执行命令
 *
 * @param resourceId 资源文件id
 * @param request    本次请求对象
 * @return 资源文件信息的实体(url或数据)
 */
@Override
public ResourceFileUrlVO<Void> execute(Long resourceId, HttpServletRequest request) {

  // 获取应用url
  String applicationUrl = ContextPathUtil.getBaseURL(request);

  // 获取相应文件类型的uri
  // 获取文件信息
  ResourceFileDTO resourceFileDTO = reviewResourceBizService.getResourceFileByResourceFileId(resourceId);
  // 获取文件后缀(不带.的)
  String suffix = resourceFileDTO.getSuffix();
  if (suffix.contains(".")) {
    suffix = suffix.substring(1, suffix.length()).toLowerCase();
  }
  String uri = GlobalConstant.OFFICE_ONLINE_PROPERTIES.get(suffix);
  // 拼装重定向url
  String url = officeOnlineUrl + uri + applicationUrl + OFFICE_WOPI + resourceId;

  // 封装返回的信息
  ResourceFileUrlVO<Void> resourceFileUrlVO = new ResourceFileUrlVO<>();
  resourceFileUrlVO.setType(resourceFileType);
  resourceFileUrlVO.setStream(Boolean.FALSE);
  resourceFileUrlVO.setUrl(url);

  return resourceFileUrlVO;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

注释应该写的很清楚了,返回的 url 格式为:

image-20200917111524577

OfficeOnline 接收到请求的时候首先会请求:http://52.83.103.252:8086/dgp-server-web-nr/wopi/files/14779581这个地址,将会被我们系统的 WopiFilter 进行拦截,此时我们会返回 14779581(这个是 resourceFileId) 对应的文件的元数据,此时 OfficeOnline 就会检查是否本地已经有这个文件了,如果没有的话,则会请求 http://52.83.103.252:8086/dgp-server-web-nr/wopi/files/14779581/contents 进行文件的下载(这个地址也会被 WopiFilter 拦截,具体可以看代码),然后就可以预览了。

所以加入 OfficeOnline 预览有了问题,可以进行 F12 抓包,抓到这个地址:http://52.83.96.20/x/_layouts/xlviewerinternal.aspx?WOPISrc=http://52.83.103.252:8086/dgp-server-web-nr/wopi/files/14779581,然后我们请求 http://52.83.103.252:8086/dgp-server-web-nr/wopi/files/14779581/contents 看看下载下的文件是否有问题,如果文件没问题,那么就是 OfficeOnline 服务器的问题了,就可以找实施了。

注:返回给 officeOnline 的文件元数据必须要有后缀名。

# 4)保存工作依据

接口:/v1/workBasis/{planType}/{areaLevel}/{path}(上传接口:/v1/temp/workBasis)

入参:planType、areaLevel、path(在 mongo 中的唯一标识)

代码逻辑:没啥可讲的,主要想说的是这句代码:

// 推送文件到全文检索
searchService.createSearchIndex(workBasisNodeType);
1
2

上传工作依据的时候需要向全文检索系统建立索引,调用时采用的 Feign,所以当上传工作依据报错 FeignException 的话,请直接找实施启动全文检索系统。

# 5)如何删除审查任务

第一步:因为部分任务状态(例如:已完成、机审中)不能进行任务的删除,所以需要进入审查任务表中,将需要删除的审查任务的 ReviewState 改为 0。

image-20200918124718078

第二步:找到 http://52.83.103.252:8086/dgp-server-web-nr/swagger-ui.html#/ARS-ReviewTaskController/batchDelReviewTaskUsingDELETE 接口,将需要删除的审查任务 id 写到请求的数组中。

image-20200918124927998

# 二、成果管理模块

image-20200918132034807

之前也提到过,成果管理页面展示的是最近一次审查完成的任务批复成果包,所以我们先看下批复成果包的上传

# 1)上传批复成果

批复成果包:链接: https://pan.baidu.com/s/1jMAAhLX4LNo9dj6_iauQ5g 密码: 8eo4

image-20200918133137876

上传完成的时候,你可以看到展示的这条记录的成果版本从【报批稿】变成了【批复稿】,成果阶段从【一审】变成了【已批复】,此时没有办法再从成果审查上传相同【区域+规划类型+区域级别+起始年+目标年 => 版本】的批复成果包,证明这个版本的成果包已经彻底审查完成。

image-20200918133346801

# 2)展示的区域树

区域树只会展示有批复或者已经审查完成的区域。

# 3)折叠方式

折叠方式为:区域代码 + 区域名称 + 规划类型 + ( + 规划目标年 + )

完结撒花~