无关风月
2026-01-23 c7854a9422258be4d352a20b9557fd8365a35427
Merge remote-tracking branch 'origin/master'
3个文件已添加
20个文件已修改
1028 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/DashboardStatisticsController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/EntrustProjectController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ProjectController.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/enums/BizResultCode.java 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/ProjectMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/ScreenAccountMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/Project.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/DeviceDetailCheckListQuery.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ScreenAccountService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ClientServiceImpl.java 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProjectInfoServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProjectServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ReportServiceImpl.java 264 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ScreenAccountServiceImpl.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/LoginNameVo.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/OngoingProjectDashboardVO.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ProjectMapPointVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ProjectVo.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenUserVo.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/ProjectMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/ScreenAccountMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/DashboardStatisticsController.java
@@ -74,13 +74,18 @@
                    screenUserVo.setName(param.getName());
                    screenUserVo.setPermissionClient(param.getPermissionClient());
                    screenUserVo.setPermissionProject(param.getPermissionProject());
                    screenUserVo.setCommentType(param.getCommentType());
                }
            }else if(type==2){
                Project project = projectService.getById(id);
                if(project==null){
                    return R.fail("项目不存在");
                }
                Client client = clientService.getById(project.getClientId());
                ClientParam param = clientParamService.getOne(new LambdaQueryWrapper<ClientParam>().eq(ClientParam::getClientId, client.getId()));
                if(param!=null){
                    screenUserVo.setCommentType(param.getCommentType());
                }
                screenUserVo.setName(project.getName());
                screenUserVo.setPermissionProject(project.getPermission());
            }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/EntrustProjectController.java
@@ -12,8 +12,6 @@
import com.ruoyi.system.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.var;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ProjectController.java
@@ -21,10 +21,7 @@
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;
@@ -59,9 +56,30 @@
    @Autowired
    private PositionService positionService;
    @Autowired
    private PlanService planService;
    @Autowired
    private ScreenAccountService screenAccountService;
    @ApiOperation(value = "获取项目/委托方列表",response = LoginNameVo.class)
    @GetMapping("/getLoginNameVoList")
    public R<List<LoginNameVo>> getProjectList(@RequestParam Integer userId) {
        ScreenAccount screenAccount = screenAccountService.getById(userId);
        String clientProjectIds = screenAccount.getClientProjectIds();
        if(screenAccount.getType()==1){
            // 委托方
            List<LoginNameVo> list = screenAccountService.getLoginClient(clientProjectIds);
            return R.ok(list);
        }else {
            // 项目
            List<LoginNameVo> list = screenAccountService.getLoginProject(clientProjectIds);
            return R.ok(list);
        }
    }
@@ -84,6 +102,8 @@
        if(task!=null){
            projectVo.setCheckTime(task.getUpdateTime());
        }
        List<DeviceCountVo> list = deviceUsageService.getProjectDeviceCount(id);
        projectVo.setDeviceCountVos(list);
        return R.ok(projectVo);
    }
@@ -162,7 +182,7 @@
    }
    @ApiOperation(value = "获取设备详情检查列表",response = DeviceDetailCheckListVo.class)
    @ApiOperation(value = "获取检查计划列表",response = DeviceDetailCheckListVo.class)
    @PostMapping("/getDeviceDetailCheckList")
    public R<Page<DeviceDetailCheckListVo>> getDeviceDetailCheckList(@RequestBody DeviceDetailCheckListQuery query) {
        Page<DeviceDetailCheckListVo> page = new Page<>(query.getPageNum(), query.getPageSize());
@@ -172,20 +192,31 @@
    }
    @ApiOperation(value = "获取设备详情检查资料列表")
    @ApiOperation(value = "获取检查资料列表")
    @GetMapping("/getDeviceDetailCheckPlanList")
    public R<List<Check>> getDeviceDetailCheckPlanList(@RequestParam Integer planId) {
        List<Check> list = checkService.list(new LambdaQueryWrapper<Check>().eq(Check::getPlanId,planId).orderByDesc(Check::getTime));
        if(!list.isEmpty()){
            List<Integer> planIds = list.stream().map(Check::getPlanId).toList();
            List<Plan> plans = planService.listByIds(planIds);
            List<Integer> projectIds = list.stream().map(Check::getProjectId).toList();
            List<Project> projects = projectService.listByIds(projectIds);
            list.forEach(check -> {
                check.setPlanName(Objects.requireNonNull(plans.stream().filter(plan -> plan.getId().equals(check.getPlanId())).findFirst().orElse(null)).getName());
                check.setProjectName(Objects.requireNonNull(projects.stream().filter(project -> project.getId().equals(check.getProjectId())).findFirst().orElse(null)).getName());
            });
        }
        return R.ok(list);
    }
    @ApiOperation(value = "获取设备详情检查资料详情")
    @ApiOperation(value = "获取检查资料详情")
    @GetMapping("/getDeviceDetailCheckPlanDetail")
    public R<Check> getDeviceDetailCheckPlanDetail(@RequestParam Integer id) {
        Check check = checkService.getDeviceDetailCheckPlanDetail(id);
        return R.ok(check);
    }
    @ApiOperation(value = "获取大屏人员在岗信息")
@@ -226,6 +257,7 @@
        List<Plan> list = planService.list(new LambdaQueryWrapper<Plan>().eq(Plan::getDeleted, false));
        return R.ok(list);
    }
    @ApiOperation(value = "获取人员在岗列表",response = ProjectPersonOnDutyListVo.class)
    @PostMapping("/getProjectOnDutyList")
@@ -272,6 +304,13 @@
        return R.ok(list);
    }
    @ApiOperation(value = "获取项目重大风险源详情")
    @GetMapping("/getProjectDangerousSourceDetail/{id}")
    public R<?> getProjectDangerousSourceDetail(@PathVariable Integer id) {
        ProjectInfo projectInfo = projectInfoService.getById(id);
        return R.ok(projectInfo);
    }
    @ApiOperation(value = "设备类型")
    @GetMapping("/deviceTypes")
    public R<?> deviceTypeOptions(@RequestParam(value = "title", required = false) String title) {
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -71,6 +71,9 @@
     */
    private SysUser user;
    private Integer type;
    public LoginUser()
    {
    }
@@ -89,6 +92,14 @@
        this.permissions = permissions;
    }
    public Integer getType() {
        return type;
    }
    public void setType(Integer type) {
        this.type = type;
    }
    public Long getUserId()
    {
        return userId;
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -1,6 +1,7 @@
package com.ruoyi.framework.web.service;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
@@ -15,8 +16,10 @@
import com.ruoyi.common.exception.user.*;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
@@ -90,8 +93,14 @@
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException(MessageUtils.message("user.not.exists"));
        }
        if (!user.getPassword().equals(SecureUtil.md5( password)))
        {
            log.info("登录用户:{} 密码错误", username);
            throw new UserPasswordNotMatchException();
        }
        if(user.getState()!=1){
            log.info("登录用户:{} 已被停用.", username);
            throw new ServiceException(MessageUtils.message("user.blocked"));
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(Long.valueOf(user.getId()));
@@ -99,6 +108,7 @@
        sysUser.setUserName(user.getName());
        sysUser.setPassword(user.getPassword());
        loginUser.setUser(sysUser);
        loginUser.setType(user.getType());
        // 生成token
        return loginUser;
    }
