MallServiceImpl.java 12.1 KB
package vion.service.impl.monitor;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.codec.MqttQoS;
import net.dreamlu.iot.mqtt.spring.client.MqttClientTemplate;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.text.StrUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vion.dto.monitor.MallDTO;
import vion.mapper.monitor.MallMapper;
import vion.model.monitor.*;
import vion.service.monitor.IEventRecordService;
import vion.service.monitor.IMAccountService;
import vion.service.monitor.IMallService;
import vion.service.monitor.IRAgentEventService;
import vion.utils.JsonUtil;
import vion.utils.TopicUtil;
import vion.vo.monitor.MallVO;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author vion
 * @date 2024/10/31
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MallServiceImpl extends MPJBaseServiceImpl<MallMapper, Mall> implements IMallService {

    private final IMAccountService accountService;
    private final IEventRecordService eventRecordService;
    private final IRAgentEventService agentEventService;
    private final MqttClientTemplate client;
    private final Converter converter;

    @Override
    public Page<MAccount> listAccount(MAccount dto) {
        return accountService.lambdaQuery(dto).page(Page.of(dto.getPageNum(), dto.getPageSize()));
    }

    @Override
    public Page<MAccount> listAttentionAccount(MAccount dto) {
        var attentionMallList = this.query().select("distinct account_uid").eq("attention", 1).list();
        return accountService.lambdaQuery()
                .in(MAccount::getUid, attentionMallList.stream().map(Mall::getAccountUid).toList())
                .orderByAsc(MAccount::getName)
                .page(Page.of(dto.getPageNum(), dto.getPageSize()));
    }

    @Override
    public Page<MallVO> list(MallDTO dto) {
        Assert.notNull(dto.getAgentType(), "agentType 不能为空");
        var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Mall.class))
                .selectAll(Mall.class)
                .selectAs(MAccount::getName, MallVO::getAccountName)
                .leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
                .orderByDesc(Mall::getUpdateTime);
        return this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), MallVO.class, wrapper);
    }

    @Override
    public MallVO get(Long id) {
        var wrapper = new MPJLambdaWrapper<Mall>()
                .selectAll(Mall.class)
                .selectAs(MAccount::getName, MallVO::getAccountName)
                .leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
                .eq(Mall::getId, id);
        return this.selectJoinOne(MallVO.class, wrapper);
    }

    @Override
    public Page<MallVO> listAttention(MallDTO dto) {
        Assert.notNull(dto.getAgentType(), "agentType 不能为空");
        if (CollUtil.isEmpty(dto.getEventUidList())) {
            var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Mall.class))
                    .selectAll(Mall.class)
                    .selectAs(MAccount::getName, MallVO::getAccountName)
                    .selectAs(Agent::getHostname, MallVO::getHostname)
                    .leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
                    .leftJoin(Agent.class, Agent::getUid, Mall::getAgentUid)
                    .eq(Mall::getAttention, 1)
                    .orderByDesc(Mall::getUid, Mall::getUpdateTime);
            var mallVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), MallVO.class, wrapper);
            Opt.ofEmptyAble(mallVOPage.getRecords())
                    .ifPresent(r -> {
                        var mallUidList = r.stream().map(MallVO::getUid).toList();
                        // fixme {@link EventServiceImpl #51}
                        var eventRecWrapper = Wrappers.<EventRecord>query()
                                .select("DISTINCT on (mall_uid,event_type) *")
                                .in("mall_uid", mallUidList)
                                .in(CollUtil.isNotEmpty(dto.getEventUidList()), "event_uid", dto.getEventUidList())
                                .orderByDesc("mall_uid", "event_type", "create_time");
                        var eventRecordList = eventRecordService.list(eventRecWrapper);
                        var mallUid2RecMap = eventRecordList.stream().collect(Collectors.groupingBy(EventRecord::getMallUid));

                        var agentEventList = agentEventService.lambdaQuery().in(RAgentEvent::getMallUid, mallUidList).list();
                        var mallUid2AgentEventMap = agentEventList.stream().collect(Collectors.groupingBy(RAgentEvent::getMallUid));

                        r.forEach(tmp -> {
                            tmp.setEventRecordList(mallUid2RecMap.getOrDefault(tmp.getUid(), List.of()));
                            tmp.setAgentEventList(mallUid2AgentEventMap.getOrDefault(tmp.getUid(), List.of()));
                        });
                    });
            return mallVOPage;
        } else {
            var agentEventWrapper = new MPJLambdaWrapper<RAgentEvent>()
                    .selectAll(RAgentEvent.class)
                    .leftJoin(Agent.class, Agent::getUid, RAgentEvent::getAgentUid)
                    .in(RAgentEvent::getEventUid, dto.getEventUidList())
                    .eq(Agent::getType, dto.getAgentType())
                    .orderByDesc(RAgentEvent::getCreateTime);
            var agentEventList = agentEventService.selectJoinList(RAgentEvent.class, agentEventWrapper);
            if (CollUtil.isEmpty(agentEventList)) {
                return new Page<>();
            }
            var mallUidList = agentEventList.stream().map(RAgentEvent::getMallUid).distinct().toList();
            var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Mall.class))
                    .selectAll(Mall.class)
                    .selectAs(MAccount::getName, MallVO::getAccountName)
                    .selectAs(Agent::getHostname, MallVO::getHostname)
                    .leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
                    .leftJoin(Agent.class, Agent::getUid, Mall::getAgentUid)
                    .eq(Mall::getAttention, 1)
                    .in(Mall::getUid, mallUidList)
                    .orderByDesc(Mall::getUid, Mall::getUpdateTime);
            var mallVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), MallVO.class, wrapper);
            Opt.ofEmptyAble(mallVOPage.getRecords())
                    .ifPresent(r -> {
                        var tmpMallUidList = r.stream().map(MallVO::getUid).toList();
                        // fixme {@link EventServiceImpl #51}
                        var eventRecWrapper = Wrappers.<EventRecord>query()
                                .select("DISTINCT on (mall_uid,event_type) *")
                                .in("mall_uid", tmpMallUidList)
                                .orderByDesc("mall_uid", "event_type", "create_time");
                        var eventRecordList = eventRecordService.list(eventRecWrapper);
                        var mallUid2RecMap = eventRecordList.stream().collect(Collectors.groupingBy(EventRecord::getMallUid));

                        var tmpAgentEventList = agentEventService.lambdaQuery().in(RAgentEvent::getMallUid, mallUidList).list();
                        var mallUid2AgentEventMap = tmpAgentEventList.stream().collect(Collectors.groupingBy(RAgentEvent::getMallUid));

                        r.forEach(tmp -> {
                            tmp.setEventRecordList(mallUid2RecMap.getOrDefault(tmp.getUid(), List.of()));
                            tmp.setAgentEventList(mallUid2AgentEventMap.getOrDefault(tmp.getUid(), List.of()));
                        });
                    });
            return mallVOPage;
        }
    }

    @Override
    public Page<MallVO> listErrorAttention(MallDTO dto) {
        var eventRecWrapper = Wrappers.<EventRecord>query()
                .select("DISTINCT on (mall_uid,event_type) *")
                .eq("agent_type", dto.getAgentType())
                .in(CollUtil.isNotEmpty(dto.getEventUidList()), "event_uid", dto.getEventUidList())
                .orderByDesc("mall_uid", "event_type", "create_time");
        var eventRecordList = eventRecordService.list(eventRecWrapper);
        var mallUidList = eventRecordList.stream().filter(r -> r.getStatus() == 0).map(EventRecord::getMallUid).toList();
        if (CollUtil.isEmpty(mallUidList)) {
            return new Page<>();
        }
        var agentEventList = agentEventService.lambdaQuery().in(RAgentEvent::getMallUid, mallUidList).list();
        var mallUid2AgentEventMap = agentEventList.stream().collect(Collectors.groupingBy(RAgentEvent::getMallUid));

        var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Mall.class))
                .selectAll(Mall.class)
                .selectAs(MAccount::getName, MallVO::getAccountName)
                .selectAs(Agent::getHostname, MallVO::getHostname)
                .leftJoin(MAccount.class, MAccount::getUid, Mall::getAccountUid)
                .leftJoin(Agent.class, Agent::getUid, Mall::getAgentUid)
                .in(Mall::getUid, mallUidList)
                .orderByDesc(Mall::getUid, Mall::getUpdateTime);
        var mallVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), MallVO.class, wrapper);
        Opt.ofEmptyAble(mallVOPage.getRecords())
                .ifPresent(r -> {
                    var tmpMallUidList = r.stream().map(MallVO::getUid).toList();

                    var tmpWrapper = Wrappers.<EventRecord>query()
                            .select("DISTINCT on (mall_uid,event_type) *")
                            .in("mall_uid", tmpMallUidList)
                            .orderByDesc("mall_uid", "event_type", "create_time");
                    var tmpEventRecordList = eventRecordService.list(tmpWrapper);
                    var tmpMallUid2RecMap = tmpEventRecordList.stream().collect(Collectors.groupingBy(EventRecord::getMallUid));
                    r.forEach(tmp -> {

                        tmp.setEventRecordList(tmpMallUid2RecMap.getOrDefault(tmp.getUid(), List.of()));
                        tmp.setAgentEventList(mallUid2AgentEventMap.getOrDefault(tmp.getUid(), List.of()));
                    });
                });
        return mallVOPage;
    }

    @Override
    public String attention(List<MallDTO> dtoList) {
        this.updateBatchById(converter.convert(dtoList, Mall.class));
        return "关注成功";
    }

    @Override
    public String attentionByAccount(String accountUid) {
        var mallList = this.lambdaQuery().eq(Mall::getAccountUid, accountUid).list();
        mallList.forEach(mall -> mall.setAttention((short) 1));
        this.updateBatchById(mallList);
        return "批量关注成功";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String cancelAttention(Long id) {
        var attentionMall = this.getById(id);
        this.lambdaUpdate().set(Mall::getAttention, 0).eq(Mall::getId, id).update(new Mall());
        var agentEventList = agentEventService.lambdaQuery().eq(RAgentEvent::getMallUid, attentionMall.getUid()).list();
        var topic = TopicUtil.getEventTopic(attentionMall.getAgentUid());
        if (StrUtil.isBlank(topic)) {
            var msg = StrUtil.format("agent:{} 获取topic失败", attentionMall.getAgentUid());
            log.error(msg);
            return msg;
        }
        agentEventList.forEach(agentEvent -> client.publish(topic, JsonUtil.toJsonByte(agentEvent), MqttQoS.QOS2));
        agentEventService.lambdaUpdate().eq(RAgentEvent::getMallUid, attentionMall.getUid()).remove();
        return "取消成功";
    }
}