QueryRoomsCmd.java 18.4 KB
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
package com.java110.community.cmd.room;

import com.alibaba.fastjson.JSONObject;
import com.java110.community.bmo.room.IQueryRoomStatisticsBMO;
import com.java110.core.annotation.Java110Cmd;
import com.java110.core.context.ICmdDataFlowContext;
import com.java110.core.event.cmd.Cmd;
import com.java110.core.event.cmd.CmdEvent;
import com.java110.doc.annotation.*;
import com.java110.dto.floor.FloorDto;
import com.java110.dto.room.RoomDto;
import com.java110.dto.unit.UnitDto;
import com.java110.dto.privilege.BasePrivilegeDto;
import com.java110.dto.data.DataPrivilegeStaffDto;
import com.java110.dto.owner.OwnerDto;
import com.java110.intf.community.*;
import com.java110.intf.user.IOwnerInnerServiceSMO;
import com.java110.intf.user.IOwnerRoomRelInnerServiceSMO;
import com.java110.utils.constant.ResponseConstant;
import com.java110.utils.exception.CmdException;
import com.java110.utils.exception.SMOException;
import com.java110.utils.util.*;
import com.java110.vo.api.ApiRoomDataVo;
import com.java110.vo.api.ApiRoomVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 房屋查询命令类
 * 负责处理房屋信息的查询请求,包括房屋基本信息、业主信息、权限控制等
 * 支持分页查询、条件筛选、数据权限控制等功能
 * 
 * @author 吴学文
 * @version 1.0
 * @since 2023
 */
@Java110CmdDoc(title = "查询房屋",
        description = "查询房屋信息",
        httpMethod = "get",
        url = "http://{ip}:{port}/app/room.queryRooms",
        resource = "communityDoc",
        author = "吴学文",
        serviceCode = "room.queryRooms",
        seq = 16
)

@Java110ParamsDoc(params = {
        @Java110ParamDoc(name = "page", type = "int", length = 11, remark = "页数"),
        @Java110ParamDoc(name = "row", type = "int", length = 11, remark = "行数"),
        @Java110ParamDoc(name = "communityId", length = 30, remark = "小区ID"),
        @Java110ParamDoc(name = "roomId", length = 30, remark = "房屋ID"),
        @Java110ParamDoc(name = "floorId", length = 30, remark = "楼栋ID"),
        @Java110ParamDoc(name = "unitId", length = 30, remark = "单元ID"),
})

@Java110ResponseDoc(
        params = {
                @Java110ParamDoc(name = "records", type = "int", length = 11, remark = "总页数"),
                @Java110ParamDoc(name = "total", type = "int", length = 11, remark = "总数据"),
                @Java110ParamDoc(name = "rooms", type = "Object", remark = "有效数据"),
                @Java110ParamDoc(parentNodeName = "rooms", name = "roomName", type = "String", remark = "房屋名称"),
                @Java110ParamDoc(parentNodeName = "rooms", name = "roomId", type = "String", remark = "房屋编号"),
        }
)

@Java110ExampleDoc(
        reqBody = "http://{ip}:{port}/app/room.queryRooms?floorId=&floorName=&unitId=&roomNum=&roomId=&state=&section=&roomType=1010301&roomSubType=&flag=0&page=1&row=10&communityId=2022081539020475",
        resBody = "{\"page\":0,\"records\":1,\"rooms\":[{\"apartment\":\"10101\",\"apartmentName\":\"一室一厅\",\"builtUpArea\":\"11.00\",\"endTime\":\"2037-01-01 00:00:00\",\"feeCoefficient\":\"1.00\",\"floorId\":\"732022081690440002\",\"floorNum\":\"D\",\"idCard\":\"\",\"layer\":\"1\",\"link\":\"18909711447\",\"ownerId\":\"772022082070860017\",\"ownerName\":\"张杰\",\"remark\":\"11\",\"roomArea\":\"11.00\",\"roomAttrDto\":[{\"attrId\":\"112022082081600012\",\"listShow\":\"Y\",\"page\":-1,\"records\":0,\"roomId\":\"752022082030880010\",\"row\":0,\"specCd\":\"9035007248\",\"specName\":\"精装修\",\"statusCd\":\"0\",\"total\":0,\"value\":\"20\",\"valueName\":\"20\"}],\"roomId\":\"752022082030880010\",\"roomName\":\"D-1-1001\",\"roomNum\":\"1001\",\"roomRent\":\"0.00\",\"roomSubType\":\"110\",\"roomSubTypeName\":\"住宅\",\"roomType\":\"1010301\",\"section\":\"1\",\"startTime\":\"2022-09-03 18:50:53\",\"state\":\"2001\",\"stateName\":\"已入住\",\"unitId\":\"742022082058950007\",\"unitNum\":\"1\"}],\"rows\":0,\"total\":2}"
)
@Java110Cmd(serviceCode = "room.queryRooms")
public class QueryRoomsCmd extends Cmd {

