# 专家库系统详细设计文档

## 3. 模块/子系统详细设计

### 3.1 功能模块划分

#### 模块1：`专家信息管理`
- **功能描述**: 提供专家信息的增删改查、导入导出、审批等核心管理功能。
- **输入/输出**:
    - 输入: [ZjkExpertBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkExpertBo.java#L18-L90), 分页查询对象 [PageQuery](file://D:\jyh-zjk\ruoyi-common\ruoyi-common-mybatis\src\main\java\org\dromara\common\mybatis\core\page\PageQuery.java#L22-L121)
    - 输出: 包含专家信息的 [ZjkExpertVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkExpertVo.java#L16-L75) 和分页数据封装类 [TableDataInfo](file://D:\jyh-zjk\ruoyi-common\ruoyi-common-mybatis\src\main\java\org\dromara\common\mybatis\core\page\TableDataInfo.java#L14-L73)
- **处理逻辑**:
```java
// 查询专家库列表信息
@GetMapping("/expertList")
public TableDataInfo<ZjkExpertVo> expertList(ZjkExpertBo bo, PageQuery pageQuery) {
    bo.setStatus(ZjkExpertTypeEnum.NORMAL.getCode());
    return zjkExpertService.expertList(bo, pageQuery);
}

// 专家信息暂存/提交
@PostMapping("save")
public R<Void> save(@Validated(AddGroup.class) @RequestBody ZjkExpertBo bo) {
    return toAjax(zjkExpertService.insertByBo(bo));
}

// 专家信息审批
@PostMapping("approval")
public R<Void> approval(@Validated(AddGroup.class) @RequestBody ApprovalCommonBo approvalCommonBo) {
    if (approvalCommonBo.getApprovalStatus()==null||approvalCommonBo.getId()==null){
        return R.fail("参数不正确");
    }else if (approvalCommonBo.getApprovalStatus()==0&& StringUtils.isEmpty(approvalCommonBo.getReason())){
            return R.fail("驳回理由不能为空");
    }
    ZjkExpertBo expert = new ZjkExpertBo();
    expert.setExpertId(approvalCommonBo.getId());
    expert.setRemark(approvalCommonBo.getReason());
    expert.setStatus(approvalCommonBo.getApprovalStatus()== ResultTypeEnum.SUCCESS.getCode()? ZjkExpertTypeEnum.NORMAL.getCode(): ZjkExpertTypeEnum.REFUSE.getCode());
    return toAjax(zjkExpertService.approval(expert));
}
```


- **接口定义**:
    - API签名:
        - `GET /expert/expertList`
        - `POST /expert/save`
        - `POST /expert/approval`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 100,
    "rows": [
      {
        "expertId": 123,
        "name": "张三",
        "status": "正常"
      }
    ]
  }
}
```


---

#### 模块2：`专家入库记录管理`
- **功能描述**: 管理专家的入库申请记录，包括记录的增删改查和趋势分析功能。
- **输入/输出**:
    - 输入: 入库记录业务对象 [ZjkExpertLogBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkExpertLogBo.java#L17-L66), 主键ID
    - 输出: 包含入库记录信息的 [ZjkExpertLogVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkExpertLogVo.java#L15-L74)
- **处理逻辑**:
```java
// 查询入库记录列表
@GetMapping("/list")
public TableDataInfo<ZjkExpertLogVo> list(ZjkExpertLogBo bo, PageQuery pageQuery) {
    return zjkExpertLogService.queryPageList(bo, pageQuery);
}

// 新增入库记录
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkExpertLogBo bo) {
    return toAjax(zjkExpertLogService.insertByBo(bo));
}

// 趋势分析
@GetMapping("getApplicationResults")
public R<List<Map<String, Object>>> getApplicationResults(@RequestParam(name = "startTime",required = false)String startTime, @RequestParam(name = "endTime",required = false)String endTime) {
    return R.ok(zjkExpertLogService.getApplicationResults(startTime,endTime));
}
```


- **接口定义**:
    - API签名:
        - `GET /expertLog/list`
        - `POST /expertLog`
        - `GET /expertLog/getApplicationResults`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "date": "2024-01",
      "count": 10
    },
    {
      "date": "2024-02",
      "count": 15
    }
  ]
}
```


---

