From ec6d8a742dd301901d2e2eeabbf763129db3186b Mon Sep 17 00:00:00 2001 From: lishiwei <3230787218@qq.com> Date: Tue, 21 Jul 2026 18:02:57 +0800 Subject: [PATCH] =?UTF-8?q?feat():=201.=E8=A1=A5=E5=85=85APP=E6=8E=A5?= =?UTF-8?q?=E6=8A=A5=E6=96=B9=E5=BC=8F=202.=E4=BC=98=E5=8C=96=E6=B6=88?= =?UTF-8?q?=E9=98=B2=E9=98=9F=E4=BC=8D=E5=9C=A8=E7=BA=BF=E7=8A=B6=E6=80=81?= =?UTF-8?q?=203.=E8=A1=A5=E5=85=85=E6=B6=88=E8=AD=A6=E7=85=A7=E7=89=87?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=8A=9F=E8=83=BD=204.=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=88=90=E5=91=98=E7=A7=9F=E6=88=B7id=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=BF=87=E6=BB=A4=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start/src/main/resources/nacos-prod.yml | 5 + start/src/main/resources/nacos.yml | 5 + .../web/FireBrigadeController.java | 10 + .../web/FireBrigadeMemberController.java | 7 + .../FireBrigadeMemberCoConvertor.java | 6 + .../service/AlarmRecordServiceImpl.java | 35 ++- .../FireAlarmMeetingUserServiceImpl.java | 9 +- .../service/FireAlarmUserResolver.java | 22 ++ .../service/FireBrigadeMemberServiceImpl.java | 59 ++++- .../FireBrigadeOnlineStatusService.java | 203 +++++++++++++++--- .../service/FireBrigadeServiceImpl.java | 57 ++++- .../api/FireBrigadeMemberServiceI.java | 3 + .../api/FireBrigadeServiceI.java | 6 + .../zcGbsServicer/dto/AlarmRecordAddCmd.java | 3 + .../dto/FireBrigadeMemberAddCmd.java | 3 + .../dto/FireBrigadeOnlineStatusQry.java | 13 ++ .../dto/clientobject/FireBrigadeCO.java | 5 + .../dto/clientobject/FireBrigadeMemberCO.java | 16 +- .../FireBrigadeMemberStatusCO.java | 15 ++ .../FireBrigadeOnlineStatusCO.java | 18 ++ .../dataobject/FireAlarmInfoDO.java | 1 + .../persistence/mapper/AlarmUserMapper.java | 10 + .../repository/AlarmUserRepository.java | 6 + .../FireAlarmMeetingUserRepository.java | 11 +- .../repository/FireBrigadeRepository.java | 4 + .../repository/FireBrigadeUserRepository.java | 8 + .../impl/AlarmUserRepositoryImpl.java | 21 ++ .../FireAlarmMeetingUserRepositoryImpl.java | 33 ++- .../impl/FireBrigadeRepositoryImpl.java | 14 ++ .../impl/FireBrigadeUserRepositoryImpl.java | 35 +++ .../src/main/resources/fireAlarm.sql | 3 +- .../main/resources/mapper/AlarmUserMapper.xml | 14 ++ 32 files changed, 588 insertions(+), 72 deletions(-) create mode 100644 web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeOnlineStatusQry.java create mode 100644 web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberStatusCO.java create mode 100644 web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeOnlineStatusCO.java create mode 100644 web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/mapper/AlarmUserMapper.java create mode 100644 web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/AlarmUserRepository.java create mode 100644 web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/AlarmUserRepositoryImpl.java create mode 100644 web-infrastructure/src/main/resources/mapper/AlarmUserMapper.xml diff --git a/start/src/main/resources/nacos-prod.yml b/start/src/main/resources/nacos-prod.yml index 910e92d..99ef822 100644 --- a/start/src/main/resources/nacos-prod.yml +++ b/start/src/main/resources/nacos-prod.yml @@ -41,6 +41,11 @@ spring: username: nacos password: u9Hc7tLFBY +fire: + brigade: + online-cache-ttl-seconds: 20 + online-cache-fail-ttl-seconds: 10 + video: platform: hst: diff --git a/start/src/main/resources/nacos.yml b/start/src/main/resources/nacos.yml index cb376e5..a58657c 100644 --- a/start/src/main/resources/nacos.yml +++ b/start/src/main/resources/nacos.yml @@ -40,6 +40,11 @@ spring: server-addr: ${spring.cloud.nacos.config.server-addr} namespace: ${spring.cloud.nacos.config.namespace} +fire: + brigade: + online-cache-ttl-seconds: 20 + online-cache-fail-ttl-seconds: 10 + video: platform: hst: diff --git a/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeController.java b/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeController.java index 7d2999a..61c30a9 100644 --- a/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeController.java +++ b/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeController.java @@ -5,15 +5,19 @@ import com.alibaba.cola.dto.Response; import com.alibaba.cola.dto.SingleResponse; import com.zcloud.zcGbsServicer.api.FireBrigadeServiceI; import com.zcloud.zcGbsServicer.dto.FireBrigadeAddCmd; +import com.zcloud.zcGbsServicer.dto.FireBrigadeOnlineStatusQry; import com.zcloud.zcGbsServicer.dto.FireBrigadePageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeOnlineStatusCO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Api(tags = "消防队伍") @RestController @AllArgsConstructor @@ -28,6 +32,12 @@ public class FireBrigadeController { return fireBrigadeService.listPage(qry); } + @ApiOperation("批量刷新消防队伍在线状态缓存(供会议室等场景调用,可定时轮询)") + @PostMapping("/online/status") + public SingleResponse> onlineStatus(@RequestBody(required = false) FireBrigadeOnlineStatusQry qry) { + return fireBrigadeService.queryOnlineStatus(qry == null ? new FireBrigadeOnlineStatusQry() : qry); + } + @ApiOperation("新增") @PostMapping("/save") public SingleResponse save(@Validated @RequestBody FireBrigadeAddCmd cmd) { diff --git a/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeMemberController.java b/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeMemberController.java index 41e1807..f647e38 100644 --- a/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeMemberController.java +++ b/web-adapter/src/main/java/com/zcloud/zcGbsServicer/web/FireBrigadeMemberController.java @@ -8,6 +8,7 @@ import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberAddCmd; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberPageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberStatusCO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; @@ -22,6 +23,12 @@ public class FireBrigadeMemberController { private final FireBrigadeMemberServiceI fireBrigadeMemberService; + @ApiOperation("查询当前登录用户是否为消防队成员") + @GetMapping("/current/status") + public SingleResponse currentMemberStatus() { + return fireBrigadeMemberService.currentMemberStatus(); + } + @ApiOperation("分页查询") @PostMapping("/list") public PageResponse list(@RequestBody FireBrigadeMemberPageQry qry) { diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/command/convertor/FireBrigadeMemberCoConvertor.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/command/convertor/FireBrigadeMemberCoConvertor.java index 288ae31..08bef09 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/command/convertor/FireBrigadeMemberCoConvertor.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/command/convertor/FireBrigadeMemberCoConvertor.java @@ -12,9 +12,15 @@ public interface FireBrigadeMemberCoConvertor { @Mapping(target = "fireBrigadeId", ignore = true) @Mapping(source = "fireBrigadeId", target = "fireBrigadeBizId") + @Mapping(source = "userName", target = "name") + @Mapping(source = "dutyName", target = "duty") + @Mapping(source = "orgName", target = "org") List converDOsToCOs(List fireBrigadeUserDOs); @Mapping(target = "fireBrigadeId", ignore = true) @Mapping(source = "fireBrigadeId", target = "fireBrigadeBizId") + @Mapping(source = "userName", target = "name") + @Mapping(source = "dutyName", target = "duty") + @Mapping(source = "orgName", target = "org") FireBrigadeMemberCO converDOToCO(FireBrigadeUserDO fireBrigadeUserDO); } diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/AlarmRecordServiceImpl.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/AlarmRecordServiceImpl.java index 112462b..bcb5aad 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/AlarmRecordServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/AlarmRecordServiceImpl.java @@ -2,6 +2,7 @@ package com.zcloud.zcGbsServicer.service; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.alibaba.cola.dto.PageResponse; import com.alibaba.cola.dto.SingleResponse; import com.alibaba.cola.exception.BizException; @@ -78,7 +79,7 @@ public class AlarmRecordServiceImpl extends FireAlarmServiceSupport implements A record.setId(nextId()); record.setFireAlarmInfoId(nextBizId()); fillCreateAudit(record); - record.setAlarmMode(ALARM_MODE_PHONE); + record.setAlarmMode(resolveAlarmMode(cmd.getAlarmMode())); record.setAlarmUserId(cmd.getAlarmUserId()); record.setAlarmUserName(cmd.getReporter()); record.setAlarmPhone(cmd.getAlarmPhone()); @@ -138,6 +139,7 @@ public class AlarmRecordServiceImpl extends FireAlarmServiceSupport implements A throw new BizException("仅当前处置消防队成员可消警"); } record.setClearReason(cmd.getDesc().trim()); + record.setClearPhotos(toPhotoJson(cmd.getPhotos())); record.setClearId(currentUserId()); record.setClearName(currentUserName()); record.setClearTime(LocalDateTime.now()); @@ -186,10 +188,39 @@ public class AlarmRecordServiceImpl extends FireAlarmServiceSupport implements A co.setClearId(record.getClearId()); co.setClearName(record.getClearName()); co.setClearTime(formatTime(record.getClearTime())); - co.setPhotos(Collections.emptyList()); + co.setPhotos(parsePhotos(record.getClearPhotos())); return co; } + private String toPhotoJson(List photos) { + if (photos == null || photos.isEmpty()) { + return null; + } + List paths = photos.stream() + .filter(StrUtil::isNotBlank) + .map(String::trim) + .collect(Collectors.toList()); + return paths.isEmpty() ? null : JSONUtil.toJsonStr(paths); + } + + private List parsePhotos(String clearPhotos) { + if (StrUtil.isBlank(clearPhotos)) { + return Collections.emptyList(); + } + return JSONUtil.toList(clearPhotos, String.class); + } + + private Integer resolveAlarmMode(Integer alarmMode) { + if (alarmMode == null) { + return ALARM_MODE_PHONE; + } + if (!Integer.valueOf(ALARM_MODE_PHONE).equals(alarmMode) + && !Integer.valueOf(ALARM_MODE_APP).equals(alarmMode)) { + throw new BizException("接报方式无效"); + } + return alarmMode; + } + private Integer parseStatus(String status) { if (StrUtil.isBlank(status)) { return null; diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmMeetingUserServiceImpl.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmMeetingUserServiceImpl.java index e295a78..d95577d 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmMeetingUserServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmMeetingUserServiceImpl.java @@ -30,6 +30,7 @@ public class FireAlarmMeetingUserServiceImpl extends FireAlarmServiceSupport imp private final FireAlarmMeetingUserRepository fireAlarmMeetingUserRepository; private final FireBrigadeRepository fireBrigadeRepository; private final FireAlarmMeetingUserCoConvertor fireAlarmMeetingUserCoConvertor; + private final FireAlarmUserResolver fireAlarmUserResolver; @Override public PageResponse listPage(FireAlarmMeetingUserPageQry qry) { @@ -49,13 +50,15 @@ public class FireAlarmMeetingUserServiceImpl extends FireAlarmServiceSupport imp @Override @Transactional(rollbackFor = Exception.class) public SingleResponse add(FireAlarmMeetingUserAddCmd cmd) { - if (fireAlarmMeetingUserRepository.existsByLocalUserId(cmd.getLocalUserId(), null)) { + Long userTenantId = fireAlarmUserResolver.resolveUserTenantId(cmd.getLocalUserId()); + if (fireAlarmMeetingUserRepository.existsByLocalUserId(cmd.getLocalUserId(), userTenantId, null)) { throw new BizException("会议用户已存在"); } FireAlarmMeetingUserDO user = new FireAlarmMeetingUserDO(); user.setId(nextId()); user.setFireAlarmMeetingUserId(nextBizId()); fillCreateAudit(user); + fireAlarmUserResolver.applyLocalUserTenant(user, cmd.getLocalUserId()); fillMeetingUser(user, cmd); fireAlarmMeetingUserRepository.save(user); return SingleResponse.of(fireAlarmMeetingUserCoConvertor.converDOToCO(user)); @@ -68,10 +71,12 @@ public class FireAlarmMeetingUserServiceImpl extends FireAlarmServiceSupport imp if (user == null) { throw new BizException("会议用户不存在"); } - if (fireAlarmMeetingUserRepository.existsByLocalUserId(cmd.getLocalUserId(), cmd.getId())) { + if (fireAlarmMeetingUserRepository.existsByLocalUserId(cmd.getLocalUserId(), + fireAlarmUserResolver.resolveUserTenantId(cmd.getLocalUserId()), cmd.getId())) { throw new BizException("会议用户已存在"); } fillUpdateAudit(user); + fireAlarmUserResolver.applyLocalUserTenant(user, cmd.getLocalUserId()); fillMeetingUser(user, cmd); fireAlarmMeetingUserRepository.updateById(user); } diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmUserResolver.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmUserResolver.java index a005f5e..491c042 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmUserResolver.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireAlarmUserResolver.java @@ -1,8 +1,11 @@ package com.zcloud.zcGbsServicer.service; import com.alibaba.cola.dto.MultiResponse; +import com.jjb.saas.framework.repository.basedo.BaseDO; import com.zcloud.gbscommon.zclouduser.facade.ZcloudUserFacade; import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo; +import com.zcloud.zcGbsServicer.persistence.repository.AlarmUserRepository; +import lombok.RequiredArgsConstructor; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.stereotype.Component; @@ -12,11 +15,14 @@ import java.util.LinkedHashMap; import java.util.Map; @Component +@RequiredArgsConstructor public class FireAlarmUserResolver { @DubboReference(check = false) private ZcloudUserFacade zcloudUserFacade; + private final AlarmUserRepository alarmUserRepository; + public Map getUserMap(Collection userIds) { if (userIds == null || userIds.isEmpty()) { return Collections.emptyMap(); @@ -39,4 +45,20 @@ public class FireAlarmUserResolver { } return userMap; } + + /** + * 从 alarm 库 user 视图查询用户所属 tenant_id。 + */ + public Long resolveUserTenantId(Long userId) { + return alarmUserRepository.getTenantIdByUserId(userId); + } + + public void applyLocalUserTenant(BaseDO dataObject, Long localUserId) { + Long tenantId = resolveUserTenantId(localUserId); + if (tenantId == null) { + return; + } + dataObject.setTenantId(tenantId); + dataObject.setOrgId(tenantId); + } } diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeMemberServiceImpl.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeMemberServiceImpl.java index 59f3705..b3a60b4 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeMemberServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeMemberServiceImpl.java @@ -12,6 +12,7 @@ import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberAddCmd; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberPageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberStatusCO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingRoomDO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingUserDO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO; @@ -47,6 +48,20 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem private final FireAlarmUserResolver fireAlarmUserResolver; private final FireBrigadeMemberCoConvertor fireBrigadeMemberCoConvertor; + @Override + public SingleResponse currentMemberStatus() { + Long userId = currentUserId(); + FireBrigadeMemberStatusCO co = new FireBrigadeMemberStatusCO(); + co.setUserId(userId); + if (userId == null) { + co.setFireBrigadeMember(false); + return SingleResponse.of(co); + } + List relations = fireBrigadeUserRepository.listByUserId(userId); + co.setFireBrigadeMember(relations != null && !relations.isEmpty()); + return SingleResponse.of(co); + } + @Override public PageResponse listPage(FireBrigadeMemberPageQry qry) { FireBrigadeDO brigade = getBrigade(qry.getFireBrigadeId()); @@ -55,7 +70,7 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem List data = relations .stream() .map(item -> buildCO(item, brigade, userMap)) - .filter(item -> StrUtil.isBlank(qry.getName()) || StrUtil.containsIgnoreCase(item.getUserName(), qry.getName().trim())) + .filter(item -> StrUtil.isBlank(qry.getName()) || StrUtil.containsIgnoreCase(item.getName(), qry.getName().trim())) .collect(Collectors.toList()); int pageSize = qry.getPageSize() <= 0 ? data.size() : qry.getPageSize(); int pageIndex = qry.getPageIndex() <= 0 ? 1 : qry.getPageIndex(); @@ -75,6 +90,7 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem if (fireBrigadeUserRepository.existsRelation(brigade.getFireBrigadeId(), userId, null)) { throw new BizException("消防队员已存在"); } + prepareMemberRelation(userId, brigade.getFireBrigadeId(), null); FireBrigadeUserDO relation = new FireBrigadeUserDO(); relation.setId(nextId()); relation.setFireBrigadeUserId(nextBizId()); @@ -102,11 +118,13 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem if (fireBrigadeUserRepository.existsRelation(brigade.getFireBrigadeId(), userId, relation.getId())) { throw new BizException("消防队员已存在"); } + prepareMemberRelation(userId, brigade.getFireBrigadeId(), relation.getId()); relation.setFireBrigadeId(brigade.getFireBrigadeId()); relation.setUserId(userId); fillMemberSnapshot(relation, cmd); fillUpdateAudit(relation); fireBrigadeUserRepository.updateById(relation); + syncCreateMeetingUser(relation, brigade); } @Override @@ -179,11 +197,12 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem co.setUserId(relation.getUserId() == null ? null : String.valueOf(relation.getUserId())); co.setDutyId(relation.getDutyId()); co.setCorpId(relation.getCorpId()); - co.setUserName(selectText(user == null ? null : user.getName(), co.getUserName())); - co.setIdNo(selectText(user == null ? null : user.getUserIdCard(), co.getIdNo())); - co.setPhone(selectText(user == null ? null : user.getPhone(), co.getPhone())); - co.setDutyName(selectText(user == null ? null : user.getPostName(), co.getDutyName())); - co.setOrgName(selectText(user == null ? null : user.getDepartmentName(), co.getOrgName())); + co.setGender(relation.getGender()); + co.setName(selectText(relation.getUserName(), user == null ? null : user.getName())); + co.setIdNo(selectText(relation.getIdNo(), user == null ? null : user.getUserIdCard())); + co.setPhone(selectText(relation.getPhone(), user == null ? null : user.getPhone())); + co.setDuty(selectText(relation.getDutyName(), user == null ? null : user.getPostName())); + co.setOrg(selectText(relation.getOrgName(), user == null ? null : user.getDepartmentName())); if (brigade.getLeaderUserId() != null && brigade.getLeaderUserId().equals(relation.getUserId())) { co.setRoleCode(1); } @@ -201,6 +220,24 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem relation.setOrgName(cmd.getOrg()); } + /** + * 用户换队时软删除其他队伍的有效成员关系。 + */ + private void prepareMemberRelation(Long userId, String targetFireBrigadeId, Long currentRelationId) { + List activeRelations = fireBrigadeUserRepository.listByUserId(userId); + if (activeRelations == null) { + return; + } + for (FireBrigadeUserDO rel : activeRelations) { + if (currentRelationId != null && currentRelationId.equals(rel.getId())) { + continue; + } + if (!targetFireBrigadeId.equals(rel.getFireBrigadeId())) { + fireBrigadeUserRepository.removeById(rel.getId()); + } + } + } + private void syncCreateMeetingUser(FireBrigadeUserDO relation, FireBrigadeDO brigade) { if (StrUtil.isBlank(hstVideoPlatformProperties.getDefaultUserPassword())) { throw new BizException("视频平台默认用户密码未配置,不能创建消防会议账号"); @@ -237,7 +274,8 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem private void upsertMeetingUserMapping(FireBrigadeUserDO relation, FireBrigadeDO brigade, String thirdUserName, Map data, String syncMsg) { - FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(relation.getUserId()); + Long userTenantId = fireAlarmUserResolver.resolveUserTenantId(relation.getUserId()); + FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(relation.getUserId(), userTenantId); boolean isNew = meetingUser == null; if (meetingUser == null) { meetingUser = new FireAlarmMeetingUserDO(); @@ -248,6 +286,7 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem else { fillUpdateAudit(meetingUser); } + fireAlarmUserResolver.applyLocalUserTenant(meetingUser, relation.getUserId()); FireAlarmMeetingRoomDO room = fireAlarmMeetingRoomRepository.getByRoomCode(hstVideoPlatformProperties.getDefaultRoomCode()); LocalDateTime now = LocalDateTime.now(); @@ -306,7 +345,8 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem if (activeRelations != null && !activeRelations.isEmpty()) { return; } - FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(relation.getUserId()); + FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(relation.getUserId(), + fireAlarmUserResolver.resolveUserTenantId(relation.getUserId())); if (meetingUser == null) { return; } @@ -333,7 +373,8 @@ public class FireBrigadeMemberServiceImpl extends FireAlarmServiceSupport implem } private String resolveThirdUserName(Long localUserId) { - FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(localUserId); + FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(localUserId, + fireAlarmUserResolver.resolveUserTenantId(localUserId)); if (meetingUser != null && StrUtil.isNotBlank(meetingUser.getThirdUserName())) { return meetingUser.getThirdUserName().trim(); } diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeOnlineStatusService.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeOnlineStatusService.java index c55c0b0..07f7443 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeOnlineStatusService.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeOnlineStatusService.java @@ -1,6 +1,7 @@ package com.zcloud.zcGbsServicer.service; import cn.hutool.core.util.StrUtil; +import com.jjb.saas.framework.auth.utils.AuthContext; import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingUserDO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO; @@ -8,14 +9,19 @@ import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmMeetingUserRepos import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeUserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Slf4j @@ -24,29 +30,105 @@ import java.util.stream.Collectors; public class FireBrigadeOnlineStatusService { private static final int USER_ONLINE_IN_MEETING = 1; + private static final long REFRESH_DEBOUNCE_MS = 5000L; private final FireBrigadeUserRepository fireBrigadeUserRepository; private final FireAlarmMeetingUserRepository fireAlarmMeetingUserRepository; private final HstVideoPlatformClient hstVideoPlatformClient; - public Map calculateOnlineMap(List brigades) { + private final ConcurrentHashMap onlineCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap refreshGuard = new ConcurrentHashMap<>(); + + @Value("${fire.brigade.online-cache-ttl-seconds:20}") + private long onlineCacheTtlSeconds; + + @Value("${fire.brigade.online-cache-fail-ttl-seconds:10}") + private long onlineCacheFailTtlSeconds; + + /** + * 列表展示用:优先读有效缓存,其次读过期缓存,最后默认未在线;不调用第三方。 + */ + public Map getOnlineMapForList(Collection brigadeBizIds, Long tenantId) { + if (brigadeBizIds == null || brigadeBizIds.isEmpty()) { + return Collections.emptyMap(); + } + Map result = new LinkedHashMap<>(); + for (String brigadeBizId : brigadeBizIds) { + if (StrUtil.isBlank(brigadeBizId)) { + continue; + } + String normalizedId = brigadeBizId.trim(); + OnlineCacheEntry cacheEntry = onlineCache.get(buildCacheKey(normalizedId, tenantId)); + result.put(normalizedId, cacheEntry == null ? Boolean.FALSE : cacheEntry.online); + } + return result; + } + + /** + * 列表请求后异步刷新缓存,不阻塞接口响应。 + */ + public void scheduleRefreshOnlineMap(List brigades) { + if (brigades == null || brigades.isEmpty()) { + return; + } + Long tenantId = resolveTenantId(brigades); + if (isCacheValidForAll(brigades, tenantId)) { + return; + } + List snapshot = new ArrayList<>(brigades); + String refreshKey = buildRefreshKey(snapshot, tenantId); + long now = System.currentTimeMillis(); + Long lastRefreshAt = refreshGuard.get(refreshKey); + if (lastRefreshAt != null && now - lastRefreshAt < REFRESH_DEBOUNCE_MS) { + return; + } + refreshGuard.put(refreshKey, now); + CompletableFuture.runAsync(() -> { + try { + refreshOnlineMap(snapshot); + } + catch (Exception ex) { + log.warn("异步刷新消防队伍在线状态失败", ex); + } + }); + } + + /** + * 同步调用第三方刷新在线状态并写入缓存。 + */ + public Map refreshOnlineMap(List brigades) { if (brigades == null || brigades.isEmpty()) { return Collections.emptyMap(); } Set brigadeBizIds = brigades.stream() .map(FireBrigadeDO::getFireBrigadeId) .filter(StrUtil::isNotBlank) + .map(String::trim) .collect(Collectors.toCollection(LinkedHashSet::new)); if (brigadeBizIds.isEmpty()) { return Collections.emptyMap(); } - List allBrigadeUsers = fireBrigadeUserRepository.listAll(); - Map> brigadeUserMap = allBrigadeUsers.stream() - .filter(item -> item != null && brigadeBizIds.contains(item.getFireBrigadeId())) + Long tenantId = resolveTenantId(brigades); + long now = System.currentTimeMillis(); + OnlineComputeResult computeResult = computeOnlineMap(brigadeBizIds, tenantId); + long ttlMs = computeResult.degraded + ? onlineCacheFailTtlSeconds * 1000L + : onlineCacheTtlSeconds * 1000L; + long expireAt = now + ttlMs; + for (Map.Entry entry : computeResult.onlineMap.entrySet()) { + onlineCache.put(buildCacheKey(entry.getKey(), tenantId), new OnlineCacheEntry(entry.getValue(), expireAt)); + } + return computeResult.onlineMap; + } + + private OnlineComputeResult computeOnlineMap(Set brigadeBizIds, Long tenantId) { + List brigadeUsers = fireBrigadeUserRepository.listByFireBrigadeIds(brigadeBizIds, tenantId); + Map> brigadeUserMap = brigadeUsers.stream() + .filter(item -> item != null && StrUtil.isNotBlank(item.getFireBrigadeId())) .collect(Collectors.groupingBy(FireBrigadeUserDO::getFireBrigadeId, LinkedHashMap::new, Collectors.toList())); if (brigadeUserMap.isEmpty()) { - return buildOfflineMap(brigadeBizIds); + return new OnlineComputeResult(buildOfflineMap(brigadeBizIds), false); } Set localUserIds = brigadeUserMap.values().stream() @@ -55,47 +137,46 @@ public class FireBrigadeOnlineStatusService { .filter(java.util.Objects::nonNull) .collect(Collectors.toCollection(LinkedHashSet::new)); if (localUserIds.isEmpty()) { - return buildOfflineMap(brigadeBizIds); + return new OnlineComputeResult(buildOfflineMap(brigadeBizIds), false); } - Map meetingAccountMap = fireAlarmMeetingUserRepository.listAll().stream() + Map meetingAccountMap = fireAlarmMeetingUserRepository.listByLocalUserIds(localUserIds, tenantId).stream() .filter(item -> item != null && item.getLocalUserId() != null) - .filter(item -> localUserIds.contains(item.getLocalUserId())) .filter(item -> StrUtil.isNotBlank(item.getThirdUserName())) .collect(Collectors.toMap(FireAlarmMeetingUserDO::getLocalUserId, item -> item.getThirdUserName().trim(), (left, right) -> left, LinkedHashMap::new)); if (meetingAccountMap.isEmpty()) { - return buildOfflineMap(brigadeBizIds); + return new OnlineComputeResult(buildOfflineMap(brigadeBizIds), false); } - Set onlineMeetingAccounts = queryOnlineMeetingAccounts(new LinkedHashSet<>(meetingAccountMap.values())); + OnlineQueryResult queryResult = queryOnlineMeetingAccounts(new LinkedHashSet<>(meetingAccountMap.values())); Map result = buildOfflineMap(brigadeBizIds); - if (onlineMeetingAccounts.isEmpty()) { - return result; + if (!queryResult.onlineMeetingAccounts.isEmpty()) { + for (Map.Entry> entry : brigadeUserMap.entrySet()) { + boolean online = entry.getValue().stream() + .map(FireBrigadeUserDO::getUserId) + .filter(java.util.Objects::nonNull) + .map(meetingAccountMap::get) + .filter(StrUtil::isNotBlank) + .anyMatch(queryResult.onlineMeetingAccounts::contains); + result.put(entry.getKey(), online); + } } - - for (Map.Entry> entry : brigadeUserMap.entrySet()) { - boolean online = entry.getValue().stream() - .map(FireBrigadeUserDO::getUserId) - .filter(java.util.Objects::nonNull) - .map(meetingAccountMap::get) - .filter(StrUtil::isNotBlank) - .anyMatch(onlineMeetingAccounts::contains); - result.put(entry.getKey(), online); - } - return result; + return new OnlineComputeResult(result, queryResult.degraded); } - private Set queryOnlineMeetingAccounts(Set meetingAccounts) { + private OnlineQueryResult queryOnlineMeetingAccounts(Set meetingAccounts) { if (meetingAccounts == null || meetingAccounts.isEmpty()) { - return Collections.emptySet(); + return new OnlineQueryResult(Collections.emptySet(), false); } Set result = new LinkedHashSet<>(); boolean authInvalid = false; + boolean degraded = false; for (String meetingAccount : meetingAccounts) { if (authInvalid) { + degraded = true; break; } try { @@ -105,6 +186,7 @@ public class FireBrigadeOnlineStatusService { } } catch (Exception ex) { + degraded = true; if (isInvalidAuth(ex)) { authInvalid = true; log.warn("查询视频平台用户在线状态失败,视频平台 HTTP API 鉴权无效,请检查 key/secret 是否为后台 HTTP API 分配的凭证,当前账号={}", @@ -114,7 +196,46 @@ public class FireBrigadeOnlineStatusService { log.warn("查询视频平台用户在线状态失败,userName={}", meetingAccount, ex); } } - return result; + return new OnlineQueryResult(result, degraded); + } + + private Long resolveTenantId(List brigades) { + if (brigades != null) { + for (FireBrigadeDO brigade : brigades) { + if (brigade != null && brigade.getTenantId() != null) { + return brigade.getTenantId(); + } + } + } + return AuthContext.getTenantId(); + } + + private boolean isCacheValidForAll(List brigades, Long tenantId) { + long now = System.currentTimeMillis(); + for (FireBrigadeDO brigade : brigades) { + if (brigade == null || StrUtil.isBlank(brigade.getFireBrigadeId())) { + continue; + } + OnlineCacheEntry cacheEntry = onlineCache.get(buildCacheKey(brigade.getFireBrigadeId().trim(), tenantId)); + if (cacheEntry == null || cacheEntry.expireAt <= now) { + return false; + } + } + return true; + } + + private String buildCacheKey(String brigadeBizId, Long tenantId) { + return (tenantId == null ? "0" : tenantId) + ":" + brigadeBizId; + } + + private String buildRefreshKey(List brigades, Long tenantId) { + String ids = brigades.stream() + .map(FireBrigadeDO::getFireBrigadeId) + .filter(StrUtil::isNotBlank) + .map(String::trim) + .sorted() + .collect(Collectors.joining(",")); + return (tenantId == null ? "0" : tenantId) + ":" + ids; } private boolean isInvalidAuth(Exception ex) { @@ -172,4 +293,34 @@ public class FireBrigadeOnlineStatusService { } return result; } + + private static final class OnlineCacheEntry { + private final boolean online; + private final long expireAt; + + private OnlineCacheEntry(boolean online, long expireAt) { + this.online = online; + this.expireAt = expireAt; + } + } + + private static final class OnlineComputeResult { + private final Map onlineMap; + private final boolean degraded; + + private OnlineComputeResult(Map onlineMap, boolean degraded) { + this.onlineMap = onlineMap; + this.degraded = degraded; + } + } + + private static final class OnlineQueryResult { + private final Set onlineMeetingAccounts; + private final boolean degraded; + + private OnlineQueryResult(Set onlineMeetingAccounts, boolean degraded) { + this.onlineMeetingAccounts = onlineMeetingAccounts; + this.degraded = degraded; + } + } } diff --git a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeServiceImpl.java b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeServiceImpl.java index d6dcd7a..14c880a 100644 --- a/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/zcGbsServicer/service/FireBrigadeServiceImpl.java @@ -9,9 +9,11 @@ import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo; import com.zcloud.zcGbsServicer.api.FireBrigadeServiceI; import com.zcloud.zcGbsServicer.command.convertor.FireBrigadeCoConvertor; import com.zcloud.zcGbsServicer.dto.FireBrigadeAddCmd; +import com.zcloud.zcGbsServicer.dto.FireBrigadeOnlineStatusQry; import com.zcloud.zcGbsServicer.dto.FireBrigadePageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeOnlineStatusCO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO; import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeRepository; @@ -20,8 +22,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -46,13 +50,46 @@ public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements F params.put("brigadeName", qry.getName()); PageResponse page = fireBrigadeRepository.listPage(params); Map userMap = getLeaderUserMap(page.getData()); - Map onlineMap = fireBrigadeOnlineStatusService.calculateOnlineMap(page.getData()); - List data = page.getData().stream() - .map(item -> buildCO(item, userMap, onlineMap)) + List brigadeBizIds = page.getData().stream() + .map(FireBrigadeDO::getFireBrigadeId) + .filter(StrUtil::isNotBlank) .collect(Collectors.toList()); + Map memberCountMap = fireBrigadeUserRepository.countByFireBrigadeIds(brigadeBizIds); + Map onlineMap = fireBrigadeOnlineStatusService.getOnlineMapForList(brigadeBizIds, currentTenantId()); + List data = page.getData().stream() + .map(item -> buildCO(item, userMap, onlineMap, memberCountMap)) + .collect(Collectors.toList()); + fireBrigadeOnlineStatusService.scheduleRefreshOnlineMap(page.getData()); return PageResponse.of(data, page.getTotalCount(), page.getPageSize(), page.getPageIndex()); } + @Override + public SingleResponse> queryOnlineStatus(FireBrigadeOnlineStatusQry qry) { + List fireBrigadeIds = qry == null || qry.getFireBrigadeIds() == null + ? Collections.emptyList() + : new ArrayList<>(qry.getFireBrigadeIds().stream() + .filter(StrUtil::isNotBlank) + .map(String::trim) + .collect(Collectors.toCollection(LinkedHashSet::new))); + if (fireBrigadeIds.isEmpty()) { + return SingleResponse.of(Collections.emptyList()); + } + + List brigades = fireBrigadeRepository.listByFireBrigadeIds(fireBrigadeIds); + Map onlineMap = fireBrigadeOnlineStatusService.refreshOnlineMap(brigades); + List data = fireBrigadeIds.stream() + .map(fireBrigadeId -> { + FireBrigadeOnlineStatusCO co = new FireBrigadeOnlineStatusCO(); + co.setFireBrigadeId(fireBrigadeId); + boolean online = Boolean.TRUE.equals(onlineMap.get(fireBrigadeId)); + co.setOnline(online); + co.setOnlineText(online ? "在线" : "未在线"); + return co; + }) + .collect(Collectors.toList()); + return SingleResponse.of(data); + } + @Override @Transactional(rollbackFor = Exception.class) public SingleResponse add(FireBrigadeAddCmd cmd) { @@ -68,10 +105,11 @@ public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements F fillCreateAudit(brigade); fillBrigade(brigade, cmd); fireBrigadeRepository.save(brigade); - ensureLeaderRelation(brigade); + // ensureLeaderRelation(brigade); // 新增队伍时不再自动创建负责人成员记录,后续单独维护 return SingleResponse.of(buildCO(brigade, getLeaderUserMap(Collections.singletonList(brigade)), - fireBrigadeOnlineStatusService.calculateOnlineMap(Collections.singletonList(brigade)))); + fireBrigadeOnlineStatusService.refreshOnlineMap(Collections.singletonList(brigade)), + fireBrigadeUserRepository.countByFireBrigadeIds(Collections.singletonList(brigade.getFireBrigadeId())))); } @Override @@ -90,7 +128,7 @@ public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements F fillUpdateAudit(brigade); fillBrigade(brigade, cmd); fireBrigadeRepository.updateById(brigade); - ensureLeaderRelation(brigade); + // ensureLeaderRelation(brigade); // 编辑队伍时不再自动维护负责人成员记录,后续单独维护 } @Override @@ -101,7 +139,8 @@ public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements F } return buildCO(brigade, getLeaderUserMap(Collections.singletonList(brigade)), - fireBrigadeOnlineStatusService.calculateOnlineMap(Collections.singletonList(brigade))); + fireBrigadeOnlineStatusService.refreshOnlineMap(Collections.singletonList(brigade)), + fireBrigadeUserRepository.countByFireBrigadeIds(Collections.singletonList(brigade.getFireBrigadeId()))); } @Override @@ -166,13 +205,13 @@ public class FireBrigadeServiceImpl extends FireAlarmServiceSupport implements F } private FireBrigadeCO buildCO(FireBrigadeDO brigade, Map userMap, - Map onlineMap) { + Map onlineMap, Map memberCountMap) { FireBrigadeCO co = fireBrigadeCoConvertor.converDOToCO(brigade); ZcloudUserCo leader = brigade.getLeaderUserId() == null ? null : userMap.get(brigade.getLeaderUserId()); co.setLeaderDeptName(selectText(leader == null ? null : leader.getDepartmentName(), co.getLeaderDeptName())); co.setLeaderName(selectText(leader == null ? null : leader.getName(), co.getLeaderName())); co.setLeaderPhone(selectText(leader == null ? null : leader.getPhone(), co.getLeaderPhone())); - co.setMemberCount(fireBrigadeUserRepository.listByFireBrigadeId(brigade.getFireBrigadeId()).size()); + co.setMemberCount(memberCountMap == null ? 0 : memberCountMap.getOrDefault(brigade.getFireBrigadeId(), 0)); boolean online = onlineMap != null && Boolean.TRUE.equals(onlineMap.get(brigade.getFireBrigadeId())); co.setOnline(online); co.setOnlineText(online ? "在线" : "未在线"); diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeMemberServiceI.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeMemberServiceI.java index 8866803..c609660 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeMemberServiceI.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeMemberServiceI.java @@ -6,6 +6,7 @@ import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberAddCmd; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberPageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeMemberUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeMemberStatusCO; public interface FireBrigadeMemberServiceI { @@ -20,4 +21,6 @@ public interface FireBrigadeMemberServiceI { void remove(Long id); void removeBatch(Long[] ids); + + SingleResponse currentMemberStatus(); } diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeServiceI.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeServiceI.java index 944aeb6..b8bc765 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeServiceI.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/api/FireBrigadeServiceI.java @@ -3,14 +3,20 @@ package com.zcloud.zcGbsServicer.api; import com.alibaba.cola.dto.PageResponse; import com.alibaba.cola.dto.SingleResponse; import com.zcloud.zcGbsServicer.dto.FireBrigadeAddCmd; +import com.zcloud.zcGbsServicer.dto.FireBrigadeOnlineStatusQry; import com.zcloud.zcGbsServicer.dto.FireBrigadePageQry; import com.zcloud.zcGbsServicer.dto.FireBrigadeUpdateCmd; import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeCO; +import com.zcloud.zcGbsServicer.dto.clientobject.FireBrigadeOnlineStatusCO; + +import java.util.List; public interface FireBrigadeServiceI { PageResponse listPage(FireBrigadePageQry qry); + SingleResponse> queryOnlineStatus(FireBrigadeOnlineStatusQry qry); + SingleResponse add(FireBrigadeAddCmd cmd); void edit(FireBrigadeUpdateCmd cmd); diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/AlarmRecordAddCmd.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/AlarmRecordAddCmd.java index 3246e9d..fe9b2ad 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/AlarmRecordAddCmd.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/AlarmRecordAddCmd.java @@ -41,4 +41,7 @@ public class AlarmRecordAddCmd extends Command { @NotNull @ApiModelProperty("纬度") private Double lat; + + @ApiModelProperty("接报方式,1:电话接报,2:APP报警;不传默认1") + private Integer alarmMode; } diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeMemberAddCmd.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeMemberAddCmd.java index c7db54e..5a2fa51 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeMemberAddCmd.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeMemberAddCmd.java @@ -1,5 +1,6 @@ package com.zcloud.zcGbsServicer.dto; +import com.fasterxml.jackson.annotation.JsonAlias; import com.alibaba.cola.dto.Command; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -35,12 +36,14 @@ public class FireBrigadeMemberAddCmd extends Command { private String dutyId; @ApiModelProperty("职务名称") + @JsonAlias("dutyName") private String duty; @ApiModelProperty("机构ID") private String corpId; @ApiModelProperty("机构名称") + @JsonAlias("orgName") private String org; @ApiModelProperty("角色编码") diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeOnlineStatusQry.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeOnlineStatusQry.java new file mode 100644 index 0000000..cc113cc --- /dev/null +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/FireBrigadeOnlineStatusQry.java @@ -0,0 +1,13 @@ +package com.zcloud.zcGbsServicer.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class FireBrigadeOnlineStatusQry { + + @ApiModelProperty("消防队伍业务ID列表,取自列表接口 fireBrigadeId 字段;调用后会刷新在线状态缓存") + private List fireBrigadeIds; +} diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeCO.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeCO.java index 0ca3b0c..aecf211 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeCO.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeCO.java @@ -2,6 +2,7 @@ package com.zcloud.zcGbsServicer.dto.clientobject; import com.alibaba.cola.dto.ClientObject; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDate; @@ -37,6 +38,10 @@ public class FireBrigadeCO extends ClientObject { private String brigadeInfo; private Integer memberCount; + + @ApiModelProperty("是否在线,列表接口返回缓存值(首次默认未在线,后台异步刷新)") private Boolean online; + + @ApiModelProperty("在线状态文案") private String onlineText; } diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberCO.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberCO.java index 622d3bd..0d0e7ab 100644 --- a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberCO.java +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberCO.java @@ -1,7 +1,6 @@ package com.zcloud.zcGbsServicer.dto.clientobject; import com.alibaba.cola.dto.ClientObject; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data @@ -12,22 +11,13 @@ public class FireBrigadeMemberCO extends ClientObject { private Long fireBrigadeId; private String fireBrigadeBizId; private String userId; - - @JsonProperty("name") - private String userName; - + private String name; private String gender; private String idNo; private String phone; private String dutyId; - - @JsonProperty("duty") - private String dutyName; - + private String duty; private String corpId; - - @JsonProperty("org") - private String orgName; - + private String org; private Integer roleCode; } diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberStatusCO.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberStatusCO.java new file mode 100644 index 0000000..3065488 --- /dev/null +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeMemberStatusCO.java @@ -0,0 +1,15 @@ +package com.zcloud.zcGbsServicer.dto.clientobject; + +import com.alibaba.cola.dto.ClientObject; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class FireBrigadeMemberStatusCO extends ClientObject { + + @ApiModelProperty("当前登录用户ID") + private Long userId; + + @ApiModelProperty("是否为消防队成员") + private Boolean fireBrigadeMember; +} diff --git a/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeOnlineStatusCO.java b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeOnlineStatusCO.java new file mode 100644 index 0000000..05fc6e5 --- /dev/null +++ b/web-client/src/main/java/com/zcloud/zcGbsServicer/dto/clientobject/FireBrigadeOnlineStatusCO.java @@ -0,0 +1,18 @@ +package com.zcloud.zcGbsServicer.dto.clientobject; + +import com.alibaba.cola.dto.ClientObject; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class FireBrigadeOnlineStatusCO extends ClientObject { + + @ApiModelProperty("消防队伍业务ID") + private String fireBrigadeId; + + @ApiModelProperty("是否在线") + private Boolean online; + + @ApiModelProperty("在线状态文案") + private String onlineText; +} diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/dataobject/FireAlarmInfoDO.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/dataobject/FireAlarmInfoDO.java index 176ea20..098cc61 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/dataobject/FireAlarmInfoDO.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/dataobject/FireAlarmInfoDO.java @@ -35,6 +35,7 @@ public class FireAlarmInfoDO extends BaseDO { private Long clearId; private String clearName; private String clearReason; + private String clearPhotos; private String meetingRoomId; private String meetingRoomName; private Long meetingApplyUserId; diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/mapper/AlarmUserMapper.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/mapper/AlarmUserMapper.java new file mode 100644 index 0000000..444bef4 --- /dev/null +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/mapper/AlarmUserMapper.java @@ -0,0 +1,10 @@ +package com.zcloud.zcGbsServicer.persistence.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface AlarmUserMapper { + + Long selectTenantIdByUserId(@Param("userId") Long userId); +} diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/AlarmUserRepository.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/AlarmUserRepository.java new file mode 100644 index 0000000..6333c1c --- /dev/null +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/AlarmUserRepository.java @@ -0,0 +1,6 @@ +package com.zcloud.zcGbsServicer.persistence.repository; + +public interface AlarmUserRepository { + + Long getTenantIdByUserId(Long userId); +} diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireAlarmMeetingUserRepository.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireAlarmMeetingUserRepository.java index fcd496f..4dc2236 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireAlarmMeetingUserRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireAlarmMeetingUserRepository.java @@ -4,15 +4,16 @@ import com.alibaba.cola.dto.PageResponse; import com.jjb.saas.framework.repository.repo.BaseRepository; import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingUserDO; +import java.util.Collection; +import java.util.List; import java.util.Map; public interface FireAlarmMeetingUserRepository extends BaseRepository { PageResponse listPage(Map params); + boolean existsByLocalUserId(Long localUserId, Long tenantId, Long excludeId); + FireAlarmMeetingUserDO getByLocalUserId(Long localUserId, Long tenantId); + List listByLocalUserIds(Collection localUserIds, Long tenantId); - boolean existsByLocalUserId(Long localUserId, Long excludeId); - - FireAlarmMeetingUserDO getByLocalUserId(Long localUserId); - - java.util.List listAll(); + List listAll(); } diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeRepository.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeRepository.java index 617d4fb..4690a2c 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeRepository.java @@ -4,12 +4,16 @@ import com.alibaba.cola.dto.PageResponse; import com.jjb.saas.framework.repository.repo.BaseRepository; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO; +import java.util.Collection; +import java.util.List; import java.util.Map; public interface FireBrigadeRepository extends BaseRepository { PageResponse listPage(Map params); + List listByFireBrigadeIds(Collection fireBrigadeIds); + boolean existsByBrigadeName(String brigadeName, Long excludeId); FireBrigadeDO getByFireBrigadeId(String fireBrigadeId); diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeUserRepository.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeUserRepository.java index 1590b08..430ba8e 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeUserRepository.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/FireBrigadeUserRepository.java @@ -3,12 +3,20 @@ package com.zcloud.zcGbsServicer.persistence.repository; import com.jjb.saas.framework.repository.repo.BaseRepository; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO; +import java.util.Collection; import java.util.List; +import java.util.Map; public interface FireBrigadeUserRepository extends BaseRepository { List listAll(); + List listByFireBrigadeIds(Collection fireBrigadeIds); + + List listByFireBrigadeIds(Collection fireBrigadeIds, Long tenantId); + + Map countByFireBrigadeIds(Collection fireBrigadeIds); + List listByFireBrigadeId(String fireBrigadeId); List listByUserId(Long userId); diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/AlarmUserRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/AlarmUserRepositoryImpl.java new file mode 100644 index 0000000..196ae00 --- /dev/null +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/AlarmUserRepositoryImpl.java @@ -0,0 +1,21 @@ +package com.zcloud.zcGbsServicer.persistence.repository.impl; + +import com.zcloud.zcGbsServicer.persistence.mapper.AlarmUserMapper; +import com.zcloud.zcGbsServicer.persistence.repository.AlarmUserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AlarmUserRepositoryImpl implements AlarmUserRepository { + + private final AlarmUserMapper alarmUserMapper; + + @Override + public Long getTenantIdByUserId(Long userId) { + if (userId == null) { + return null; + } + return alarmUserMapper.selectTenantIdByUserId(userId); + } +} diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireAlarmMeetingUserRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireAlarmMeetingUserRepositoryImpl.java index 0a62145..b86b5d4 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireAlarmMeetingUserRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireAlarmMeetingUserRepositoryImpl.java @@ -15,6 +15,9 @@ import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmMeetingUserRepos import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; @Service @@ -57,13 +60,16 @@ public class FireAlarmMeetingUserRepositoryImpl extends BaseRepositoryImpl wrapper = new QueryWrapper<>(); wrapper.eq("local_user_id", localUserId).eq("delete_enum", "FALSE"); - if (AuthContext.getTenantId() != null) { + if (tenantId != null) { + wrapper.eq("tenant_id", tenantId); + } + else if (AuthContext.getTenantId() != null) { wrapper.eq("tenant_id", AuthContext.getTenantId()); } if (excludeId != null) { @@ -73,20 +79,37 @@ public class FireAlarmMeetingUserRepositoryImpl extends BaseRepositoryImpl wrapper = new QueryWrapper<>(); wrapper.eq("local_user_id", localUserId).eq("delete_enum", "FALSE").last("limit 1"); - if (AuthContext.getTenantId() != null) { + if (tenantId != null) { + wrapper.eq("tenant_id", tenantId); + } + else if (AuthContext.getTenantId() != null) { wrapper.eq("tenant_id", AuthContext.getTenantId()); } return this.getOne(wrapper); } @Override - public java.util.List listAll() { + public List listByLocalUserIds(Collection localUserIds, Long tenantId) { + if (localUserIds == null || localUserIds.isEmpty()) { + return Collections.emptyList(); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .in(FireAlarmMeetingUserDO::getLocalUserId, localUserIds) + .eq(FireAlarmMeetingUserDO::getDeleteEnum, "FALSE"); + if (tenantId != null) { + wrapper.eq(FireAlarmMeetingUserDO::getTenantId, tenantId); + } + return this.list(wrapper); + } + + @Override + public List listAll() { return this.list(new LambdaQueryWrapper() .eq(FireAlarmMeetingUserDO::getTenantId, AuthContext.getTenantId()) .eq(FireAlarmMeetingUserDO::getDeleteEnum, "FALSE")); diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeRepositoryImpl.java index ec89630..7edb786 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeRepositoryImpl.java @@ -14,6 +14,9 @@ import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Map; @Service @@ -30,6 +33,17 @@ public class FireBrigadeRepositoryImpl extends BaseRepositoryImpl listByFireBrigadeIds(Collection fireBrigadeIds) { + if (fireBrigadeIds == null || fireBrigadeIds.isEmpty()) { + return Collections.emptyList(); + } + return this.list(new LambdaQueryWrapper() + .in(FireBrigadeDO::getFireBrigadeId, fireBrigadeIds) + .eq(FireBrigadeDO::getTenantId, AuthContext.getTenantId()) + .eq(FireBrigadeDO::getDeleteEnum, "FALSE")); + } + @Override public boolean existsByBrigadeName(String brigadeName, Long excludeId) { if (StrUtil.isBlank(brigadeName)) { diff --git a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeUserRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeUserRepositoryImpl.java index 331c39b..950c8d7 100644 --- a/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeUserRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/zcGbsServicer/persistence/repository/impl/FireBrigadeUserRepositoryImpl.java @@ -6,10 +6,15 @@ import com.jjb.saas.framework.repository.repo.impl.BaseRepositoryImpl; import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO; import com.zcloud.zcGbsServicer.persistence.mapper.FireBrigadeUserMapper; import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeUserRepository; +import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -22,6 +27,36 @@ public class FireBrigadeUserRepositoryImpl extends BaseRepositoryImpl listByFireBrigadeIds(Collection fireBrigadeIds) { + return listByFireBrigadeIds(fireBrigadeIds, AuthContext.getTenantId()); + } + + @Override + public List listByFireBrigadeIds(Collection fireBrigadeIds, Long tenantId) { + if (fireBrigadeIds == null || fireBrigadeIds.isEmpty()) { + return Collections.emptyList(); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .in(FireBrigadeUserDO::getFireBrigadeId, fireBrigadeIds) + .eq(FireBrigadeUserDO::getDeleteEnum, "FALSE"); + if (tenantId != null) { + wrapper.eq(FireBrigadeUserDO::getTenantId, tenantId); + } + return this.list(wrapper); + } + + @Override + public Map countByFireBrigadeIds(Collection fireBrigadeIds) { + if (fireBrigadeIds == null || fireBrigadeIds.isEmpty()) { + return Collections.emptyMap(); + } + return listByFireBrigadeIds(fireBrigadeIds).stream() + .filter(item -> item != null && StrUtil.isNotBlank(item.getFireBrigadeId())) + .collect(Collectors.groupingBy(FireBrigadeUserDO::getFireBrigadeId, + Collectors.collectingAndThen(Collectors.counting(), Long::intValue))); + } + @Override public List listByFireBrigadeId(String fireBrigadeId) { return this.list(new LambdaQueryWrapper() diff --git a/web-infrastructure/src/main/resources/fireAlarm.sql b/web-infrastructure/src/main/resources/fireAlarm.sql index 3649c2c..4dcced1 100644 --- a/web-infrastructure/src/main/resources/fireAlarm.sql +++ b/web-infrastructure/src/main/resources/fireAlarm.sql @@ -94,6 +94,7 @@ CREATE TABLE `fire_alarm_info` ( `clear_id` bigint DEFAULT NULL COMMENT '消警人ID', `clear_name` varchar(64) DEFAULT NULL COMMENT '消警人姓名', `clear_reason` varchar(1000) DEFAULT NULL COMMENT '消警说明', + `clear_photos` varchar(2000) DEFAULT NULL COMMENT '消警现场照片路径,JSON数组', `meeting_room_id` varchar(64) DEFAULT NULL COMMENT '会议室ID', `meeting_room_name` varchar(128) DEFAULT NULL COMMENT '会议室名称', `meeting_apply_user_id` bigint DEFAULT NULL COMMENT '申请入会本地用户ID', @@ -197,7 +198,7 @@ CREATE TABLE `fire_brigade_user` ( `env` varchar(32) DEFAULT NULL COMMENT '环境', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_fire_brigade_user_id` (`fire_brigade_user_id`) USING BTREE, - UNIQUE KEY `uk_fire_brigade_user_rel` (`fire_brigade_id`,`user_id`) USING BTREE, + UNIQUE KEY `uk_fire_brigade_user_rel` (`fire_brigade_id`,`user_id`,`delete_enum`) USING BTREE, KEY `idx_fire_brigade_id` (`fire_brigade_id`) USING BTREE, KEY `idx_user_id` (`user_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='消防队伍人员表'; diff --git a/web-infrastructure/src/main/resources/mapper/AlarmUserMapper.xml b/web-infrastructure/src/main/resources/mapper/AlarmUserMapper.xml new file mode 100644 index 0000000..ab6daac --- /dev/null +++ b/web-infrastructure/src/main/resources/mapper/AlarmUserMapper.xml @@ -0,0 +1,14 @@ + + + + + + + +