feat(): 添加报警记录权限查询和APP端同步会议账号功能

dev^2
lishiwei 2026-07-24 17:02:02 +08:00
parent 154c41ec52
commit 892c736ea9
13 changed files with 328 additions and 51 deletions

View File

@ -6,6 +6,7 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.zcloud.gbscommon.utils.PageQueryHelper;
import com.zcloud.zcGbsServicer.api.AlarmRecordServiceI;
import com.zcloud.zcGbsServicer.command.convertor.AlarmRecordCoConvertor;
import com.zcloud.zcGbsServicer.dto.AlarmRecordAddCmd;
@ -16,6 +17,8 @@ import com.zcloud.zcGbsServicer.dto.clientobject.AlarmRecordCO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmInfoDO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeDO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireBrigadeUserDO;
import com.zcloud.zcGbsServicer.persistence.dataobject.AlarmUserScopeDO;
import com.zcloud.zcGbsServicer.persistence.repository.AlarmUserRepository;
import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmInfoRepository;
import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeRepository;
import com.zcloud.zcGbsServicer.persistence.repository.FireBrigadeUserRepository;
@ -42,33 +45,63 @@ public class AlarmRecordServiceImpl extends FireAlarmServiceSupport implements A
private static final int ALARM_STATUS_ALARMING = 1;
private static final int ALARM_STATUS_DISPOSING = 2;
private static final int ALARM_STATUS_CLEARED = 3;
private static final int USER_TYPE_SUPERVISE = 1;
private static final int USER_TYPE_ENTERPRISE = 2;
private static final int USER_TYPE_RELATED = 3;
/** 港务局用户-gwj特殊处理 */
private static final Long SPECIAL_SUPERVISE_USER_ID = 1976974388809424896L;
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final FireAlarmInfoRepository fireAlarmInfoRepository;
private final FireBrigadeRepository fireBrigadeRepository;
private final FireBrigadeUserRepository fireBrigadeUserRepository;
private final AlarmUserRepository alarmUserRepository;
private final AlarmRecordCoConvertor alarmRecordCoConvertor;
private final FireAlarmMeetingAccountService fireAlarmMeetingAccountService;
@Override
public PageResponse<AlarmRecordCO> listPage(AlarmRecordPageQry qry) {
Map<String, Object> params = new HashMap<>();
params.put("pageIndex", qry.getPageIndex());
params.put("pageSize", qry.getPageSize());
params.put("fireBrigadeName", qry.getTeam());
params.put("alarmStatus", parseStatus(qry.getStatus()));
params.put("feedbackOnly", Boolean.TRUE.equals(qry.getMyFeedbackOnly()));
if (Boolean.TRUE.equals(qry.getMyFeedbackOnly())) {
List<String> currentBrigadeIds = getCurrentUserBrigadeBizIds();
if (currentBrigadeIds.isEmpty()) {
return PageResponse.of(Collections.emptyList(), 0, qry.getPageSize(), qry.getPageIndex());
Map<String, Object> params = PageQueryHelper.toHashMap(qry);
String menuPath = qry == null ? null : qry.getMenuPath();
if (qry != null && StrUtil.isNotBlank(qry.getTeam())) {
params.put("fireBrigadeName", qry.getTeam().trim());
}
params.put("fireBrigadeIds", currentBrigadeIds);
Integer alarmStatus = parseStatus(qry == null ? null : qry.getStatus());
if (alarmStatus != null) {
params.put("alarmStatus", alarmStatus);
}
PageResponse<FireAlarmInfoDO> page = fireAlarmInfoRepository.listPage(params);
Long corpinfoId = resolveListCorpinfoId(qry);
if (corpinfoId != null) {
params.put("corpinfoId", corpinfoId);
}
PageResponse<FireAlarmInfoDO> page = fireAlarmInfoRepository.listPage(params, menuPath);
return PageResponse.of(page.getData().stream().map(this::buildCO).collect(Collectors.toList()),
page.getTotalCount(), page.getPageSize(), page.getPageIndex());
}
/**
* user_type12/3
*/
private Long resolveListCorpinfoId(AlarmRecordPageQry qry) {
Long userId = currentUserId();
if (SPECIAL_SUPERVISE_USER_ID.equals(userId)) {
return qry == null ? null : qry.getCorpinfoId();
}
AlarmUserScopeDO scope = alarmUserRepository.getScopeByUserId(userId);
Integer userType = scope == null ? null : scope.getUserType();
if (Integer.valueOf(USER_TYPE_SUPERVISE).equals(userType)) {
return qry == null ? null : qry.getCorpinfoId();
}
if (Integer.valueOf(USER_TYPE_ENTERPRISE).equals(userType)
|| Integer.valueOf(USER_TYPE_RELATED).equals(userType)) {
if (scope.getCorpinfoId() != null) {
return scope.getCorpinfoId();
}
throw new BizException("当前企业用户未配置所属企业,无法查询报警记录");
}
return qry == null ? null : qry.getCorpinfoId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public SingleResponse<AlarmRecordCO> add(AlarmRecordAddCmd cmd) {
@ -92,6 +125,18 @@ public class AlarmRecordServiceImpl extends FireAlarmServiceSupport implements A
record.setAlarmStatus(ALARM_STATUS_ALARMING);
record.setRecordTime(LocalDateTime.now());
fireAlarmInfoRepository.save(record);
if (Integer.valueOf(ALARM_MODE_APP).equals(record.getAlarmMode())) {
Long appUserId = record.getAlarmUserId() == null ? currentUserId() : record.getAlarmUserId();
if (appUserId == null) {
throw new BizException("APP报警人用户ID不能为空");
}
if (record.getAlarmUserId() == null) {
record.setAlarmUserId(appUserId);
fillUpdateAudit(record);
fireAlarmInfoRepository.updateById(record);
}
fireAlarmMeetingAccountService.ensureAppMeetingAccount(appUserId, record.getAlarmUserName(), record.getAlarmPhone());
}
return SingleResponse.of(buildCO(record));
}

View File

@ -0,0 +1,198 @@
package com.zcloud.zcGbsServicer.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.exception.BizException;
import com.zcloud.gbscommon.zclouduser.response.ZcloudUserCo;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingRoomDO;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmMeetingUserDO;
import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmMeetingRoomRepository;
import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmMeetingUserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
/**
* APP
*/
@Service
@RequiredArgsConstructor
public class FireAlarmMeetingAccountService extends FireAlarmServiceSupport {
private static final int MEETING_USER_TYPE_APP = 2;
private final FireAlarmMeetingUserRepository fireAlarmMeetingUserRepository;
private final FireAlarmMeetingRoomRepository fireAlarmMeetingRoomRepository;
private final HstVideoPlatformProperties hstVideoPlatformProperties;
private final HstVideoPlatformClient hstVideoPlatformClient;
private final FireAlarmUserResolver fireAlarmUserResolver;
@Transactional(rollbackFor = Exception.class)
public void ensureAppMeetingAccount(Long localUserId, String localUserName, String localPhone) {
if (localUserId == null) {
throw new BizException("报警人用户ID不能为空");
}
Long userTenantId = fireAlarmUserResolver.resolveUserTenantId(localUserId);
FireAlarmMeetingUserDO meetingUser = fireAlarmMeetingUserRepository.getByLocalUserId(localUserId, userTenantId);
if (meetingUser != null && StrUtil.isNotBlank(meetingUser.getThirdUserName())) {
boolean needUpdate = false;
if (StrUtil.isNotBlank(localUserName) && !localUserName.equals(meetingUser.getLocalUserName())) {
meetingUser.setLocalUserName(localUserName);
needUpdate = true;
}
if (StrUtil.isNotBlank(localPhone) && !localPhone.equals(meetingUser.getLocalPhone())) {
meetingUser.setLocalPhone(localPhone);
needUpdate = true;
}
if (needUpdate) {
fillUpdateAudit(meetingUser);
fireAlarmMeetingUserRepository.updateById(meetingUser);
}
return;
}
if (StrUtil.isBlank(hstVideoPlatformProperties.getDefaultUserPassword())) {
throw new BizException("视频平台默认用户密码未配置,不能创建会议账号");
}
ZcloudUserCo user = fireAlarmUserResolver.getUserMap(Collections.singleton(localUserId)).get(localUserId);
String resolvedName = selectText(localUserName, user == null ? null : user.getName());
String resolvedPhone = selectText(localPhone, user == null ? null : user.getPhone());
String thirdUserName = resolveThirdUserName(meetingUser, localUserId);
Map<String, Object> requestBody = new LinkedHashMap<>();
requestBody.put("userName", thirdUserName);
requestBody.put("password", hstVideoPlatformProperties.getDefaultUserPassword());
requestBody.put("passwordType", 0);
requestBody.put("mobile", resolvedPhone);
requestBody.put("nickName", selectText(resolvedName, thirdUserName));
requestBody.put("sex", "0");
requestBody.put("departId", StrUtil.blankToDefault(hstVideoPlatformProperties.getDefaultDepartId(), "0"));
requestBody.put("adminRole", 2);
Map<String, Object> data = new HashMap<>();
String syncMsg = "第三方账号创建成功";
try {
Map<String, Object> response = hstVideoPlatformClient.addUser(requestBody);
hstVideoPlatformClient.ensureSuccess(response, "创建视频平台用户");
data = castMap(response.get("data"));
syncMsg = selectText(asText(response.get("msg")), syncMsg);
}
catch (BizException ex) {
if (!isAlreadyExists(ex.getMessage())) {
throw new BizException("创建视频平台用户失败:" + ex.getMessage());
}
syncMsg = "第三方账号已存在,已复用";
}
boolean isNew = meetingUser == null;
if (meetingUser == null) {
meetingUser = new FireAlarmMeetingUserDO();
meetingUser.setId(nextId());
meetingUser.setFireAlarmMeetingUserId(nextBizId());
fillCreateAudit(meetingUser);
}
else {
fillUpdateAudit(meetingUser);
}
fireAlarmUserResolver.applyLocalUserTenant(meetingUser, localUserId);
FireAlarmMeetingRoomDO room = fireAlarmMeetingRoomRepository.getByRoomCode(hstVideoPlatformProperties.getDefaultRoomCode());
LocalDateTime now = LocalDateTime.now();
meetingUser.setLocalUserId(localUserId);
meetingUser.setLocalUserName(resolvedName);
meetingUser.setLocalPhone(resolvedPhone);
if (meetingUser.getUserType() == null) {
meetingUser.setUserType(MEETING_USER_TYPE_APP);
}
meetingUser.setThirdUserId(selectText(asText(data.get("userId")), meetingUser.getThirdUserId()));
meetingUser.setThirdUserName(selectText(asText(data.get("userName")), thirdUserName));
meetingUser.setThirdNickName(selectText(asText(data.get("displayName")), resolvedName));
meetingUser.setThirdDepartId(selectText(asText(data.get("departId")), hstVideoPlatformProperties.getDefaultDepartId()));
meetingUser.setAuthRoomId(room == null ? hstVideoPlatformProperties.getDefaultRoomNo()
: selectText(room.getThirdRoomId(), room.getThirdRoomNo()));
meetingUser.setAuthRoomName(room == null ? "消防报警固定会议室" : room.getRoomName());
meetingUser.setAuthStatus(1);
meetingUser.setAuthTime(now);
meetingUser.setSyncStatus(1);
meetingUser.setSyncMsg(syncMsg);
meetingUser.setLastSyncTime(now);
if (isNew) {
fireAlarmMeetingUserRepository.save(meetingUser);
}
else {
fireAlarmMeetingUserRepository.updateById(meetingUser);
}
syncRoomAuth(meetingUser.getThirdUserName(), 2);
}
private void syncRoomAuth(String thirdUserName, int permission) {
if (StrUtil.isBlank(thirdUserName)) {
return;
}
FireAlarmMeetingRoomDO room = fireAlarmMeetingRoomRepository.getByRoomCode(hstVideoPlatformProperties.getDefaultRoomCode());
String roomId = room == null ? hstVideoPlatformProperties.getDefaultRoomNo()
: selectText(room.getThirdRoomId(), room.getThirdRoomNo());
if (StrUtil.isBlank(roomId)) {
return;
}
Map<String, Object> requestBody = new LinkedHashMap<>();
requestBody.put("roomUserStr", roomId + "," + permission);
requestBody.put("userName", thirdUserName);
try {
Map<String, Object> response = hstVideoPlatformClient.authRoom(requestBody);
hstVideoPlatformClient.ensureSuccess(response, "用户授权会议室");
}
catch (BizException ex) {
throw new BizException("用户授权会议室失败:" + ex.getMessage());
}
}
private String resolveThirdUserName(FireAlarmMeetingUserDO meetingUser, Long localUserId) {
if (meetingUser != null && StrUtil.isNotBlank(meetingUser.getThirdUserName())) {
return meetingUser.getThirdUserName().trim();
}
String userName = StrUtil.blankToDefault(hstVideoPlatformProperties.getFireUserPrefix(), "xfbj") + localUserId;
if (userName.length() > 32) {
return userName.substring(0, 32);
}
return userName;
}
private boolean isAlreadyExists(String message) {
String msg = StrUtil.blankToDefault(message, "").toLowerCase(Locale.ROOT);
return msg.contains("存在") || msg.contains("exist") || msg.contains("duplicate");
}
@SuppressWarnings("unchecked")
private Map<String, Object> castMap(Object value) {
if (!(value instanceof Map)) {
return new HashMap<>();
}
return (Map<String, Object>) value;
}
private String asText(Object value) {
return value == null ? null : String.valueOf(value);
}
private String selectText(String preferred, String fallback) {
return StrUtil.isNotBlank(preferred) ? preferred : fallback;
}
private long nextId() {
return IdUtil.getSnowflake(1, 1).nextId();
}
private String nextBizId() {
return UUID.randomUUID().toString().replace("-", "");
}
}

View File

@ -13,6 +13,11 @@ public class AlarmRecordPageQry extends PageQuery {
@ApiModelProperty("报警状态")
private String status;
@ApiModelProperty("所属单位ID")
private Long corpinfoId;
@ApiModelProperty("是否只查询当前登录人所在消防队的处置数据") // 预留暂未使用
private Boolean myFeedbackOnly;
private String menuPath;
}

View File

@ -0,0 +1,13 @@
package com.zcloud.zcGbsServicer.persistence.dataobject;
import lombok.Data;
@Data
public class AlarmUserScopeDO {
/** 用户类型1监管 2企业 3相关方 */
private Integer userType;
/** 所属企业ID对应 fire_alarm_info.corpinfo_id */
private Long corpinfoId;
}

View File

@ -1,5 +1,6 @@
package com.zcloud.zcGbsServicer.persistence.mapper;
import com.zcloud.zcGbsServicer.persistence.dataobject.AlarmUserScopeDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -7,4 +8,6 @@ import org.apache.ibatis.annotations.Param;
public interface AlarmUserMapper {
Long selectTenantIdByUserId(@Param("userId") Long userId);
AlarmUserScopeDO selectScopeByUserId(@Param("userId") Long userId);
}

View File

@ -2,19 +2,21 @@ package com.zcloud.zcGbsServicer.persistence.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jjb.saas.framework.datascope.annotation.DataScope;
import com.jjb.saas.framework.datascope.annotation.DataScopes;
import com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmInfoDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@Mapper
@DataScopes({
@DataScope(method = "selectPageSql", menuPerms = "qyd-xfbjxxgl"),
})
public interface FireAlarmInfoMapper extends BaseMapper<FireAlarmInfoDO> {
IPage<FireAlarmInfoDO> selectPageSql(IPage<FireAlarmInfoDO> page,
@Param("tenantId") Long tenantId,
@Param("fireBrigadeName") String fireBrigadeName,
@Param("alarmStatus") Integer alarmStatus,
@Param("fireBrigadeIds") List<String> fireBrigadeIds,
@Param("feedbackOnly") Boolean corpinfoId);
IPage<FireAlarmInfoDO> selectPageSql(IPage<FireAlarmInfoDO> iPage,
@Param("params") Map<String, Object> params,
@Param("menuPath") String menuPath);
}

View File

@ -1,6 +1,10 @@
package com.zcloud.zcGbsServicer.persistence.repository;
import com.zcloud.zcGbsServicer.persistence.dataobject.AlarmUserScopeDO;
public interface AlarmUserRepository {
Long getTenantIdByUserId(Long userId);
AlarmUserScopeDO getScopeByUserId(Long userId);
}

View File

@ -8,7 +8,7 @@ import java.util.Map;
public interface FireAlarmInfoRepository extends BaseRepository<FireAlarmInfoDO> {
PageResponse<FireAlarmInfoDO> listPage(Map<String, Object> params);
PageResponse<FireAlarmInfoDO> listPage(Map<String, Object> params, String menuPath);
FireAlarmInfoDO getByFireAlarmInfoId(String fireAlarmInfoId);
}

View File

@ -1,5 +1,6 @@
package com.zcloud.zcGbsServicer.persistence.repository.impl;
import com.zcloud.zcGbsServicer.persistence.dataobject.AlarmUserScopeDO;
import com.zcloud.zcGbsServicer.persistence.mapper.AlarmUserMapper;
import com.zcloud.zcGbsServicer.persistence.repository.AlarmUserRepository;
import lombok.RequiredArgsConstructor;
@ -18,4 +19,12 @@ public class AlarmUserRepositoryImpl implements AlarmUserRepository {
}
return alarmUserMapper.selectTenantIdByUserId(userId);
}
@Override
public AlarmUserScopeDO getScopeByUserId(Long userId) {
if (userId == null) {
return null;
}
return alarmUserMapper.selectScopeByUserId(userId);
}
}

View File

@ -13,7 +13,6 @@ import com.zcloud.zcGbsServicer.persistence.repository.FireAlarmInfoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
@ -23,20 +22,9 @@ public class FireAlarmInfoRepositoryImpl extends BaseRepositoryImpl<FireAlarmInf
private final FireAlarmInfoMapper fireAlarmInfoMapper;
@Override
public PageResponse<FireAlarmInfoDO> listPage(Map<String, Object> params) {
public PageResponse<FireAlarmInfoDO> listPage(Map<String, Object> params, String menuPath) {
IPage<FireAlarmInfoDO> page = new Query<FireAlarmInfoDO>().getPage(params);
String fireBrigadeName = params == null ? null : (String) params.get("fireBrigadeName");
Integer alarmStatus = params == null ? null : (Integer) params.get("alarmStatus");
List<String> fireBrigadeIds = params == null ? null : (List<String>) params.get("fireBrigadeIds");
Boolean feedbackOnly = params == null ? null : (Boolean) params.get("feedbackOnly");
IPage<FireAlarmInfoDO> result = fireAlarmInfoMapper.selectPageSql(
page,
AuthContext.getTenantId(),
fireBrigadeName,
alarmStatus,
fireBrigadeIds,
feedbackOnly
);
IPage<FireAlarmInfoDO> result = fireAlarmInfoMapper.selectPageSql(page, params, menuPath);
return PageHelper.pageToResponse(result, result.getRecords());
}

View File

@ -185,6 +185,7 @@ CREATE TABLE `fire_brigade_user` (
`duty_name` varchar(128) DEFAULT NULL COMMENT '职务名称',
`corp_id` varchar(64) DEFAULT NULL COMMENT '机构ID',
`org_name` varchar(128) DEFAULT NULL COMMENT '机构名称',
`age` int DEFAULT NULL COMMENT '年龄',
`version` int DEFAULT NULL COMMENT '乐观锁',
`create_id` bigint DEFAULT NULL COMMENT '创建人ID',
`create_name` varchar(64) DEFAULT NULL COMMENT '创建人姓名',

View File

@ -11,4 +11,13 @@
LIMIT 1
</select>
<select id="selectScopeByUserId" resultType="com.zcloud.zcGbsServicer.persistence.dataobject.AlarmUserScopeDO">
SELECT
user_type AS userType,
corpinfo_id AS corpinfoId
FROM user
WHERE id = #{userId}
LIMIT 1
</select>
</mapper>

View File

@ -5,30 +5,30 @@
<mapper namespace="com.zcloud.zcGbsServicer.persistence.mapper.FireAlarmInfoMapper">
<select id="selectPageSql" resultType="com.zcloud.zcGbsServicer.persistence.dataobject.FireAlarmInfoDO">
SELECT *
FROM fire_alarm_info
SELECT fai.*
FROM fire_alarm_info fai
<where>
delete_enum = 'FALSE'
<if test="tenantId != null">
AND tenant_id = #{tenantId}
fai.delete_enum = 'FALSE'
<if test="params.fireBrigadeName != null and params.fireBrigadeName != ''">
AND fai.fire_brigade_name LIKE CONCAT('%', #{params.fireBrigadeName}, '%')
</if>
<if test="fireBrigadeName != null and fireBrigadeName != ''">
AND fire_brigade_name LIKE CONCAT('%', #{fireBrigadeName}, '%')
<if test="params.alarmStatus != null">
AND fai.alarm_status = #{params.alarmStatus}
</if>
<if test="alarmStatus != null">
AND alarm_status = #{alarmStatus}
<if test="params.alarmStatus == null and params.feedbackOnly != null and params.feedbackOnly">
AND fai.alarm_status IN (2, 3)
</if>
<if test="alarmStatus == null and feedbackOnly != null and feedbackOnly">
AND alarm_status IN (2, 3)
</if>
<if test="fireBrigadeIds != null and fireBrigadeIds.size() > 0">
AND fire_brigade_id IN
<foreach collection="fireBrigadeIds" item="item" open="(" separator="," close=")">
<if test="params.fireBrigadeIds != null and params.fireBrigadeIds.size() > 0">
AND fai.fire_brigade_id IN
<foreach collection="params.fireBrigadeIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="params.corpinfoId != null">
AND fai.corpinfo_id = #{params.corpinfoId}
</if>
</where>
ORDER BY record_time DESC, create_time DESC
ORDER BY fai.record_time DESC, fai.create_time DESC
</select>
</mapper>