#### 模块3：`专家变更历史管理`
- **功能描述**: 记录并管理专家信息的变更历史，支持变更记录的增删改查操作。
- **输入/输出**:
    - 输入: 变更历史业务对象 [ZjkExpertHistoryBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkExpertHistoryBo.java#L17-L65)
    - 输出: 包含变更历史信息的 [ZjkExpertHistoryVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkExpertHistoryVo.java#L15-L73)
- **处理逻辑**:
```java
// 查询专家记录变更历史表列表
@GetMapping("/list")
public TableDataInfo<ZjkExpertHistoryVo> list(ZjkExpertHistoryBo bo, PageQuery pageQuery) {
    return zjkExpertHistoryService.queryPageList(bo, pageQuery);
}

// 新增专家记录变更历史表
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkExpertHistoryBo bo) {
    return toAjax(zjkExpertHistoryService.insertByBo(bo));
}
```


- **接口定义**:
    - API签名:
        - `GET /expertHistory/list`
        - `POST /expertHistory`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 5,
    "rows": [
      {
        "changeDate": "2024-03-15",
        "changes": "姓名从张三改为李四"
      }
    ]
  }
}
```

---

#### 模块4：`专家抽取条件管理`
- **功能描述**: 提供多维度的专家抽取条件设置，支持查询、新增、修改和删除抽取条件，并能根据条件筛选出符合要求的专家信息。
- **输入/输出**:
    - 输入:抽取条件业务对象 [ZjkReviewPhaseBo]/分页查询对象 [PageQuery]
    - 输出: 包含抽取条件信息的 [ZjkReviewPhaseVo]
- **处理逻辑**:
```java
// 查询抽取条件列表
@GetMapping("/list")
public TableDataInfo<ZjkReviewPhaseVo> list(ZjkReviewPhaseBo bo, PageQuery pageQuery) {
    return zjkReviewPhaseService.queryPageList(bo, pageQuery);
}

// 新增抽取条件
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkReviewPhaseBo bo) {
    return toAjax(zjkReviewPhaseService.insertByBo(bo));
}

// 修改抽取条件
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ZjkReviewPhaseBo bo) {
    return toAjax(zjkReviewPhaseService.updateByBo(bo));
}

// 删除抽取条件
@DeleteMapping("/{tenantIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
                      @PathVariable String[] tenantIds) {
    return toAjax(zjkReviewPhaseService.deleteWithValidByIds(List.of(tenantIds), true));
}
```


- **接口定义**:
    - API签名:
        - `GET /reviewPhase/list`
        - `POST /reviewPhase`
        - `PUT /reviewPhase`
        - `DELETE /reviewPhase/{tenantIds}`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "total": 10,
        "rows": [
            {
                "conditionName": "高级职称",
                "description": "筛选具有高级职称的专家"
            }
        ]
    }
}
```

---

#### 模块5：`评审项目与抽取记录管理`
- **功能描述**: 管理与抽取条件关联的评审项目信息，支持项目的查询、导出以及通过规则查询抽取记录。同时提供统计分析功能。

- **输入/输出**:
    - 输入: 评审项目业务对象 [ZjkReviewProductBo]/分页查询对象 [PageQuery]
    - 输出: 包含评审项目信息的 [ZjkReviewProductVo]/导出数据封装类 [ZjkReviewExportVo]
- **处理逻辑**:
```java
// 查询评审项目列表
@GetMapping("/review/product/list")
public TableDataInfo<ZjkReviewProductVo> reviewProductList(ZjkReviewProductBo bo, PageQuery pageQuery) {
    return zjkReviewPhaseService.reviewProductList(bo, pageQuery);
}

// 导出评审项目列表
@PostMapping("/review/export")
public void reviewExport(ZjkReviewProductBo bo, HttpServletResponse response) {
    List<ZjkReviewProductVo> zjkReviewProductVos = zjkReviewPhaseService.reviewExport(bo);
    List<ZjkReviewExportVo> zjkReviewExportVo = BeanUtil.copyToList(zjkReviewProductVos, ZjkReviewExportVo.class);
    ExcelUtil.exportExcel(zjkReviewExportVo, "评审项目", ZjkReviewExportVo.class, response);
}

// 获取单个评审项目详细信息
@GetMapping("/getInfo/{productId}")
public R<ZjkReviewProductVo> getInfo(@NotNull(message = "项目id不能为空")
                                     @PathVariable Long productId) {
    ZjkReviewProductVo zjkReviewProductVos = zjkReviewPhaseService.reviewListById(productId);
    return R.ok(zjkReviewProductVos);
}
```


- **接口定义**:
    - API签名:
        - `GET /reviewPhase/review/product/list`
        - `POST /reviewPhase/review/export`
        - `GET /reviewPhase/getInfo/{productId}`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "total": 5,
        "rows": [
            {
                "projectName": "XX项目",
                "expertCount": 3
            }
        ]
    }
}
```

---

#### 模块6：`专家抽取操作与状态管理`
- **功能描述**: 实现专家抽取操作、抽取确认、取消抽取等核心流程，并支持抽取记录的查询、级联搜索及短信回调处理。

- **输入/输出**:
    - 输入: 抽取设置对象 [ZjkProjectExpertItemBo]
    - 输出: 包含抽取结果的 [ZjkExpertItemVo]
    - 输入: 查询参数对象 [ZjkItemExtreationBo]
    - 输出: 抽取结果列表 [ZjkExpertVo]
- **处理逻辑**:
```java
// 专家抽取
@PostMapping("/expertltem")
public R<Long> expertltem(@Validated(AddGroup.class) @RequestBody String zjkProjectExpertItemBo) {
    ZjkProjectExpertItemBo itemBo = JSON.parseObject(zjkProjectExpertItemBo, ZjkProjectExpertItemBo.class);
    return R.ok(zjkExpertItemService.expertltem(itemBo));
}