    @Autowired
    private IUnitInnerServiceSMO unitInnerServiceSMOImpl;

    @Autowired
    private IFloorInnerServiceSMO floorInnerServiceSMOImpl;

    @Autowired
    private IRoomInnerServiceSMO roomInnerServiceSMOImpl;

    @Autowired
    private IOwnerInnerServiceSMO ownerInnerServiceSMOImpl;

    @Autowired
    private IOwnerRoomRelInnerServiceSMO ownerRoomRelInnerServiceSMOImpl;

    @Autowired
    private IDataPrivilegeUnitV1InnerServiceSMO dataPrivilegeUnitV1InnerServiceSMOImpl;

    @Autowired
    private IMenuInnerServiceSMO menuInnerServiceSMOImpl;

    @Autowired
    private IQueryRoomStatisticsBMO queryRoomStatisticsBMOImpl;

    /** 最大查询行数限制 */
    protected static final int MAX_ROW = 10000;

    /**
     * 参数验证方法
     * 验证请求参数的合法性,包括必填项检查、分页参数验证、小区楼栋关系验证等
     *
     * @param event 命令事件
     * @param cmdDataFlowContext 命令数据流上下文
     * @param reqJson 请求参数JSON对象
     * @throws SMOException 当参数验证失败时抛出异常
     */
    @Override
    public void validate(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) {
        super.validateProperty(cmdDataFlowContext);
        // 验证必填参数communityId
        Assert.hasKeyAndValue(reqJson, "communityId", "请求中未包含communityId信息");
        //Assert.jsonObjectHaveKey(reqJson, "floorId", "请求中未包含floorId信息");
        super.validatePageInfo(reqJson);
        int row = Integer.parseInt(reqJson.getString("row"));

        // 验证行数是否超过最大限制
        if (row > MAX_ROW) {
            throw new SMOException(ResponseConstant.RESULT_CODE_ERROR, "row 数量不能大于50");
        }
        // 校验小区楼ID和小区是否有对应关系
        int total = floorInnerServiceSMOImpl.queryFloorsCount(BeanConvertUtil.covertBean(reqJson, FloorDto.class));

        // 如果传入了floorId但查询不到对应楼栋,说明楼栋ID不合法
        if (!StringUtil.isEmpty(reqJson.getString("floorId")) && total < 1) {
            throw new IllegalArgumentException("传入小区楼ID不是该小区的楼");
        }
    }

