TaskTempServiceImpl.java 9.45 KB
package vion.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.date.TimeUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.math.NumberUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.crypto.SecureUtil;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vion.dto.TaskTempDTO;
import vion.mapper.TaskTempMapper;
import vion.model.*;
import vion.service.IFileService;
import vion.service.ITaskTempService;
import vion.service.IUserService;
import vion.third.DingMod;
import vion.utils.JsonUtil;
import vion.vo.TaskTempVO;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class TaskTempServiceImpl extends MPJBaseServiceImpl<TaskTempMapper, TaskTemp> implements ITaskTempService {

    private final IFileService fileService;
    private final IUserService userService;
    private final DingMod dingMod;
    private final Converter converter;
    private final RedissonClient redissonClient;

    @Value("${fileUrl:}")
    private String fileUrl;

    @Override
    public Page<TaskTempVO> getTaskTempList(TaskTempDTO data) {
        var taskTempPage = this
                .lambdaQuery(converter.convert(data, TaskTemp.class))
                .between(ArrayUtil.isAllNotNull(data.getStartdate(), data.getEnddate()), TaskTemp::getRepairTime, data.getStartdate(), data.getEnddate())
                .page(Page.of(data.getPageNum(), data.getPageSize()));
        var taskTempVOList = converter.convert(taskTempPage.getRecords(), TaskTempVO.class);
        return Page.<TaskTempVO>of(taskTempPage.getCurrent(), taskTempPage.getSize(), taskTempPage.getTotal()).setRecords(taskTempVOList);
    }

    @Override
    public TaskTempVO getTaskTempById(Long id) {
        var wrapper = new MPJLambdaWrapper<TaskTemp>()
                .selectAll(TaskTemp.class)
                .selectCollection(FileInfo.class, TaskTempVO::getFileList)
                .leftJoin(FileInfo.class, on -> on
                        .eq(FileInfo::getSourceId, TaskTemp::getId)
                        .eq(FileInfo::getSourceType, 2L)
                        .eq(FileInfo::getStoreId, 0L))
                .eq(TaskTemp::getId, id);
        return Opt.ofNullable(this.selectJoinOne(TaskTempVO.class, wrapper))
                .ifPresent(taskTempVO -> {
                    Task task = Db.getOne(Wrappers.lambdaQuery(Task.class).eq(Task::getTaskTempId, id));
                    taskTempVO.setTask(task);
                })
                .orElse(null);
    }

    @Override
    public Object saveTaskTemp(TaskTempDTO data) {
        var taskTemp = converter.convert(data, TaskTemp.class);
        this.save(taskTemp);

        Opt.ofNullable(data.getFiles())
                .ifPresent(fileList ->
                        Arrays.stream(fileList).forEach(infile -> {
                            String orgName = infile.getOriginalFilename();
                            String mainName = FileNameUtil.mainName(orgName);
                            String fileExt = FileNameUtil.extName(orgName);
                            String filename = StrUtil.format("{}_{}.{}", mainName, TimeUtil.format(LocalDateTime.now(), "yyyyMMdd_HHmmssSSS"), fileExt);
                            String path = fileUrl + FileUtil.FILE_SEPARATOR + 0 + FileUtil.FILE_SEPARATOR + taskTemp.getId() + FileUtil.FILE_SEPARATOR + filename;
                            File file = FileUtil.touch(path);
                            try {
                                infile.transferTo(file);
                            } catch (IOException e) {
                                log.error("保存文件出错", e);
                            }

                            FileInfo fileInfo = new FileInfo();
                            fileInfo.setStoreId(0L);
                            fileInfo.setSourceId(taskTemp.getId());
                            fileInfo.setSourceType(2);
                            fileInfo.setName(filename);
                            fileInfo.setUrl(path);
                            fileInfo.setType(FileNameUtil.extName(file));
                            fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
                            fileInfo.setUploader(data.getRepairPeople());
                            fileService.save(fileInfo);
                        }));

        try {
            var bd = redissonClient.<TaskTemp>getBlockingDeque("task_temp_queue");
            var delayedQueue = redissonClient.getDelayedQueue(bd);
            delayedQueue.offer(taskTemp, 20, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("预工单添加延时队列出错,{}", e.getMessage());
        }

        var userList = userService.lambdaQuery().eq(User::getPreWorkOrder, 1).list();
        String userids = userList.stream().map(User::getUserid).collect(Collectors.joining(","));
        dingMod.workMsg(buildMsg(userids, taskTemp));

        return Map.of("id", taskTemp.getId());
    }

    @Override
    public Map<String, Long> getInfoByPhone(String phone) {
        if (StrUtil.isBlank(phone)) {
            return Map.of();
        }
        var wrapper = new MPJLambdaWrapper<TaskTemp>()
                .selectAs(TaskTemp::getStoreId, TaskTempVO::getStoreId)
                .selectAs(Store::getAccountId, TaskTempVO::getAccountId)
                .leftJoin(Store.class, Store::getId, TaskTemp::getStoreId)
                .eq(TaskTemp::getRepairPhone, phone)
                .orderByDesc(TaskTemp::getCreateTime);
        var voList = this.selectJoinList(TaskTempVO.class, wrapper);
        var filterList = voList.stream().filter(BeanUtil::isNotEmpty).collect(Collectors.toList());

        if (CollUtil.isNotEmpty(filterList) && filterList.size() > 1) {
            return Map.of("accountId", filterList.getFirst().getAccountId(), "storeId", filterList.getFirst().getStoreId());
        }
        return Map.of();
    }

    String buildMsg(String userid, TaskTemp taskTemp) {
        var jsonObj = JsonUtil.createObj()
                .put("agent_id", 2358374016L)
                .put("userid_list", userid);

        String template = """
                ### 客户提交工单提醒
                #### 门店信息: **{}**
                #### 客户姓名:{}
                #### 联系方式:{}
                #### 故障描述:{}
                #### 发送时间:{}
                """;
        String markdown = StrUtil.format(template,
                taskTemp.getStoreName(), taskTemp.getRepairPeople(), taskTemp.getRepairPhone(), taskTemp.getFaultDescription(), TimeUtil.formatNormal(LocalDateTime.now()));
        var content = JsonUtil.createObj()
                .put("title", "客户提交工单,请及时处理哦~_~")
                .put("markdown", markdown).put("btn_orientation", "1");

        var jsonArray = JsonUtil.createArr()
                .add(JsonUtil.createObj()
                        .put("title", "查看详情")
                        .put("action_url", "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingkrzwks0jpi2di3uo&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=https%3A%2F%2Fyunwei.vionyun.com%3A8443%2Fyunwei%2Fapi%2Fding%2Fcallback%2Finside%3FtaskTempId%3D" + taskTemp.getId()));
        content.set("btn_json_list", jsonArray);

        var msg = JsonUtil.createObj().put("msgtype", "action_card").set("action_card", content);
        jsonObj.set("msg", msg);
        return jsonObj.toString();
    }

    /**
     * 处理延时队列里的20分钟后未确认的工单,再次推送钉钉消息提醒
     */
    @PostConstruct
    void processTaskTempInQueue() {
        Thread.startVirtualThread(() -> {
            var bd = redissonClient.<TaskTemp>getBlockingDeque("task_temp_queue");
            var delayedQueue = redissonClient.getDelayedQueue(bd);
            while (true) {
                var taskTemp = bd.poll();
                if (ObjUtil.isNotNull(taskTemp)) {
                    var taskTempByDB = this.getById(taskTemp.getId());
                    if (ObjUtil.isNotNull(taskTempByDB) && NumberUtil.equals(taskTempByDB.getStatus(), 1)) {
                        var userids = userService.lambdaQuery()
                                .eq(User::getPreWorkOrder, 1)
                                .list().stream()
                                .map(User::getUserid)
                                .collect(Collectors.joining(","));
                        dingMod.workMsg(buildMsg(userids, taskTemp));

                        delayedQueue.offer(taskTemp, 20, TimeUnit.MINUTES);
                    }
                }
            }
        });
    }

}