// 取消抽取
@PostMapping("/cancel")
public R<Void> cancel(@Validated(AddGroup.class) @RequestBody ZjkProjectExpertItemBo itemExpertId) {
    zjkExpertItemService.cancel(itemExpertId);
    return R.ok();
}

// 专家级联查询
@GetMapping ("/concatenated")
public R<List<ZjkExpertVo>> concatenated(String name) {
    return R.ok(zjkExpertItemService.concatenated(name));
}
```


- **接口定义**:
    - API签名:
        - `POST /project/extract/expertltem`
        - `POST /project/extract/cancel`
        - `GET /project/extract/concatenated`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": 1
}
```

---

#### 模块7：`专家抽取记录管理`
- **功能描述**: 对抽取记录进行增删改查操作，包括导出抽取列表、获取抽取详情等功能。


- **输入/输出**:
    - 输入: 抽取记录查询对象 [ZjkItemExtreationBo]
    - 输出: 包含抽取记录的 [ZjkItemExtreationVo]
- **处理逻辑**:
```java
// 查询专家抽取列表
@GetMapping("/list")
public TableDataInfo<ZjkItemExtreationVo> list(ZjkItemExtreationBo bo, PageQuery pageQuery) {
    bo.setEffective(1); // 筛选有效记录
    return zjkItemExtreationService.queryPageList(bo, pageQuery);
}

// 获取专家抽取详细信息
@GetMapping("/{id}")
public R<ZjkItemExtreationVo> getInfo(@NotNull(message = "主键不能为空")
                                      @PathVariable Long id) {
    return R.ok(zjkItemExtreationService.queryById(id));
}

// 导出专家抽取列表
@PostMapping("/export")
public void export(ZjkItemExtreationBo bo, HttpServletResponse response) {
    List<ZjkItemExtreationVo> list = zjkItemExtreationService.queryList(bo);
    ExcelUtil.exportExcel(list, "抽取", ZjkItemExtreationVo.class, response);
}
```


- **接口定义**:
    - API签名:
        - `GET /itemExtreation/list`
        - `GET /itemExtreation/{id}`
        - `POST /itemExtreation/export`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "total": 10,
        "rows": [
            {
                "expertName": "张三",
                "projectId": 1001,
                "status": "已抽取"
            }
        ]
    }
}
```

---

#### 模块8：`专家合作项目查询`
- **功能描述**: 根据专家ID获取其参与的评审项目信息，并提供统计分析功能。

- **输入/输出**:
    - 输入: 评审项目业务对象 [ZjkReviewProductBo]/分页查询对象 [PageQuery]
    - 输出: 包含专家合作项目信息的 [ZjkReviewProductVo]
- **处理逻辑**:
```java
// 根据专家ID获取合作项目信息
@GetMapping("/getReviewProductListByExpert")
public TableDataInfo<ZjkReviewProductVo> getReviewProductListByExpert(ZjkReviewProductBo bo, PageQuery pageQuery) {
    return zjkReviewPhaseService.getReviewProductListByExpert(bo, pageQuery);
}

// 获取评审项目数量统计
@GetMapping("/getReview/count")
public R getReviewCount() {
    return R.ok("success", zjkReviewPhaseService.getReviewCount());
}
```


- **接口定义**:
    - API签名:
        - `GET /reviewPhase/getReviewProductListByExpert`
        - `GET /reviewPhase/getReview/count`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "total": 2,
        "rows": [
            {
                "projectName": "YY项目",
                "startDate": "2024-01-01"
            }
        ]
    }
}
```

---
#### 模块9：`项目管理`
- **功能描述**: 提供项目的增删改查、导出、权限控制等功能，支持不同角色对项目的操作。
- **输入/输出**:
    - 输入: [ZjkProductBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkProductBo.java#L17-L68), 分页查询对象 [PageQuery](file://D:\jyh-zjk\ruoyi-common\ruoyi-common-mybatis\src\main\java\org\dromara\common\mybatis\core\page\PageQuery.java#L22-L121)
    - 输出: 包含项目信息的 [ZjkProductVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkProductVo.java#L15-L74) 和分页数据封装类 [TableDataInfo](file://D:\jyh-zjk\ruoyi-common\ruoyi-common-mybatis\src\main\java\org\dromara\common\mybatis\core\page\TableDataInfo.java#L14-L73)
- **处理逻辑**:
```java
// 查询项目管理列表
@GetMapping("/list")
public TableDataInfo<ZjkProductVo> list(ZjkProductBo bo, PageQuery pageQuery) {
    return zjkProductService.queryPageList(bo, pageQuery);
}

// 新增项目管理
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkProductBo bo) {
    return toAjax(zjkProductService.insertByBo(bo));
}

// 修改项目管理
@PostMapping("/update")
public R<Void> edit(@RequestBody ZjkProductBo bo) {
    return toAjax(zjkProductService.updateByBo(bo));
}
```


- **接口定义**:
    - API签名:
        - `GET /product/list`
        - `POST /product`
        - `POST /product/update`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 100,
    "rows": [
      {
        "projectId": 123,
        "projectName": "项目A",
        "status": "进行中"
      }
    ]
  }
}
```


---

#### 模块10：`项目总结评价`
- **功能描述**: 管理项目总结评价，包括评价的增删改查和导出功能。
- **输入/输出**:
    - 输入: 项目总结评价业务对象 [ZjkProjectEvaluationBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkProjectEvaluationBo.java#L17-L66), 主键ID
    - 输出: 包含项目总结评价信息的 [ZjkProjectEvaluationVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkProjectEvaluationVo.java#L15-L74)
- **处理逻辑**:
```java
// 查询项目总结评价列表
@GetMapping("/list")
public TableDataInfo<ZjkProjectEvaluationVo> list(ZjkProjectEvaluationBo bo, PageQuery pageQuery) {
    return zjkProjectEvaluationService.queryPageList(bo, pageQuery);
}