    /**
     * 执行房屋查询命令
     * 处理房屋查询业务逻辑,包括数据权限控制、房屋信息查询、业主信息关联等
     *
     * @param event 命令事件
     * @param cmdDataFlowContext 命令数据流上下文
     * @param reqJson 请求参数JSON对象
     * @throws CmdException 当命令执行失败时抛出异常
     */
    @Override
    public void doCmd(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) throws CmdException {
        // 将请求参数转换为RoomDto对象
        RoomDto roomDto = BeanConvertUtil.covertBean(reqJson, RoomDto.class);

        // 获取员工ID并查询数据权限
        String staffId = cmdDataFlowContext.getReqHeaders().get("user-id");
        DataPrivilegeStaffDto dataPrivilegeStaffDto = new DataPrivilegeStaffDto();
        dataPrivilegeStaffDto.setStaffId(staffId);
        // 查询员工有权限访问的单元ID列表
        String[] unitIds = dataPrivilegeUnitV1InnerServiceSMOImpl.queryDataPrivilegeUnitsByStaff(dataPrivilegeStaffDto);

        // 根据不同的查询模式计算房屋ID和单元ID
        computeRoomIdAndUnitId(reqJson, unitIds, roomDto);

        // 处理楼栋-单元-房屋编号格式的查询
        computeFloorUnitRoomNum(reqJson, roomDto);

        // 处理商铺类型的特殊查询格式
        computeRoomShopFloorUnitRoomNum(reqJson, roomDto);

        // 处理房屋状态参数,支持多状态查询
        String roomState = reqJson.getString("roomState");
        if (!StringUtil.isEmpty(roomState)) {
            roomDto.setStates(roomState.split(","));
        }

        ApiRoomVo apiRoomVo = new ApiRoomVo();

        // 如果员工有数据权限限制,设置可查询的单元ID列表
        if (unitIds != null && unitIds.length > 0) {
            roomDto.setUnitIds(unitIds);
        }
        // 查询总记录数
        int total = roomInnerServiceSMOImpl.queryRoomsCount(roomDto);
        apiRoomVo.setTotal(total);
        List<RoomDto> roomDtoList = null;
        if (total > 0) {
            // 查询房屋列表数据
            roomDtoList = roomInnerServiceSMOImpl.queryRooms(roomDto);
            // 刷新房屋业主信息
            refreshRoomOwners(reqJson.getString("loginUserId"), reqJson.getString("communityId"), roomDtoList);
            // 查询房屋统计数据
            roomDtoList = queryRoomStatisticsBMOImpl.query(roomDtoList);
        } else {
            roomDtoList = new ArrayList<>();
        }
        // 转换数据格式并设置返回结果
        apiRoomVo.setRooms(BeanConvertUtil.covertBeanList(roomDtoList, ApiRoomDataVo.class));
        int row = reqJson.getInteger("row");
        // 计算总页数
        apiRoomVo.setRecords((int) Math.ceil((double) total / (double) row));

        // 构建HTTP响应
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(JSONObject.toJSONString(apiRoomVo), HttpStatus.OK);
        cmdDataFlowContext.setResponseEntity(responseEntity);
    }

    /**
     * 处理商铺类型的房屋编号格式
     * 商铺的房屋编号格式为"楼层-房间号",需要特殊处理
     *
     * @param reqJson 请求参数JSON对象
     * @param roomDto 房屋数据传输对象
     */
    private static void computeRoomShopFloorUnitRoomNum(JSONObject reqJson, RoomDto roomDto) {
        // 如果不是商铺类型,直接返回
        if (!reqJson.containsKey("roomType") || !RoomDto.ROOM_TYPE_SHOPS.equals(reqJson.getString("roomType"))) {
            return;
        }
        // 如果没有房屋编号参数,清空相关字段
        if (!reqJson.containsKey("roomNum") || StringUtil.isEmpty(reqJson.getString("roomNum"))) {
            roomDto.setUnitNum("");
            roomDto.setFloorNum("");
            roomDto.setRoomNum("");
            return;
        }
        // 按"-"分割房屋编号,处理商铺格式
        String[] roomNums = reqJson.getString("roomNum").split("-", 2);
        if (roomNums != null && roomNums.length == 2) {
            // 商铺格式:楼层-房间号,单元号固定为0
            roomDto.setFloorNum(roomNums[0]);
            roomDto.setUnitNum("0");
            roomDto.setRoomNum(roomNums[1]);
        } else {
            roomDto.setRoomNum(reqJson.getString("roomNum"));
        }
    }