ruoyi-system/src/main/java/com/ruoyi/system/enums/BizResultCode.java
New file
@@ -0,0 +1,227 @@
package com.ruoyi.system.enums;
import lombok.Getter;
/**
 * @description: 弹窗消息的定义
 * @author: code
 **/
@Getter
public enum BizResultCode implements ApiResultCode {
    INVALID_OPERATION("无效操作"),
    MOBILE_ALREADY_EXIST("手机号已存在"),
    USERNAME_ALREADY_EXIST("用户名已存在"),
    ACCOUNT_NOT_FOUND("帐号不存在"),
    SYS_VALIDATION_FAILED_ERROR("验证失败,无效请求"),
    APP_CLIENT_NOT_EXIST("登录客户端不存在"),
    SESSION_EXPIRED("会话已过期"),
    SESSION_INVALID("会话无效"),
    NO_LOGIN_ERROR("未登录"),
    ACCOUNT_FORBIDDEN("帐号被禁用"),
    H_CAPTCHA_CODE_NULL_ERROR("图形验证码不能为空"),
    CAPTCHA_CODE_NOT_NULL(""),
    H_CAPTCHA_CODE_VALIDATE_ERROR("图形验证失败"),
    VERIFICATION_CODE_INVALID("图形验证码验证失败"),
    BIZ_PASSWORD_INVALID("密码错误"),
//    BIZ_CLIENT_NOT_FOUND("委托方不存在"),
//    BIZ_CLIENT_NAME_ALREADY_EXISTS("委托方名称已存在"),
//    BIZ_CONTRACT_NOT_EXIST("合同不存在"),
    BIZ_CAR_NOT_EXIST("车辆不存在"),
    BIZ_DATE_FORMAT_ERROR("日期格式错误"),
    BIZ_PROJECT_NOT_EXIST("项目不存在"),
    BIZ_DEVICE_NOT_EXIST("设备不存在"),
    BIZ_SCORE_WEIGHT_CAN_NOT_NULL("分数和权重不能为空"),
    BIZ_HIERARCHY_SYSTEM_NOT_EXIST("体系不存在"),
    BIZ_PARENT_HIERARCHY_SYSTEM_NOT_EXIST("父ID体系不存在"),
    BIZ_PLAN_NOT_EXIST("计划不存在"),
    BIZ_PROBLEM_NUM_CANNOT_NULL("问题数量集合不能为空"),
    BIZ_PROBLEM_SCALE_CANNOT_NULL("对应规模集合不能为空"),
    BIZ_REAL_RULE_NOT_EXIST("实测实量规则不存在"),
    BIZ_EXPERT_NOT_EXIST("专家不存在"),
    EXPERT_FUNCTIONS_MUST_ENABLE("专家功能必须启用"),
    BIZ_MODEL_NOT_EXIST("模型不存在"),
    BIZ_PROJECT_STATUS_NOT_MATCH("项目状态不匹配"),
    BIZ_EXPERT_SCORE_SYS_NOT_EXIST("专家评分体系不存在"),
    BIZ_MEMBERSHIP_DEGREE_NOT_EXIST("隐患等级不存在"),
    BIZ_PROJECT_SUPERVISOR_HIS_NOT_EXIST("项目监督历史不存在"),
    BIZ_PROJECT_DEVICE_NOT_EXIST("项目设备不存在"),
    BIZ_REPORT_TEMPLATE_NOT_EXIST("报告模板不存在"),
    BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST("报告模板类型不存在"),
    BIZ_ARCHIVE_NOT_EXIST("档案不存在"),
    BIZ_PROJECT_NOT_CLOSED("项目未关闭"),
    BIZ_PROJECT_ALREADY_CLOSED("项目已关闭"),
    BIZ_PLAN_CLIENT_EXIST("该委托方对应的计划已存在"),
    BIZ_PLAN_PROJECT_RELATION_NOT_EXIST("计划项目关系不存在"),
    BIZ_PROJECT_NAME_EXIST("同一个委托方下已存在相同名称的项目"),
    HIERARCHY_PARENT_NOT_FOUND("父级体系不存在"),
    HIERARCHY_NODE_NOT_FOUND("节点不存在"),
    HIERARCHY_NODE_NAME_ALREADY_EXISTS("节点名称已存在"),
    BIZ_MODEL_NOT_FOUND("模型不存在"),
    DRIVER_CAR_NOT_MATCH("司机和车辆数量不匹配"),
    PARAM_ERROR("参数错误"),
    CAR_NOT_EXIST("车辆不存在"),
    PROBLEM_NOT_EXIST("问题不存在"),
    ID_CANNOT_NULL("ID不能为空"),
    MODEL_NOT_FOUND("模型不存在"),
    PROJECT_INFO_NOT_EXIST("项目信息不存在"),
    DEVICE_NOT_FOUND("设备不存在"),
    DEVICE_IS_BUSY("设备正在使用中"),
    PLAN_NOT_EXIST("计划不存在"),
    ARCHIVE_NOT_EXIST("档案不存在"),
    ENTITY_NOT_FOUND("实体不存在"),
    ENTITY_NAME_ALREADY_EXISTS("实体名称已存在"),
    ENTITY_CANNOT_NULL("实体不能为空"),
    MODEL_PUBLISHED_CANNOT_MODIFY("已发布的模型不可修改"),
    ACCOUNT_ALREADY_EXISTS("登录账号已存在"),
    //无权修改他人信息
    NO_PERMISSION_MODIFY_OTHERS_INFO("无权修改他人信息"),
    DEVICE_USAGE_NOT_FOUND("设备使用记录不存在"),
    MEMBERSHIP_MATRIX_LOAD_ERROR("隶属度矩阵加载失败"),
    TASK_NOT_FOUND("任务不存在"),
    TASK_ALREADY_EXIST("任务已存在"),
    TASK_STATUS_ERROR("任务状态错误"),
    NUMBER_FACTOR_NOT_EXIST("问题数量集合不存在"),
    NUMBER_FACTOR_INDEX_ERROR("问题数量索引错误"),
    SCALE_FACTOR_NOT_EXIST("对应规模集合不存在"),
    SCALE_FACTOR_INDEX_ERROR("对应规模索引错误"),
    INDEX_COLS_EMPTY("索引列为空"),
    COMPARE_MATRIX_EMPTY("比较矩阵为空"),
    MATRIX_SIZE_ERROR("矩阵大小错误"),
    MATRIX_ERROR("所有的数字都应该是正数,且沿着主对角线对称的元素应该是彼此的相反数"),
    NUMBER_NON_NEGATIVE("所有的数字都应该是非负数"),
    INDEX_RANGE_ERROR("索引范围错误"),
    MEMBERSHIP_MATRIX_ERROR("隶属度矩阵每一行的和应该等于1"),
    SIGN_RECORD_EXIST("重复签到"),
    PLAN_NAME_EXIST("计划名称已存在"),
    CAR_LICENSE_NO_EXIST("车牌号已存在"),
    HIERARCHY_NOT_FOUND("体系数据不存在"),
    PLAN_NOT_FOUND("计划不存在"),
    RECORD_NOT_FOUND("问题记录不存在"),
    RECORD_REVIEW_EXISTED("问题已经复核"),
    REVIEW_ALREADY_REFORMED("问题已经整改,无须复查"),
    UPLOAD_FILE_FAILED("上传文件失败"),
    UPLOAD_FILE_CONTAINS_ILLEGAL_CHARACTERS("上传文件名包含非法字符"),
    FILE_NOT_FOUND("文件不存在"),
    EVAL_FUZZY_RESULT_NOT_EXIST("模糊评价结果不存在"),
    EVAL_SCORE_RESULT_NOT_EXIST("评分评价结果不存在"),
    USER_IS_DISABLE("用户已被禁用"),
    EXPERT_MODEL_NOT_EXIST("专家对应的模型不存在"),
    MEMBERSHIP_MATRIX_NOT_EXIST("隶属度矩阵不存在"),
    EXPERT_NOT_FOUND("专家不存在"),
    MOBILE_FORMAT_ERROR("手机号格式错误"),
    HIERARCHY_NOT_EXIST("体系不存在"),
    PlAN_MODEL_EXPERT_SHOULD_PAIRED("计划模型和专家模型不匹配"),
    PLAN_SYSTEM_MODEL_NOT_EXIST("综合体系模型不存在"),
    PLAN_DEVICE_MODEL_NOT_EXIST("设备体系模型不存在"),
    REVIEW_TASK_NOT_EXIST("复核任务不存在"),
    ERROR_RECORD_ALL_REVIEWD("问题已全部复核"),
    PROJECT_INFO_EXISTS("检查任务对应的项目信息已存在"),
    IMPORT_DATA_EMPTY("导入数据为空"),
    IMPORT_DATA_COLUMN_COUNT("导入数据列数不正确"),
    CLIENT_NOT_FOUND("委托方不存在"),
    DEVICE_ALREADY_EXISTS("设备名称已存在"),
    ROLE_NOT_FOUND("角色不存在"),
    CHECK_TASK_NOT_EXIST("检查任务不存在"),
    DEVICE_USAGE_NOT_EXISTED("设备使用记录不存在"),
    PASSWORD_ERROR("密码输入错误"),
    PASSWORD_FORMAT_ERROR("密码需要6到16位长度"),
    // License相关错误码
    LICENSE_NOT_CONFIGURED("License密钥未配置"),
    LICENSE_INVALID_FORMAT("License格式错误"),
    LICENSE_SIGNATURE_INVALID("License签名验证失败"),
    LICENSE_EXPIRED("License已过期"),
    LICENSE_VALIDATION_FAILED("License验证失败"),
    // 报告生成相关错误码
    BIZ_REPORT_GENERATE_FAILED("报告生成失败");
    private final String errorMsg;
    BizResultCode(String errorMsg) {
        this.errorMsg = errorMsg;
    }
    /**
     * 得到 message 的值.
     *
     * @return 属性 message 的值.
     */
    @Override
    public String getErrorMsg() {
        return errorMsg + "(" + getAppId() + ")";
    }
    /**
     * @return 当前服务的AppId
     */
    @Override
    public String getAppId() {
        return "1001";
    }
    /**
     * 校验方法
     *
     * @param expect
     */
    public void check(boolean expect) {
        if (expect) {
            throw new BizException(this.errorMsg);
        }
    }
    /**
     * 校验方法
     * @param expect
     * @param code
     */
    public void check(boolean expect, String code) {
        if (expect) {
            throw new BizException(code);
        }
    }
    /**
     * 校验方法
     * @param expect
     * @param code
     * @param message
     */
    public void check(boolean expect, String code, String message) {
        if (expect) {
            throw new BizException(message);
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/ProjectMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.system.model.Project;
import com.ruoyi.system.query.DeviceDetailCheckListQuery;
import com.ruoyi.system.vo.DeviceDetailCheckListVo;
import org.apache.ibatis.annotations.Param;
@@ -19,7 +20,7 @@
 */
public interface ProjectMapper extends BaseMapper<Project> {
    List<DeviceDetailCheckListVo> getDeviceDetailCheckList(@Param("page") Page<DeviceDetailCheckListVo> page, @Param("projectId") Integer projectId);
    List<DeviceDetailCheckListVo> getDeviceDetailCheckList(@Param("page") Page<DeviceDetailCheckListVo> page, @Param("query") DeviceDetailCheckListQuery query);
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/ScreenAccountMapper.java
@@ -3,10 +3,16 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.system.model.Contract;
import com.ruoyi.system.model.ScreenAccount;
import com.ruoyi.system.vo.LoginNameVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ScreenAccountMapper extends BaseMapper<ScreenAccount> {
    Long getToken(@Param("key") String key);
    List<LoginNameVo> getLoginClient(@Param("ids") List<String> ids);
    List<LoginNameVo> getLoginProject(@Param("ids") List<String> ids);
}
ruoyi-system/src/main/java/com/ruoyi/system/model/Project.java
@@ -66,4 +66,14 @@
    private String permission;
    private String scale;
    /**
     * 状态:1-在建 2-完成
     */
    @TableField("status")
    private Integer status;
    /**
     * 完成时间
     */
    @TableField("success_time")
    private Date successTime;
}
ruoyi-system/src/main/java/com/ruoyi/system/query/DeviceDetailCheckListQuery.java
@@ -5,10 +5,27 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("设备详情检查列表查询query")
public class DeviceDetailCheckListQuery extends BasePage {
    @ApiModelProperty("项目id")
    @NotNull(message = "项目id不能为空")
    private Integer projectId;
    @ApiModelProperty("计划类型")
    private Integer planType;
    @ApiModelProperty("开始时间")
    private String startTime;
    @ApiModelProperty("结束时间")
    private String endTime;
    @ApiModelProperty("计划名称")
    private String planName;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ScreenAccountService.java
@@ -3,6 +3,9 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.system.model.OnDuty;
import com.ruoyi.system.model.ScreenAccount;
import com.ruoyi.system.vo.LoginNameVo;
import java.util.List;
/**
 * <p>
@@ -18,4 +21,9 @@
    Long getToken(String key);
    List<LoginNameVo> getLoginClient(String clientProjectIds);
    List<LoginNameVo> getLoginProject(String clientProjectIds);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ClientServiceImpl.java
@@ -12,12 +12,14 @@
import com.ruoyi.system.mapper.PlanMapper;
import com.ruoyi.system.mapper.ProjectMapper;
import com.ruoyi.system.mapper.RecordMapper;
import com.ruoyi.system.mapper.TaskMapper;
import com.ruoyi.system.model.Check;
import com.ruoyi.system.model.Client;
import com.ruoyi.system.model.DeviceUsage;
import com.ruoyi.system.model.Plan;
import com.ruoyi.system.model.Project;
import com.ruoyi.system.model.Record;
import com.ruoyi.system.model.Task;
import com.ruoyi.system.service.ClientService;
import com.ruoyi.system.service.ProjectCategoryCalculator;
import com.ruoyi.system.vo.*;
@@ -49,6 +51,7 @@
    private final ProjectMapper projectMapper;
    private final PlanMapper planMapper;
    private final CheckMapper checkMapper;
    private final TaskMapper taskMapper;
    private final DeviceUsageMapper deviceUsageMapper;
    private final RecordMapper recordMapper;
    private final ProjectCategoryCalculator projectCategoryCalculator;
@@ -88,7 +91,15 @@
        // 查询在建工程项目(usage_type 表示项目用途类型,假设 0 表示在建工程)
        LambdaQueryWrapper<Project> projectWrapper = new LambdaQueryWrapper<>();
        projectWrapper.eq(Project::getDeleted, false)
                .eq(Project::getUsageType, 0); // 在建工程
                .ne(Project::getType, 2) // 在建工程
                .and(wrapper -> wrapper
                    .eq(Project::getStatus, 1)  // 在建项目
                    .or(w -> w
                        .eq(Project::getStatus, 2)  // 已完成项目
                        .ge(Project::getSuccessTime, monthStart)  // 完成时间 >= 开始日期
                        .le(Project::getSuccessTime, monthEnd)    // 完成时间 <= 结束日期
                    )
                );
        if (clientId != null) {
            projectWrapper.eq(Project::getClientId, clientId);
        }
@@ -101,41 +112,66 @@
        vo.setHousingProjectCount((int) housingCount);
        vo.setMunicipalProjectCount((int) municipalCount);
        // 计算检查覆盖率
        // 计算检查覆盖率(仅当查询时间范围为当月时才计算)
        List<Integer> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
        if (!projectIds.isEmpty()) {
            LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
            checkWrapper.in(Check::getProjectId, projectIds);
            List<Check> checks = checkMapper.selectList(checkWrapper);
        if (!projectIds.isEmpty() && isCurrentMonth(monthStart, monthEnd)) {
            // 1. 先查询符合条件的 Task
            LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
            taskWrapper.in(Task::getProjectId, projectIds)
                    .eq(Task::getDeleted, false);
            List<Task> tasks = taskMapper.selectList(taskWrapper);
            List<Integer> checkedProjectIds = checks.stream()
                    .map(Check::getProjectId)
                    .distinct()
                    .toList();
            if (!tasks.isEmpty()) {
                // 2. 获取 Task ID 列表
                List<Integer> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
            // 房建检查覆盖率
            List<Integer> housingProjectIds = projects.stream()
                    .filter(p -> p.getType() != null && p.getType() == 0)
                    .map(Project::getId)
                    .toList();
            long checkedHousingCount = checkedProjectIds.stream()
                    .filter(housingProjectIds::contains)
                    .count();
            vo.setHousingInspectionCoverage(
                    housingCount > 0 ? (int) Math.round(checkedHousingCount * 100.0 / housingCount) : 0
            );
                // 3. 建立 Task ID 到 Project ID 的映射
                Map<Integer, Integer> taskToProjectMap = tasks.stream()
                        .collect(Collectors.toMap(Task::getId, Task::getProjectId));
            // 市政检查覆盖率
            List<Integer> municipalProjectIds = projects.stream()
                    .filter(p -> p.getType() != null && p.getType() == 1)
                    .map(Project::getId)
                    .toList();
            long checkedMunicipalCount = checkedProjectIds.stream()
                    .filter(municipalProjectIds::contains)
                    .count();
            vo.setMunicipalInspectionCoverage(
                    municipalCount > 0 ? (int) Math.round(checkedMunicipalCount * 100.0 / municipalCount) : 0
            );
                // 4. 查询 record 表中 record_type='error' 且 device_id 为 null 的记录(项目检查)
                LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
                recordWrapper.eq(Record::getRecordType, "error")
                        .isNull(Record::getDeviceId)
                        .in(Record::getCheckTaskId, taskIds)
                        .eq(Record::getDeleted, false);
                List<Record> projectRecords = recordMapper.selectList(recordWrapper);
                // 5. 通过 Task 映射获取有检查记录的项目 ID
                List<Integer> checkedProjectIds = projectRecords.stream()
                        .map(Record::getCheckTaskId)
                        .map(taskToProjectMap::get)
                        .filter(Objects::nonNull)
                        .distinct()
                        .toList();
                // 房建检查覆盖率
                List<Integer> housingProjectIds = projects.stream()
                        .filter(p -> p.getType() != null && p.getType() == 0)
                        .map(Project::getId)
                        .toList();
                long checkedHousingCount = checkedProjectIds.stream()
                        .filter(housingProjectIds::contains)
                        .count();
                vo.setHousingInspectionCoverage(
                        housingCount > 0 ? (int) Math.round(checkedHousingCount * 100.0 / housingCount) : 0
                );
                // 市政检查覆盖率
                List<Integer> municipalProjectIds = projects.stream()
                        .filter(p -> p.getType() != null && p.getType() == 1)
                        .map(Project::getId)
                        .toList();
                long checkedMunicipalCount = checkedProjectIds.stream()
                        .filter(municipalProjectIds::contains)
                        .count();
                vo.setMunicipalInspectionCoverage(
                        municipalCount > 0 ? (int) Math.round(checkedMunicipalCount * 100.0 / municipalCount) : 0
                );
            } else {
                vo.setHousingInspectionCoverage(0);
                vo.setMunicipalInspectionCoverage(0);
            }
        } else {
            vo.setHousingInspectionCoverage(0);
            vo.setMunicipalInspectionCoverage(0);
@@ -145,7 +181,23 @@
        calculateMonthlyInspectionForOngoing(vo, projects, projectIds, monthStart, monthEnd);
        // 3. 统计大型机械设备数
        vo.setMachineryStatistics(calculateMachineryStatistics(projectIds));
        List<MachineryStatisticsVO> machineryStatistics = calculateMachineryStatistics(projectIds);
        vo.setMachineryStatistics(machineryStatistics);
        // 汇总计算设备总数统计
        int machineryTotal = machineryStatistics.stream()
                .mapToInt(MachineryStatisticsVO::getTotal)
                .sum();
        int inspectedMachineryTotal = machineryStatistics.stream()
                .mapToInt(MachineryStatisticsVO::getInspectedCount)
                .sum();
        int uninspectedMachineryTotal = machineryStatistics.stream()
                .mapToInt(MachineryStatisticsVO::getUninspectedCount)
                .sum();
        vo.setMachineryTotal(machineryTotal);
        vo.setInspectedMachineryTotal(inspectedMachineryTotal);
        vo.setUninspectedMachineryTotal(uninspectedMachineryTotal);
        // 4. 统计重大隐患数
        calculateHazardStatistics(vo, projectIds);
@@ -165,7 +217,15 @@
        // 查询固定资产项目(usage_type 表示项目用途类型,假设 1 表示固定资产)
        LambdaQueryWrapper<Project> projectWrapper = new LambdaQueryWrapper<>();
        projectWrapper.eq(Project::getDeleted, false)
                .eq(Project::getUsageType, 1); // 固定资产
                .eq(Project::getUsageType, 1) // 固定资产
                .and(wrapper -> wrapper
                    .eq(Project::getStatus, 1)  // 在建项目
                    .or(w -> w
                        .eq(Project::getStatus, 2)  // 已完成项目
                        .ge(Project::getSuccessTime, monthStart)  // 完成时间 >= 开始日期
                        .le(Project::getSuccessTime, monthEnd)    // 完成时间 <= 结束日期
                    )
                );
        if (clientId != null) {
            projectWrapper.eq(Project::getClientId, clientId);
        }
@@ -177,17 +237,41 @@
        // 计算检查覆盖率
        List<Integer> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
        if (!projectIds.isEmpty()) {
            LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
            checkWrapper.in(Check::getProjectId, projectIds);
            List<Check> checks = checkMapper.selectList(checkWrapper);
            // 1. 先查询符合条件的 Task
            LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
            taskWrapper.in(Task::getProjectId, projectIds)
                    .eq(Task::getDeleted, false);
            List<Task> tasks = taskMapper.selectList(taskWrapper);
            long checkedProjectCount = checks.stream()
                    .map(Check::getProjectId)
                    .distinct()
                    .count();
            vo.setInspectionCoverage(
                    projects.size() > 0 ? (int) Math.round(checkedProjectCount * 100.0 / projects.size()) : 0
            );
            if (!tasks.isEmpty()) {
                // 2. 获取 Task ID 列表
                List<Integer> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
                // 3. 建立 Task ID 到 Project ID 的映射
                Map<Integer, Integer> taskToProjectMap = tasks.stream()
                        .collect(Collectors.toMap(Task::getId, Task::getProjectId));
                // 4. 查询 record 表中 record_type='error' 且 device_id 为 null 的记录(项目检查)
                LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
                recordWrapper.eq(Record::getRecordType, "error")
                        .isNull(Record::getDeviceId)
                        .in(Record::getCheckTaskId, taskIds)
                        .eq(Record::getDeleted, false);
                List<Record> projectRecords = recordMapper.selectList(recordWrapper);
                // 5. 通过 Task 映射获取有检查记录的项目 ID
                long checkedProjectCount = projectRecords.stream()
                        .map(Record::getCheckTaskId)
                        .map(taskToProjectMap::get)
                        .filter(Objects::nonNull)
                        .distinct()
                        .count();
                vo.setInspectionCoverage(
                        projects.size() > 0 ? (int) Math.round(checkedProjectCount * 100.0 / projects.size()) : 0
                );
            } else {
                vo.setInspectionCoverage(0);
            }
        } else {
            vo.setInspectionCoverage(0);
        }
@@ -219,15 +303,44 @@
            return;
        }
        // 查询本月有检查记录的项目
        LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.in(Check::getProjectId, projectIds)
                .ge(Check::getTime, monthStart)
                .le(Check::getTime, monthEnd);
        List<Check> monthlyChecks = checkMapper.selectList(checkWrapper);
        // 1. 先查询符合条件的 Task(本月的任务)
        LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(Task::getProjectId, projectIds)
                .ge(Task::getDate, monthStart.toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                .le(Task::getDate, monthEnd.toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                .eq(Task::getDeleted, false);
        List<Task> monthlyTasks = taskMapper.selectList(taskWrapper);
        List<Integer> inspectedProjectIds = monthlyChecks.stream()
                .map(Check::getProjectId)
        if (monthlyTasks.isEmpty()) {
            vo.setInspectedCount(0);
            vo.setInspectedHousingCount(0);
            vo.setInspectedMunicipalCount(0);
            vo.setUninspectedCount(projects.size());
            vo.setUninspectedHousingCount(vo.getHousingProjectCount());
            vo.setUninspectedMunicipalCount(vo.getMunicipalProjectCount());
            return;
        }
        // 2. 获取 Task ID 列表
        List<Integer> taskIds = monthlyTasks.stream().map(Task::getId).collect(Collectors.toList());
        // 3. 建立 Task ID 到 Project ID 的映射
        Map<Integer, Integer> taskToProjectMap = monthlyTasks.stream()
                .collect(Collectors.toMap(Task::getId, Task::getProjectId));
        // 4. 查询本月有检查记录的项目(查询 record 表中 record_type='error' 且 device_id 为 null 的记录)
        LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(Record::getRecordType, "error")
                .isNull(Record::getDeviceId)
                .in(Record::getCheckTaskId, taskIds)
                .eq(Record::getDeleted, false);
        List<Record> monthlyRecords = recordMapper.selectList(recordWrapper);
        // 5. 通过 Task 映射获取有检查记录的项目 ID
        List<Integer> inspectedProjectIds = monthlyRecords.stream()
                .map(Record::getCheckTaskId)
                .map(taskToProjectMap::get)
                .filter(Objects::nonNull)
                .distinct()
                .toList();
@@ -265,15 +378,40 @@
            return;
        }
        // 查询本月有检查记录的项目
        LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.in(Check::getProjectId, projectIds)
                .ge(Check::getTime, monthStart)
                .le(Check::getTime, monthEnd);
        List<Check> monthlyChecks = checkMapper.selectList(checkWrapper);
        // 1. 先查询符合条件的 Task(本月的任务)
        LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(Task::getProjectId, projectIds)
                .ge(Task::getDate, monthStart.toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                .le(Task::getDate, monthEnd.toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                .eq(Task::getDeleted, false);
        List<Task> monthlyTasks = taskMapper.selectList(taskWrapper);
        long inspectedCount = monthlyChecks.stream()
                .map(Check::getProjectId)
        if (monthlyTasks.isEmpty()) {
            vo.setInspectedCount(0);
            vo.setUninspectedCount(projects.size());
            return;
        }
        // 2. 获取 Task ID 列表
        List<Integer> taskIds = monthlyTasks.stream().map(Task::getId).collect(Collectors.toList());
        // 3. 建立 Task ID 到 Project ID 的映射
        Map<Integer, Integer> taskToProjectMap = monthlyTasks.stream()
                .collect(Collectors.toMap(Task::getId, Task::getProjectId));
        // 4. 查询本月有检查记录的项目(查询 record 表中 record_type='error' 且 device_id 为 null 的记录)
        LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(Record::getRecordType, "error")
                .isNull(Record::getDeviceId)
                .in(Record::getCheckTaskId, taskIds)
                .eq(Record::getDeleted, false);
        List<Record> monthlyRecords = recordMapper.selectList(recordWrapper);
        // 5. 通过 Task 映射获取有检查记录的项目 ID
        long inspectedCount = monthlyRecords.stream()
                .map(Record::getCheckTaskId)
                .map(taskToProjectMap::get)
                .filter(Objects::nonNull)
                .distinct()
                .count();
@@ -305,8 +443,10 @@
        Map<Integer, Boolean> deviceInspectionMap = new HashMap<>();
        if (!deviceIds.isEmpty()) {
            LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
            recordWrapper.eq(Record::getDeleted, false)
                    .in(Record::getDeviceId, deviceIds);
            recordWrapper.eq(Record::getRecordType, "error")
                    .isNotNull(Record::getDeviceId)
                    .in(Record::getDeviceId, deviceIds)
                    .eq(Record::getDeleted, false);
            List<Record> records = recordMapper.selectList(recordWrapper);
            Set<Integer> inspectedDeviceIds = records.stream()
@@ -349,10 +489,11 @@
        }
        // 查询检查任务
        LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.in(Check::getProjectId, projectIds);
        List<Check> checks = checkMapper.selectList(checkWrapper);
        List<Integer> checkTaskIds = checks.stream().map(Check::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(Task::getProjectId, projectIds)
                .eq(Task::getDeleted, false);
        List<Task> tasks = taskMapper.selectList(taskWrapper);
        List<Integer> checkTaskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        if (checkTaskIds.isEmpty()) {
            vo.setMajorHazardTotal(0);
@@ -361,11 +502,11 @@
            return;
        }
        // 查询重大隐患记录(level 表示隐患等级,假设 3 表示重大隐患)
        // 查询重大隐患记录(level 表示隐患等级,0 表示重大隐患)
        LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(Record::getDeleted, false)
                .in(Record::getCheckTaskId, checkTaskIds)
                .eq(Record::getLevel, 3); // 重大隐患等级
                .eq(Record::getLevel, 0); // 重大隐患等级
        List<Record> majorHazards = recordMapper.selectList(recordWrapper);
        vo.setMajorHazardTotal(majorHazards.size());
@@ -394,10 +535,11 @@
        }
        // 查询检查任务
        LambdaQueryWrapper<Check> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.in(Check::getProjectId, projectIds);
        List<Check> checks = checkMapper.selectList(checkWrapper);
        List<Integer> checkTaskIds = checks.stream().map(Check::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(Task::getProjectId, projectIds)
                .eq(Task::getDeleted, false);
        List<Task> tasks = taskMapper.selectList(taskWrapper);
        List<Integer> checkTaskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        if (checkTaskIds.isEmpty()) {
            vo.setMajorHazardTotal(0);
@@ -406,11 +548,11 @@
            return;
        }
        // 查询重大隐患记录(level 表示隐患等级,假设 3 表示重大隐患)
        // 查询重大隐患记录(level 表示隐患等级,0 表示重大隐患)
        LambdaQueryWrapper<Record> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(Record::getDeleted, false)
                .in(Record::getCheckTaskId, checkTaskIds)
                .eq(Record::getLevel, 3); // 重大隐患等级
                .eq(Record::getLevel, 0); // 重大隐患等级
        List<Record> majorHazards = recordMapper.selectList(recordWrapper);
        vo.setMajorHazardTotal(majorHazards.size());
@@ -513,4 +655,27 @@
        YearMonth currentMonth = YearMonth.now();
        return Date.from(currentMonth.atEndOfMonth().atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     * 判断给定的日期范围是否为当前月份
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 如果日期范围在当前月份内则返回 true,否则返回 false
     */
    private boolean isCurrentMonth(Date startDate, Date endDate) {
        if (startDate == null || endDate == null) {
            return false;
        }
        YearMonth currentMonth = YearMonth.now();
        LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        YearMonth startMonth = YearMonth.from(start);
        YearMonth endMonth = YearMonth.from(end);
        // 判断开始和结束日期是否都在当前月份
        return startMonth.equals(currentMonth) && endMonth.equals(currentMonth);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProjectInfoServiceImpl.java
@@ -1,20 +1,16 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.mapper.ProjectInfoMapper;
import com.ruoyi.system.model.Project;
import com.ruoyi.system.model.ProjectInfo;
import com.ruoyi.system.mapper.ProjectInfoMapper;
import com.ruoyi.system.model.Record;
import com.ruoyi.system.query.ProjectDangerousTrendQuery;
import com.ruoyi.system.query.ProjectHiddenDangerTrendListQuery;
import com.ruoyi.system.service.ProjectCategoryCalculator;
import com.ruoyi.system.service.ProjectInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.service.ProjectService;
import com.ruoyi.system.service.RecordService;
import com.ruoyi.system.vo.ProjectDangerousTrendVo;
import com.ruoyi.system.vo.ProjectHiddenDangerList;
import com.ruoyi.system.vo.ProjectHiddenDangerNextList;
@@ -30,7 +26,10 @@
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.groupingBy;
@@ -230,18 +229,5 @@
        // 计算月份差 + 1(包含结束月份)
        return (int) ChronoUnit.MONTHS.between(start, end) + 1;
    }
    public static void main(String[] args) {
        LocalDate monthBoundaries = getMonthBoundaries("2025-03", true);
        System.out.println(monthBoundaries);
        System.out.println(getMonthBoundaries("2025-02",false));
        System.out.println(calculateMonthsBetween("2025-03", "2026-01"));
        for (int count = 0; count < 11; count++) {
            // 根据2025-03 根据循环获取下一个月的时间
            LocalDate monthBoundaries1 = getMonthBoundaries("2025-03", true).plusMonths(count);
            System.out.println(monthBoundaries1.toString().substring(0,7));
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProjectServiceImpl.java
@@ -37,7 +37,7 @@
    public List<DeviceDetailCheckListVo> getDeviceDetailCheckList(Page<DeviceDetailCheckListVo> page, DeviceDetailCheckListQuery query) {
        Project project = this.getById(query.getProjectId());
        Integer clientId = project.getClientId();
        List<DeviceDetailCheckListVo> deviceDetailCheckList = this.baseMapper.getDeviceDetailCheckList(page, query.getProjectId());
        List<DeviceDetailCheckListVo> deviceDetailCheckList = this.baseMapper.getDeviceDetailCheckList(page, query);
        ClientParam param = clientParamService.getOne(new LambdaQueryWrapper<ClientParam>().eq(ClientParam::getClientId, clientId));
        if(param!=null){
            deviceDetailCheckList.forEach(item -> {
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ReportServiceImpl.java
New file
@@ -0,0 +1,264 @@
package com.ruoyi.system.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.system.enums.BizResultCode;
import com.ruoyi.system.model.ReportTemplate;
import com.ruoyi.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
/**
 * 报告数据服务实现类
 **/
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {
    @Resource
    private ReportTemplateService reportTemplateService;
    @Resource
    private ProjectInfoService projectInfoService;
    @Resource
    private DeviceUsageService deviceUsageService;
    @Resource
    private EvalFuzzyService evalFuzzyService;
    @Resource
    private EvalScoreService evalScoreService;
    @Resource
    private ErrorRecordService errorRecordService;
    @Resource
    private DeviceService deviceService;
    @Resource
    private UserFileService userFileService;
    @Override
    public JSONObject fuzzyReportData(Integer checkTaskId, Integer templateId) {
        var evalFuzzyResult = evalFuzzyService.getByCheckTaskId(checkTaskId);
        BizResultCode.EVAL_FUZZY_RESULT_NOT_EXIST.check(evalFuzzyResult == null);
        var evalScoreResult =  evalScoreService.getByCheckTaskId(checkTaskId);
        BizResultCode.EVAL_SCORE_RESULT_NOT_EXIST.check(evalScoreResult == null);
        var reportTemplate = reportTemplateService.get(templateId);
        BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null);
        switch (reportTemplate.getType()) {
            case ThirdPartyReport:
                return buildFuzzySystemReportData(evalFuzzyResult, evalScoreResult, reportTemplate);
            case DeviceReport:
                return buildFuzzyDeviceReportData(evalFuzzyResult, evalScoreResult, reportTemplate);
            default:
                throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST);
        }
    }
    @Override
    public JSONObject scoreReportData(Integer checkTaskId, Integer templateId) {
        var evalFuzzyResult = evalFuzzyService.getByCheckTaskId(checkTaskId);
        BizResultCode.EVAL_FUZZY_RESULT_NOT_EXIST.check(evalFuzzyResult == null);
        var evalScoreResult =  evalScoreService.getByCheckTaskId(checkTaskId);
        BizResultCode.EVAL_SCORE_RESULT_NOT_EXIST.check(evalScoreResult == null);
        var reportTemplate = reportTemplateService.get(templateId);
        BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null);
        switch (reportTemplate.getType()) {
            case ThirdPartyReport:
                return buildScoreSystemReportData(evalFuzzyResult, evalScoreResult, reportTemplate);
            case DeviceReport:
                return buildScoreDeviceReportData(evalFuzzyResult, evalScoreResult, reportTemplate);
            default:
                throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST);
        }
    }
    @Override
    public XWPFTemplate fuzzyReport(Integer checkTaskId, Integer templateId) {
        var reportData = fuzzyReportData(checkTaskId, templateId);
        var builder = getReportBuilder(templateId);
        var template = reportTemplateService.get(templateId);
        // reportData to JSONObject
        return builder.buildReport(reportData, template.getConfig());
    }
    @Override
    public XWPFTemplate scoreReport(Integer checkTaskId, Integer templateId) {
        var reportData = scoreReportData(checkTaskId, templateId);
        var builder = getReportBuilder(templateId);
        var template = reportTemplateService.get(templateId);
        // reportData to JSONObject
        return builder.buildReport(reportData, template.getConfig());
    }
    @Override
    public void fuzzyReportPdf(Integer checkTaskId, Integer templateId, OutputStream outputStream) {
        try (var doc = fuzzyReport(checkTaskId, templateId)) {
            convertToPdf(doc, outputStream);
        } catch (Exception e) {
            log.error("生成模糊评价PDF报告失败", e);
            throw new BizException("生成模糊评价PDF报告失败");
        }
    }
    @Override
    public void scoreReportPdf(Integer checkTaskId, Integer templateId, OutputStream outputStream) {
        try (var doc = scoreReport(checkTaskId, templateId)) {
            convertToPdf(doc, outputStream);
        } catch (Exception e) {
            log.error("生成打分评价PDF报告失败", e);
            throw new BizException("生成打分评价PDF报告失败");
        }
    }
    /**
     * 将Word文档转换为PDF
     * @param template Word模板
     * @param outputStream 输出流
     */
    private void convertToPdf(XWPFTemplate template, OutputStream outputStream) throws Exception {
        // 先将Word模板写入字节数组
        ByteArrayOutputStream docOutputStream = new ByteArrayOutputStream();
        template.write(docOutputStream);
        // 从字节数组读取Word文档
        ByteArrayInputStream docInputStream = new ByteArrayInputStream(docOutputStream.toByteArray());
        org.apache.poi.xwpf.usermodel.XWPFDocument document = new org.apache.poi.xwpf.usermodel.XWPFDocument(docInputStream);
        // 转换为PDF
        PdfOptions options = PdfOptions.create();
        PdfConverter.getInstance().convert(document, outputStream, options);
        // 关闭资源
        document.close();
        docInputStream.close();
        docOutputStream.close();
    }
    private ReportBuilderBase getReportBuilder(Integer templateId) {
        var reportTemplate = reportTemplateService.get(templateId);
        BizResultCode.BIZ_REPORT_TEMPLATE_NOT_EXIST.check(reportTemplate == null);
        switch (reportTemplate.getType()) {
            case ThirdPartyReport:
                return new SystemReportBuilder(userFileService);
            case DeviceReport:
                return new DeviceReportBuilder(userFileService);
            default:
                throw new BizException(BizResultCode.BIZ_REPORT_TEMPLATE_TYPE_NOT_EXIST);
        }
    }
    private JSONObject buildFuzzySystemReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult, ReportTemplate reportTemplate) {
        // 查询必须要的数据
        var records = errorRecordService.listSystemErrors(evalFuzzyResult.getTask().getId());
        var project = evalFuzzyResult.getProject();
        var projectInfo = evalFuzzyResult.getTask().getProjectInfo();
//        var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId());
        var deviceUsages = deviceUsageService.listUsages(project.getId(), null);
        var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList();
        var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent();
        // 生成报告数据
        return SystemFuzzyReportData.builder()
                .reportId(evalFuzzyResult.getId())
                .systemHierarchy(hierarchy)
                .sysResult(evalFuzzyResult.getSystemRes())
                .scoreResult(scoreResult.getSystemRes())
                .template(reportTemplate)
                .project(project)
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .build()
                .generate();
    }
    private JSONObject buildScoreSystemReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult, ReportTemplate reportTemplate) {
        // 查询必须要的数据
        var records = errorRecordService.listSystemErrors(evalFuzzyResult.getTask().getId());
        var project = evalFuzzyResult.getProject();
//        var projectInfo = projectInfoService.latest(evalFuzzyResult.getProject().getId());
        var projectInfo = evalFuzzyResult.getTask().getProjectInfo();
        var deviceUsages = deviceUsageService.listUsages(project.getId(), null);
        var devices= deviceUsages.stream().map(DeviceUsage::getDevice).toList();
        var hierarchy = evalFuzzyResult.getPlan().getSystemScoreExpert().getModel().getHierarchy().getContent();
        // 生成报告数据
        return SystemScoreReportData.builder()
                .reportId(evalFuzzyResult.getId())
                .systemHierarchy(hierarchy)
                .sysResult(evalFuzzyResult.getSystemRes())
                .scoreResult(scoreResult.getSystemRes())
                .template(reportTemplate)
                .project(project)
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .build()
                .generate();
    }
    private JSONObject buildFuzzyDeviceReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult scoreResult,  ReportTemplate reportTemplate) {
        var records = errorRecordService.listDeviceErrors(evalFuzzyResult.getTask().getId());
        var project = evalFuzzyResult.getProject();
        var projectInfo = evalFuzzyResult.getTask().getProjectInfo();
//        var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId());
        var deviceIds = evalFuzzyResult.getDeviceResMap().keySet();
        var devices = deviceService.findAllById(deviceIds);
        var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent();
        // 生成报告数据
        return DeviceFuzzyReportData.builder()
                .reportId(evalFuzzyResult.getId())
                .deviceResMap(evalFuzzyResult.getDeviceResMap())
                .deviceHierarchy(hierarchy)
                .template(reportTemplate)
                .project(project)
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .build()
                .generate();
    }
    private JSONObject buildScoreDeviceReportData(EvalFuzzyResult evalFuzzyResult, EvalScoreResult evalScoreResult, ReportTemplate reportTemplate) {
        var records = errorRecordService.listDeviceErrors(evalFuzzyResult.getTask().getId());
        var project = evalFuzzyResult.getProject();
//        var projectInfo = projectInfoService.getByCheckTaskId(evalFuzzyResult.getTask().getId());
        var projectInfo = evalFuzzyResult.getTask().getProjectInfo();
        var deviceIds = evalFuzzyResult.getDeviceResMap().keySet();
        var devices = deviceService.findAllById(deviceIds);
        var hierarchy = evalFuzzyResult.getPlan().getDeviceScoreExpert().getModel().getHierarchy().getContent();
        // 生成报告数据
        return DeviceScoreReportData.builder()
                .reportId(evalFuzzyResult.getId())
                .deviceResMap(evalFuzzyResult.getDeviceResMap())
                .deviceScoreResMap(evalScoreResult.getDeviceResMap())
                .deviceHierarchy(hierarchy)
                .template(reportTemplate)
                .project(project)
                .projectInfo(projectInfo)
                .devices(devices)
                .records(records)
                .build()
                .generate();
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ScreenAccountServiceImpl.java
@@ -8,7 +8,11 @@
import com.ruoyi.system.model.ScreenAccount;
import com.ruoyi.system.service.OnDutyService;
import com.ruoyi.system.service.ScreenAccountService;
import com.ruoyi.system.vo.LoginNameVo;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
 * <p>
@@ -30,4 +34,15 @@
    public Long getToken(String key) {
        return this.baseMapper.getToken(key);
    }
    @Override
    public List<LoginNameVo> getLoginClient(String clientProjectIds) {
        return this.baseMapper.getLoginClient(Arrays.asList(clientProjectIds.split( ",")));
    }
    @Override
    public List<LoginNameVo> getLoginProject(String clientProjectIds) {
        return this.baseMapper.getLoginProject(Arrays.asList(clientProjectIds.split( ",")));
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/LoginNameVo.java
New file
@@ -0,0 +1,12 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel("登录查看选择账户")
public class LoginNameVo {
    private Integer id;
    private String name;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/OngoingProjectDashboardVO.java
@@ -52,6 +52,15 @@
    private Integer uninspectedMunicipalCount;
    // ==================== 大型机械设备数 ====================
    @ApiModelProperty("大型机械设备总数")
    private Integer machineryTotal;
    @ApiModelProperty("已检查大型机械设备总数")
    private Integer inspectedMachineryTotal;
    @ApiModelProperty("未检查大型机械设备总数")
    private Integer uninspectedMachineryTotal;
    @ApiModelProperty("大型机械设备统计列表")
    private List<MachineryStatisticsVO> machineryStatistics;
ruoyi-system/src/main/java/com/ruoyi/system/vo/ProjectMapPointVO.java
@@ -20,7 +20,7 @@
    @ApiModelProperty("项目名称")
    private String projectName;
    @ApiModelProperty("项目类型(0-房建,1-市政)")
    @ApiModelProperty("项目类型(0-房建,1-市政,2-固定资产)")
    private Integer projectType;
    @ApiModelProperty("项目类别(A类、B类、C类)")
ruoyi-system/src/main/java/com/ruoyi/system/vo/ProjectVo.java
@@ -52,6 +52,7 @@
    @ApiModelProperty("项目阶段")
    private String progress;
    @ApiModelProperty("设备列表")
    private List<DeviceCountVo> deviceCountVos;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenUserVo.java
@@ -17,6 +17,9 @@
    @ApiModelProperty(value = "项目权限")
    private String permissionProject;
    @ApiModelProperty(value = "1模糊评价  2打分评价")
    private Integer commentType=1;
    @ApiModelProperty(value = "1委托方 2项目")
    private Integer type;
}
ruoyi-system/src/main/resources/mapper/system/ProjectMapper.xml
@@ -30,7 +30,20 @@
            from task t1
            left join plan t2 on t1.plan_id = t2.id
            left join eval_result t3 on t1.id = t3.check_task_id
            where t1.project_id = #{projectId}
            where t1.project_id = #{query.projectId}
            <if test="query.planName != null and query.planName != ''">
                and t2.name like concat('%',#{query.planName},'%')
            </if>
            <if test="query.planType != null">
                and t2.type = #{query.planType}
            </if>
            <if test="query.startTime != null and query.startTime != ''">
                and t1.date >= #{query.startTime}
            </if>
            <if test="query.endTime != null and query.endTime != ''">
                and  #{query.endTime} >=t1.date
            </if>
            order by t1.date desc
ruoyi-system/src/main/resources/mapper/system/ScreenAccountMapper.xml
@@ -5,4 +5,10 @@
    <select id="getToken" resultType="java.lang.Long">
        select id from user_session where token = #{key} and `state`="ENABLED" limit 1
    </select>
    <select id="getLoginClient" resultType="com.ruoyi.system.vo.LoginNameVo">
        select id,name from client where id in <foreach collection="ids" separator="," item="id" close=")" open="(" >#{id}</foreach>
    </select>
    <select id="getLoginProject" resultType="com.ruoyi.system.vo.LoginNameVo">
        select id,name from project where id in <foreach collection="ids" separator="," item="id" close=")" open="(" >#{id}</foreach>
    </select>
</mapper>