// 新增项目总结评价
@PostMapping("/insert")
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkProjectEvaluationBo bo) {
    return toAjax(zjkProjectEvaluationService.insertByBo(bo));
}

// 导出项目总结评价列表
@PostMapping("/export")
public void export(ZjkProjectEvaluationBo bo, HttpServletResponse response) {
    List<ZjkProjectEvaluationVo> list = zjkProjectEvaluationService.queryList(bo);
    ExcelUtil.exportExcel(list, "项目总结评价", ZjkProjectEvaluationVo.class, response);
}
```


- **接口定义**:
    - API签名:
        - `GET /projectEvaluation/list`
        - `POST /projectEvaluation/insert`
        - `POST /projectEvaluation/export`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 5,
    "rows": [
      {
        "evaluationId": 123,
        "score": 95
      }
    ]
  }
}
```


---

#### 模块11：`项目阶段文档管理`
- **功能描述**: 管理项目的各个阶段文档，支持文档的增删改查操作。
- **输入/输出**:
    - 输入: 项目阶段文档业务对象 [ZjkProductReviewsnBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkProductReviewsnBo.java#L17-L65)
    - 输出: 包含项目阶段文档信息的 [ZjkProductReviewsnVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkProductReviewsnVo.java#L15-L73)
- **处理逻辑**:
```java
// 查询项目阶段文档管理列表
@GetMapping("/list")
public TableDataInfo<ZjkProductReviewsnVo> list(ZjkProductReviewsnBo bo, PageQuery pageQuery) {
    return zjkProductReviewsnService.queryPageList(bo, pageQuery);
}

// 新增项目阶段文档管理
@PostMapping("/add")
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkProductReviewsnBo bo) {
    return toAjax(zjkProductReviewsnService.insertByBo(bo));
}
```


- **接口定义**:
    - API签名:
        - `GET /productReviewsn/list`
        - `POST /productReviewsn/add`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 5,
    "rows": [
      {
        "documentId": 123,
        "documentName": "需求文档"
      }
    ]
  }
}
```


---

#### 模块12：`项目总结与日志`
- **功能描述**: 实现项目的总结撰写、日志记录以及审核功能，包括总结导入导出、审批等操作。
- **输入/输出**:
    - 输入: 项目总结业务对象 [ZjkProductSummarizeBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkProductSummarizeBo.java#L17-L68)
    - 输出: 包含项目总结信息的 [ZjkProductSummarizeVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkProductSummarizeVo.java#L15-L73)
- **处理逻辑**:
```java
// 查询项目总结列表
@GetMapping("/list")
public TableDataInfo<ZjkProductSummarizeVo> list(ZjkProductSummarizeBo bo, PageQuery pageQuery) {
    return zjkProductSummarizeService.queryPageList(bo, pageQuery);
}

// 导出项目总结列表
@PostMapping("/export")
public void export(ZjkProductSummarizeBo bo, HttpServletResponse response) {
    List<ZjkProductSummarizeVo> list = zjkProductSummarizeService.queryList(bo);
    List<ZjkProductSummarizeExportVo> zjkProductSummarizeExportVos = BeanUtil.copyToList(list, ZjkProductSummarizeExportVo.class);
    ExcelUtil.exportExcel(zjkProductSummarizeExportVos, "项目总结", ZjkProductSummarizeExportVo.class, response);
}

// 修改项目总结
@PostMapping("/update")
public R<Void> edit(@RequestBody ZjkProductSummarizeBo bo) {
    return toAjax(zjkProductSummarizeService.updateByBo(bo));
}
```


- **接口定义**:
    - API签名:
        - `GET /productSummarize/list`
        - `POST /productSummarize/export`
        - `POST /productSummarize/update`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "total": 5,
    "rows": [
      {
        "summaryId": 123,
        "content": "项目按计划完成"
      }
    ]
  }
}
```

---