    /**
     * 计算楼栋单元房屋编号
     * 处理标准格式的房屋编号:楼栋号-单元号-房间号
     *
     * @param reqJson 请求参数JSON对象
     * @param roomDto 房屋数据传输对象
     */
    private static void computeFloorUnitRoomNum(JSONObject reqJson, RoomDto roomDto) {

        // 检查是否启用了编号解析模式
        if (!reqJson.containsKey("flag") || !"1".equals(reqJson.getString("flag"))) {
            return;
        }
        // 如果没有房屋编号,清空相关字段
        if (!reqJson.containsKey("roomNum") || StringUtil.isEmpty(reqJson.getString("roomNum"))) {
            roomDto.setUnitNum("");
            roomDto.setFloorNum("");
            roomDto.setRoomNum("");
            return;
        }
        // 按"-"分割房屋编号,处理标准格式
        String[] roomNums = reqJson.getString("roomNum").split("-", 3);
        if (roomNums != null && roomNums.length == 3) {
            // 标准格式:楼栋号-单元号-房间号
            roomDto.setFloorNum(roomNums[0]);
            roomDto.setUnitNum(roomNums[1]);
            roomDto.setRoomNum(roomNums[2]);
            return;
        }
        // 如果不是标准格式,直接使用原始房屋编号
        roomDto.setRoomNum(reqJson.getString("roomNum"));
    }

    /**
     * 根据楼栋号、单元号、房间号计算房屋ID和单元ID
     * 用于通过房屋位置信息反向查找房屋ID的场景
     *
     * @param reqJson 请求参数JSON对象
     * @param unitIds 员工有权限的单元ID数组
     * @param roomDto 房屋数据传输对象
     */
    private void computeRoomIdAndUnitId(JSONObject reqJson, String[] unitIds, RoomDto roomDto) {

        // 检查是否启用了ID计算模式
        if (!reqJson.containsKey("flag") || !"0".equals(reqJson.getString("flag"))) {
            return;
        }

        // 验证必要的参数是否存在
        if (!reqJson.containsKey("floorNum") || StringUtil.isEmpty(reqJson.getString("floorNum"))) {
            return;
        }

        if (!reqJson.containsKey("unitNum") || StringUtil.isEmpty(reqJson.getString("unitNum"))) {
            return;
        }

        if (!reqJson.containsKey("roomNum") || StringUtil.isEmpty(reqJson.getString("roomNum"))) {
            return;
        }

        // 根据楼栋号查询楼栋信息
        FloorDto floorDto = new FloorDto();
        floorDto.setFloorNum(reqJson.getString("floorNum"));
        floorDto.setCommunityId(reqJson.getString("communityId"));
        List<FloorDto> floorDtos = floorInnerServiceSMOImpl.queryFloors(floorDto);
        if (ListUtil.isNull(floorDtos)) {
            return;
        }

        String roomId = "";
        String unitId = "";
        List<UnitDto> unitDtos = null;
        // 遍历查询到的楼栋,查找对应的单元和房屋
        for (FloorDto floor : floorDtos) {
            UnitDto unitDto = new UnitDto();
            unitDto.setFloorId(floor.getFloorId());
            unitDto.setUnitNum(reqJson.getString("unitNum"));
            // 如果员工有权限限制,设置权限单元ID
            if (unitIds != null && unitIds.length > 0) {
                unitDto.setUnitIds(unitIds);
            }
            unitDtos = unitInnerServiceSMOImpl.queryUnits(unitDto);
            if (unitDtos == null || unitDtos.isEmpty()) {
                continue;
            }
            // 在找到的单元中查找对应的房屋
            for (UnitDto unit : unitDtos) {
                RoomDto room = new RoomDto();
                room.setUnitId(unit.getUnitId());
                room.setRoomNum(reqJson.getString("roomNum"));
                room.setCommunityId(reqJson.getString("communityId"));
                List<RoomDto> roomDtos = roomInnerServiceSMOImpl.queryRooms(room);
                if (roomDtos == null || roomDtos.isEmpty()) {
                    continue;
                }
                // 找到对应的房屋,记录ID信息
                unitId = roomDtos.get(0).getUnitId();
                roomId = roomDtos.get(0).getRoomId();
            }
        }
        // 设置查询到的房屋ID和单元ID
        roomDto.setRoomId(roomId);
        roomDto.setUnitId(unitId);
    }