#### 模块13：`专家请假管理`
- **功能描述**: 提供专家的日常请假功能，支持项目评审专家请假、机构管理员审批请假、请假规则配置以及请假统计分析。
- **输入/输出**:
    - 输入: 请假业务对象 [ZjkLeaveBo]
    - 输入: 规则配置对象 [ZjkLeaveRuleBo]
    - 输出: 请假记录信息 [ZjkLeaveVo]
    - 输出: 统计数据封装类 [StsNumVO]
- **处理逻辑**:
```java
// 查询专家请假列表（专家）
@GetMapping("/list")
public TableDataInfo<ZjkLeaveVo> list(ZjkLeaveBo bo, PageQuery pageQuery) {
    return zjkLeaveService.queryPageList(bo, pageQuery);
}

// 新增请假申请
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZjkLeaveBo bo) {
    return zjkLeaveService.insertByBo(bo);
}

// 修改请假规则（机构管理员）
@PutMapping("/setRule")
public R<Void> edit(@RequestBody ZjkLeaveRuleBo bo) {
    return toAjax(zjkLeaveRuleService.updateByBo(bo));
}

// 获取请假统计图表
@GetMapping("/stsChart")
public R<StsLeaveVO> stsChart(Integer rangeMonth) {
    return zjkLeaveService.getStsChart(rangeMonth);
}
```


- **接口定义**:
    - API签名:
        - `GET /leave/list`
        - `POST /leave`
        - `PUT /leave/setRule`
        - `GET /leave/stsChart`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "totalLeaves": 5,
        "approvedLeaves": 3,
        "pendingLeaves": 2
    }
}
```

---

#### 模块14：`专家互评管理`
- **功能描述**: 支持项目评审结束后对参评专家进行评价打分，包含专家自评、管理员查看、互评统计等功能。
- **输入/输出**:
    - 输入: 互评业务对象 [ZjkEvaluateVO]
    - 输出: 互评结果信息 [ZjkEvaluateVO]
    - 对象 [ZjkProductSummarizeBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkProductSummarizeBo.java#L17-L68)
    - 输出: 统计数据封装类 [StsEvaluateNumVO]
- **处理逻辑**:
```java
// 查询专家评价列表（专家）
@GetMapping("/listToZj")
public TableDataInfo<ZjkEvaluateVO> listToZj(ZjkEvaluateVO bo, PageQuery pageQuery) {
    return zjkEvaluateService.getListToZj(bo, pageQuery);
}

// 新增专家评价
@PostMapping()
public R<Void> addComment(@RequestBody ZjkEvaluateVO bo) {
    return zjkEvaluateService.addComment(bo);
}

// 获取互评统计次数
@GetMapping("/stsNum")
public R<StsEvaluateNumVO> getStsNum() {
    return R.ok(zjkEvaluateService.getStsNum());
}

// 导出互评统计
@PostMapping("/export")
public void export(ZjkEvaluateVO bo, HttpServletResponse response) {
    List<StsListVO> list = zjkEvaluateService.selectStsEvaluateList(bo);
    ExcelUtil.exportExcel(list, "评价统计", StsListVO.class, response);
}
```


- **接口定义**:
    - API签名:
        - `GET /evaluate/listToZj`
        - `POST /evaluate`
        - `POST /evaluate/stsNum`
        - `POST /evaluate/export`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "totalEvaluations": 10,
        "averageScore": 4.5
    }
}
```

---

#### 模块15：`请假与评审项目的联动管理`
- **功能描述**: 处理专家请假与其参与评审项目之间的联动关系，包括待接受项目查询、项目请假操作、项目接受确认等。
- **输入/输出**:
    - 输入: 项目评价对象 [ZjkEvaluateVO]
    - 输出: 项目信息封装类 [ZjkEvaluateVO]
- **处理逻辑**:
```java
// 获取待接受项目
@GetMapping("/prosForAccept")
public TableDataInfo<ZjkEvaluateVO> getProsForAccept() {
    return zjkLeaveService.getProsForAccept();
}

// 项目请假
@PostMapping("/leaveForPro")
public R<Void> leaveForPro(@RequestBody ZjkEvaluateVO bo) {
    return zjkLeaveService.leaveForPro(bo);
}

// 项目接受确认
@PostMapping("/setAccept")
public R<Void> setAccept(@RequestBody ZjkEvaluateVO bo) {
    return zjkLeaveService.setAccept(bo);
}
```


- **接口定义**:
    - API签名:
        - `GET /leave/prosForAccept`
        - `POST /leave/leaveForPro`
        - `POST /leave/setAccept`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "操作成功"
}
```
---
#### 模块16：`请假规则与审批流程`
- **功能描述**: 提供请假规则配置及审批流程管理，供机构管理员设置请假策略并处理请假审批。
- **输入/输出**:
    - 输入: 请假规则对象 [ZjkLeaveRuleBo]
    - 输出: 规则详情 [ZjkLeaveRuleVo]
- **处理逻辑**:
```java
// 获取请假规则详情
@GetMapping("/getRule")
public R<ZjkLeaveRuleVo> getLeavelRule() {
    return R.ok(zjkLeaveRuleService.selectRuleByTannet());
}

// 审批请假列表
@GetMapping("/splist")
public TableDataInfo<ZjkLeaveVo> splist(ZjkLeaveBo bo, PageQuery pageQuery) {
    return zjkLeaveService.queryPageSpList(bo, pageQuery);
}

// 修改请假规则
@PutMapping("/setRule")
public R<Void> edit(@RequestBody ZjkLeaveRuleBo bo) {
    return toAjax(zjkLeaveRuleService.updateByBo(bo));
}
```


- **接口定义**:
    - API签名:
        - `GET /leave/getRule`
        - `GET /leave/splist`
        - `PUT /leave/setRule`
    - 消息格式: JSON
    - 示例响应:
```json
{
    "code": 200,
    "msg": "success",
    "data": {
        "maxLeavesPerYear": 5,
        "approvalRequired": true
    }
}
```
---
#### 模块17：`专家画像管理`
- **功能描述**: 提供专家的基本信息展示和知识图谱分析，包括基本信息、同院校/单位/专业专家等维度的数据。
- **输入/输出**:
    - 输入: 用户ID (`Long userId`)
    - 输出: 包含专家基本信息的 [ChartBaseVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ChartBaseVO.java#L18-L153) 和包含相关专家信息的 [ChartRelExpertVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ChartRelExpertVO.java#L14-L21)
- **处理逻辑**:
```java
// 获取专家基本信息
@GetMapping("/chartBase")
public R<ChartBaseVO> getChartBase(Long userId) {
    return zjkExpertChartService.getChartBase(userId);
}

// 获取与指定专家相关的其他专家信息
@GetMapping("/sameOther")
public R<ChartRelExpertVO> getSameOtherData(Long userId) {
    return zjkExpertChartService.getSameOtherData(userId);
}

// 获取所有专家简化信息列表
@GetMapping("/users")
public R<List<SimpleExpertDto>> getExperts() {
    return zjkExpertChartService.getExperts();
}
```


- **接口定义**:
    - API签名:
        - `GET /chart/chartBase?userId={userId}`
        - `GET /chart/sameOther?userId={userId}`
        - `GET /chart/users`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "userId": 123,
    "name": "张三",
    "creditLevel": "A",
    "papersCount": 50,
    "awards": "国家级奖项"
  }
}
```


---

#### 模块18：`积分管理`
- **功能描述**: 管理专家的积分规则、奖励配置、积分记录查询及统计分析。支持积分规则定义、奖励设置、积分复核、趋势分析等功能。
- **输入/输出**:
    - 输入: 积分请求参数对象 [PointReqDto](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\dto\PointReqDto.java#L11-L46), 分页查询对象 [PageQuery](file://D:\jyh-zjk\ruoyi-common\ruoyi-common-mybatis\src\main\java\org\dromara\common\mybatis\core\page\PageQuery.java#L22-L121)
    - 输出: 包括 [ZjkPointRule](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPointRule.java#L18-L65), [ZjkPointReward](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPointReward.java#L18-L84), [PointShowVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\PointShowVO.java#L11-L49), [PointTrendVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\PointTrendVO.java#L15-L20) 等多种数据结构
- **处理逻辑**:
```java
// 查询积分规则列表
@GetMapping("/ruleList")
public R<List<ZjkPointRule>> pointRule(PointReqDto dto) {
    QueryWrapper<ZjkPointRule> wq = new QueryWrapper<>();
    wq.lambda().eq(!StringUtils.isEmpty(dto.getStartFlag()), ZjkPointRule::getStatus, dto.getStartFlag())
        .like(!StringUtils.isEmpty(dto.getRuleName()), ZjkPointRule::getRuleName, dto.getRuleName());
    return R.ok(zjkPointRuleService.list(wq));
}

// 新增奖励
@PostMapping("addReward")
public R<Void> addReward(@RequestBody ZjkPointReward bo) {
    boolean save = zjkPointRewardService.save(bo);
    if (save) {
        return R.ok();
    } else {
        return R.fail();
    }
}

// 积分趋势分析
@GetMapping("/pointTrend")
public R<PointTrendVO> pointTrend(String dayKey,String expertId) {
    return zjkPointUserService.getPointTrend(dayKey,expertId);
}
```


- **接口定义**:
    - API签名:
        - `GET /point/ruleList`
        - `POST /point/addReward`
        - `GET /point/pointTrend`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "totalPoints": 850,
    "trendData": [
      {"date": "2024-01", "points": 100},
      {"date": "2024-02", "points": 150}
    ]
  }
}
```


---

#### 模块19：`信用管理`
- **功能描述**: 管理专家的信用记录，包括信用评分、信用等级、奖惩记录等，并提供信用榜单展示和同步功能。
- **输入/输出**:
    - 输入: 信用请求参数对象 [CreditReqDto](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\dto\CreditReqDto.java#L11-L57), 主键ID
    - 输出: 包括 [ZjkCreditVo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ZjkCreditVo.java#L22-L85), [ChartBaseCreditVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\ChartBaseCreditVO.java#L18-L161), [PointExpertRankVO](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\vo\PointExpertRankVO.java#L14-L19) 等多种数据结构
- **处理逻辑**:
```java
// 查询信用记录列表
@GetMapping("/list")
public TableDataInfo<ZjkCreditVo> list(ZjkCreditBo bo, PageQuery pageQuery) {
    return zjkCreditService.queryPageList(bo, pageQuery);
}