    /**
     * 刷新房屋业主信息
     * 为房屋列表关联业主信息,并进行敏感信息脱敏处理
     *
     * @param userId 当前用户ID,用于权限检查
     * @param communityId 小区ID
     * @param roomDtos 房屋数据传输对象列表
     */
    private void refreshRoomOwners(String userId, String communityId, List<RoomDto> roomDtos) {

        /**
         * 性能优化:当房屋数量过多时,不查询业主信息
         * 避免大数据量查询导致的性能问题
         */
        if (roomDtos == null || roomDtos.size() > 20) {
            return;
        }
        // 收集所有房屋ID
        List<String> roomIds = new ArrayList<>();
        for (RoomDto roomDto : roomDtos) {
            roomIds.add(roomDto.getRoomId());
        }
        OwnerDto ownerDto = new OwnerDto();
        ownerDto.setCommunityId(communityId);
        ownerDto.setRoomIds(roomIds.toArray(new String[roomIds.size()]));
        // 检查用户是否有查看完整业主信息的权限
        List<Map> mark = getPrivilegeOwnerList("/roomCreateFee", userId);
        // 查询房屋对应的业主信息
        List<OwnerDto> ownerDtos = ownerInnerServiceSMOImpl.queryOwnersByRoom(ownerDto);
        // 为每个房屋关联业主信息
        for (RoomDto roomDto : roomDtos) {
            for (OwnerDto tmpOwnerDto : ownerDtos) {
                // 匹配房屋ID
                if (!roomDto.getRoomId().equals(tmpOwnerDto.getRoomId())) {
                    continue;
                }
                try {
                    // 转换时间格式
                    roomDto.setStartTime(DateUtil.getDateFromString(tmpOwnerDto.getStartTime(), DateUtil.DATE_FORMATE_STRING_A));
                    roomDto.setEndTime(DateUtil.getDateFromString(tmpOwnerDto.getEndTime(), DateUtil.DATE_FORMATE_STRING_A));
                } catch (Exception e) {
                    // 时间格式转换异常,忽略继续处理
                }
                // 设置业主基本信息
                roomDto.setOwnerId(tmpOwnerDto.getOwnerId());
                roomDto.setOwnerName(tmpOwnerDto.getName());
                // 对业主身份证号进行脱敏处理
                String idCard = tmpOwnerDto.getIdCard();
                // 如果没有查看完整信息的权限,进行脱敏
                if (mark.size() == 0 && idCard != null && !idCard.equals("") && idCard.length() > 15) {
                    idCard = idCard.substring(0, 6) + "**********" + idCard.substring(16);
                }
                // 对业主手机号进行脱敏处理
                String link = tmpOwnerDto.getLink();
                roomDto.setOwnerTel(link); // 程序内部使用完整手机号,用于统计查询
                if (mark.size() == 0 && link != null && !link.equals("") && link.length() > 10) {
                    link = link.substring(0, 3) + "****" + link.substring(7);
                }
                // 设置脱敏后的信息
                roomDto.setIdCard(idCard);
                roomDto.setLink(link);
            }
        }
    }

    /**
     * 检查用户对指定资源是否有权限
     * 用于敏感信息脱敏的权限控制
     *
     * @param resource 资源路径
     * @param userId 用户ID
     * @return 权限列表,如果有权限则返回非空列表
     */
    public List<Map> getPrivilegeOwnerList(String resource, String userId) {
        BasePrivilegeDto basePrivilegeDto = new BasePrivilegeDto();
        basePrivilegeDto.setResource(resource);
        basePrivilegeDto.setUserId(userId);
        // 查询用户对指定资源的权限
        List<Map> privileges = menuInnerServiceSMOImpl.checkUserHasResource(basePrivilegeDto);
        return privileges;
    }
}