// 获取专家信用榜基本信息
@GetMapping("/pointBase")
public R<ChartBaseCreditVO> pointBase() {
    return zjkCreditService.getPointBase();
}

// 同步专家信息到信用用户记录表
@GetMapping("/expertPointRank/user")
public R<PointExpertRankVO> expertPointRankUser() {
    return zjkCreditService.expertPointRankUser();
}
```


- **接口定义**:
    - API签名:
        - `GET /credit/list`
        - `GET /credit/pointBase`
        - `GET /credit/expertPointRank/user`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "creditLevel": "A",
    "recentPenalties": 0,
    "totalRewards": 5
  }
}
```


---

#### 模块20：`积分复核与统计`
- **功能描述**: 提供积分复核操作和统计分析功能，包括积分复核列表、复核详情、复核提交等。
- **输入/输出**:
    - 输入: 专家ID, 积分复核对象 [ZjkPointUser](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPointUser.java#L14-L76)
    - 输出: 复核结果状态码、积分详情数据
- **处理逻辑**:
```java
// 积分复核列表
@GetMapping("/checkPointList")
public TableDataInfo<PointShowVO> checkPointList(PointReqDto bo, PageQuery pageQuery) {
    return zjkPointUserService.checkPointList(bo, pageQuery);
}

// 积分复核提交
@PostMapping("/pointCheck")
public R<Void> pointCheck(@RequestBody ZjkPointUser dto) {
    return zjkPointUserService.pointCheck(dto);
}

// 积分复核详情
@GetMapping("/pointCheckDetail")
public R<ZjkPointUser> pointCheckDetail(String expertId) {
    QueryWrapper<ZjkPointUser> wq = new QueryWrapper<>();
    wq.lambda().eq(ZjkPointUser::getExpertId,expertId);
    return R.ok(zjkPointUserService.getOne(wq));
}
```


- **接口定义**:
    - API签名:
        - `GET /point/checkPointList`
        - `POST /point/pointCheck`
        - `GET /point/pointCheckDetail`
    - 消息格式: JSON
    - 示例响应:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "expertId": "E1001",
    "totalPoints": 900,
    "status": "已审核"
  }
}
```


---

#### 模块21：`数据导出与文件处理`
- **功能描述**: 提供信用记录的Excel导出功能，支持批量删除和更新操作。
- **输入/输出**:
    - 输入: 导出条件参数对象 [ZjkCreditBo](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\bo\ZjkCreditBo.java#L17-L65)
    - 输出: Excel 文件流
- **处理逻辑**:
```java
// 导出信用记录列表
@PostMapping("/export")
public void export(ZjkCreditBo bo, HttpServletResponse response) {
    List<ZjkCreditVo> list = zjkCreditService.queryList(bo);
    ExcelUtil.exportExcel(list, "信用记录", ZjkCreditVo.class, response);
}

// 删除信用记录
@DeleteMapping("/{IDs}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] IDs) {
    return toAjax(zjkCreditService.deleteWithValidByIds(List.of(IDs), true));
}
```


- **接口定义**:
    - API签名:
        - `POST /credit/export`
        - `DELETE /credit/{IDs}`
    - 消息格式: 文件流（导出）JSON（删除）
    - 示例响应:
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename=credit_records.xlsx
```


### 3.2 类/对象设计

#### 类图（UML）
```plantuml
@startuml
class ZjkExpertController {
  + IZjkExpertService zjkExpertService
  + expertList()
  + pendingApproval()
  + save()
  + approval()
  + getInfo()
}

class ZjkReviewPhaseController {
  + IZjkReviewPhaseService zjkReviewPhaseService
  + list()
  + reviewProductList()
  + getReviewCount()
}

class IZjkExpertService {
  <<interface>>
  + expertList()
  + insertByBo()
  + approval()
  + getReviewCount()
}

class ZjkExpertBo {
  - Long expertId
  - String name
  - Integer status
  + getStatus()
  + setStatus()
}

class ZjkExpertVo {
  - Long expertId
  - String name
  - String status
}

ZjkExpertController --> IZjkExpertService
ZjkReviewPhaseController --> IZjkReviewPhaseService
IZjkExpertService ..> ZjkExpertBo
IZjkExpertService ..> ZjkExpertVo
@enduml
```


#### 关键类说明

**1. ZjkExpertController**
- **职责**：专家信息管理核心控制器，处理专家信息的CRUD、审批、统计等操作
- **核心方法**：
    - `expertList()`：查询专家列表，包含状态过滤逻辑
    - `approval()`：专家审批流程处理，包含状态转换和驳回理由校验
    - `getExpertCount()`：获取专家总数统计
- **状态转换**：
  ```mermaid
  stateDiagram
    [*] --> TEMPORARY: 暂存
    TEMPORARY --> APPROVAL: 提交
    APPROVAL --> NORMAL: 审批通过
    APPROVAL --> REFUSE: 审批驳回
    NORMAL --> DISABLED: 停用
    DISABLED --> NORMAL: 启用
  ```


**2. ZjkReviewPhaseController**
- **职责**：评审项目管理控制器，处理项目与抽取条件的关联关系
- **核心方法**：
    - [reviewProductList()](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\controller\ZjkReviewPhaseController.java#L113-L117)：查询评审项目列表
    - [getReviewCount()](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\controller\ZjkReviewPhaseController.java#L150-L159)：获取项目评审数量统计
- **设计模式**：使用策略模式处理不同类型的项目查询条件

**3. ZjkExpertBo/ZjkExpertVo**
- **职责**：专家信息数据传输对象
- **关联关系**：
    - 与数据库表`zjk_expert`字段映射
    - 包含状态枚举[ZjkExpertTypeEnum](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\enums\ZjkExpertTypeEnum.java#L8-L41)转换逻辑

### 3.3 数据模型设计

#### 数据库表结构（核心表）

表名 | 关键字段 | 索引 | 约束
---|---|---|---
`zjk_expert` | [id](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPoint.java#L22-L23),`user_id`,[status](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkLeave.java#L56-L57),`id_card` | `idx_user_id`, `uniq_id_card` | 非空约束：`id_card`,`user_id`
`zjk_product_summarize` | [id](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPoint.java#L22-L23),`review_id`,[status](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkLeave.java#L56-L57) | `idx_review_id` | 外键约束：`review_id`
`zjk_evaluate` | [id](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPoint.java#L22-L23),`evaluate_user`,`item_id` | `idx_item_user` | 复合索引
`zjk_point` | [id](file://D:\jyh-zjk\ruoyi-modules\zjk-api\src\main\java\org\dromara\zjk\domain\ZjkPoint.java#L22-L23),`expert_id`,`user_id` | `idx_expert_user` | 复合索引

#### ER图
```mermaid
erDiagram
    ZJK_EXPERT ||--o{ ZJK_PRODUCT_SUMMARIZE : "参与"
    ZJK_EXPERT ||--o{ ZJK_EVALUATE : "被评价"
    ZJK_EXPERT ||--o{ ZJK_POINT : "获得积分"
    ZJK_PRODUCT_SUMMARIZE {
        bigint id PK
        bigint review_id
        varchar product_summarize_name
    }
    ZJK_EXPERT {
        bigint id PK
        bigint user_id
        varchar id_card
    }
```


#### 缓存设计
- **Redis键结构**：
  ```yaml
  expert:{id}: 专家完整信息缓存
  expert_stats: 专家统计信息
  project:{id}:expert_list 项目关联专家列表
  ```

- **过期策略**：
    - 专家信息：24小时 + 随机偏移（防雪崩）
    - 统计信息：定时刷新（每日凌晨）

#### 文件存储设计
- **目录结构**：
  ```
  /expert/
    ├── id_card/{date}/{md5}.jpg   # 身份证件
    ├── diploma/{date}/{uuid}.pdf  # 学历证明
  ```

- **格式**：身份证件为JPG，其他文档为PDF
- **分片策略**：按日期分片+哈希命名

### 3.4 接口设计

#### 外部接口
1. **身份认证接口**
    - 协议：OAuth2.0
    - 端点：`/oauth2/token`
    - 安全：HTTPS + Client Credentials

2. **短信通知接口**
    - 协议：HTTP
    - 规范：
      ```json
      {
        "mobile": "13800138000",
        "template": "EXPERT_APPROVAL",
        "params": {"name": "张三"}
      }
      ```


#### 内部接口
1. **专家服务接口**
    - 路径：`/api/expert/internal/{id}`
    - 方法：GET
    - 协议：Feign HTTP

2. **项目事件消息**
    - 队列：`project.event.queue`
    - 协议：
      ```proto
      message ProjectEvent {
        int64 projectId = 1;
        string eventType = 2; // "CREATE"/"UPDATE"
      }
      ```


#### 接口安全
1. **认证方式**：
    - 内部：Satoken JWT
    - 外部：API Key + IP白名单

2. **加密机制**：
    - 敏感字段：AES-256-GCM（如身份证号）
    - 传输层：TLS 1.3

3. **权限控制**：
   ```java
   @SaCheckRole(value = {
       TenantConstants.JG_ROLE_KEY,
       TenantConstants.TENANT_ADMIN_ROLE_KEY
   }, mode = SaMode.OR)
   ```





