TaskServiceImpl.java 12.9 KB
package vion.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vion.Global;
import vion.third.DingMod;
import vion.third.WechatMod;
import vion.dto.TaskDTO;
import vion.mapper.ServiceOrderMapper;
import vion.mapper.TaskMapper;
import vion.model.Dictionary;
import vion.model.*;
import vion.service.*;
import vion.vo.TaskVO;
import vion.vo.UserVO;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {

    private final ITaskTempService taskTempService;
    private final IFileService fileService;
    private final IFaultLogService faultLogService;
    private final IStoreService storeService;
    private final IUserService userService;
    private final IAccountService accountService;
    private final IDictionaryService dictionaryService;
    // 循环依赖,这里用mapper
    // private final IServiceOrderService serviceOrderService;
    private final ServiceOrderMapper serviceOrderMapper;
    private final DingMod dingMod;
    private final WechatMod wechatMod;
    private final Converter converter;
    @Value("${fileUrl:}")
    private String fileUrl;

    @Override
    public Page<TaskVO> getTaskList(TaskDTO data) {
        Page<Task> taskList = this
                .lambdaQuery(converter.convert(data, new Task()))
                .between(data.getStartdate() != null && data.getEnddate() != null, Task::getRepairTime, data.getStartdate(), data.getEnddate())
                .lt(data.getCurDate() != null, Task::getExpDate, data.getCurDate())
                .page(Page.of(data.getPageNum(), data.getPageSize()));

        // todo 是否加入缓存
        List<Store> storeList = storeService.list();
        List<Account> accountList = accountService.list();
        List<TaskVO> taskVOList = new ArrayList<>();
        Map<Long, ServiceOrder> taskId2OrderMap = Opt.ofEmptyAble(taskList.getRecords())
                .map(l -> l.stream().map(Task::getId).collect(Collectors.toList()))
                .map(idList -> serviceOrderMapper.selectList(Wrappers.<ServiceOrder>lambdaQuery().in(ServiceOrder::getTaskId, idList)))
                .map(serviceOrderList -> serviceOrderList.stream().collect(Collectors.toMap(ServiceOrder::getTaskId, Function.identity())))
                .orElse(MapUtil.empty());

        Opt.ofEmptyAble(taskList.getRecords())
                .ifPresent(l -> l.forEach(v -> {
                    TaskVO taskVO = converter.convert(v, TaskVO.class);
                    taskVO.setStoreName(storeList.stream().filter(s -> s.getId().equals(v.getStoreId())).map(Store::getName).findFirst().orElse("--"));
                    taskVO.setAccountName(accountList.stream().filter(a -> a.getId().equals(v.getAccountId())).map(Account::getName).findFirst().orElse("--"));
                    taskVO.setServiceOrder(taskId2OrderMap.get(v.getId()));
                    taskVOList.add(taskVO);
                }));
        return Page.<TaskVO>of(data.getPageNum(), data.getPageSize(), taskList.getTotal()).setRecords(taskVOList);
    }

    @Override
    public TaskVO getTaskById(Long taskId) {
        Task task = this.getById(taskId);
        List<FileInfo> fileInfos = fileService.list(Wrappers.<FileInfo>lambdaUpdate()
                .eq(FileInfo::getSourceId, task.getId())
                .eq(FileInfo::getStoreId, task.getStoreId()));
        TaskVO taskVO = converter.convert(task, TaskVO.class);
        taskVO.setFileList(fileInfos);
        return taskVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long circTask(TaskDTO data, String token) {
        UserVO user = Global.USERNAME_MAP.get(token);

        Task task = converter.convert(data, Task.class);
        if (task.getId() == null) {
            task.setCreateUser(user.getId());
        }

        // 可能直接提工单,而不是预工单确认之后生成的工单
        if (data.getTasktempId() != null) {
            taskTempService.lambdaUpdate()
                    .set(TaskTemp::getStatus, 3)
                    .set(TaskTemp::getOperator, data.getActiveUser())
                    .set(TaskTemp::getStoreId, data.getStoreId())
                    .eq(TaskTemp::getId, data.getTasktempId())
                    .update();

            //根据预处理工单更新附件的门店ID
            /*fileService.lambdaUpdate()
                    .set(FileInfo::getStoreId, data.getStoreId())
                    .eq(FileInfo::getSourceId, data.getId())
                    .update();*/
        }

        if (data.getId() == null) {
            //添加新工单
            task.setUuid(IdUtil.nanoId());
            task.setTaskTempId(data.getTasktempId());
            this.save(task);

            List<FaultLog> saveList = new ArrayList<>();
            // 预工单提交,客户名称不在系统用户表内
            FaultLog faultLog = new FaultLog();
            faultLog.setTaskId(task.getId());
            faultLog.setStoreId(task.getStoreId());
            faultLog.setOperator(-1L);
            faultLog.setContent(data.getRepairPeople() + "|提交工单");
            saveList.add(faultLog);

            //添加工单处理日志
            FaultLog faultLog1 = new FaultLog();
            faultLog1.setTaskId(task.getId());
            faultLog1.setStoreId(task.getStoreId());
            faultLog1.setOperator(user.getId());
            faultLog1.setContent("确认工单");
            faultLog1.setRemark(task.getRemark());
            saveList.add(faultLog1);
            faultLogService.saveBatch(saveList);
        } else {
            this.updateById(task);

            //根据状态判断是否要添加工单处理日志(状态:1待确认2进行中3已完成4挂起)
            FaultLog faultLog = new FaultLog();
            faultLog.setTaskId(task.getId());
            faultLog.setStoreId(task.getStoreId());
            faultLog.setOperator(user.getId());
            faultLog.setRemark(task.getRemark());
            if (task.getStatus() == 2) {
                faultLog.setContent("工单正在处理中");
            }
            if (task.getStatus() == 3) {
                faultLog.setContent("工单处理完成");
            }
            if (task.getStatus() == 4) {
                faultLog.setContent("工单挂起");
            }
            if (task.getStatus() == 5) {
                faultLog.setContent("工单已关闭");
            }
            faultLogService.save(faultLog);
        }
        // todo 异步发送钉钉消息通知
        Store store = storeService.getById(task.getStoreId());
        Task existTask = this.getById(task.getId());
        Long activeUserId = data.getActiveUser();
        User activeUser = userService.lambdaQuery().eq(User::getId, activeUserId).one();
        Set<String> useridList = new HashSet<>();
        useridList.add(activeUser.getUserid());
        if (task.getStatus() == 3) {
            // 工单完成时,推送钉钉消息到预工单的确认人
            Opt.ofNullable(existTask.getTaskTempId())
                    .map(taskTempId -> taskTempService.getById(taskTempId).getOperator())
                    .map(userService::getById)
                    .map(User::getUserid)
                    .ifPresent(useridList::add);
        }
        JSONObject msg = buildMsg(String.join(",", useridList), store.getName(), existTask);
        String pushRes = dingMod.sendMessage(msg);

        // todo 异步微信公众号消息推送
        if (task.getStatus() == 3) {
            Opt.ofNullable(existTask.getTaskTempId())
                    .map(taskTempId -> taskTempService.getById(taskTempId).getOpenid())
                    .ifPresent(openid -> {
                        Map<Integer, String> statusMap = MapUtil.<Integer, String>builder()
                                .put(1, "待确认")
                                .put(2, "进行中")
                                .put(3, "已完成")
                                .put(4, "挂起")
                                .build();
                        List<WxMpTemplateData> wxMpTemplateDataList = ListUtil.of(
                                new WxMpTemplateData("character_string1", existTask.getUuid()),
                                new WxMpTemplateData("thing7", DesensitizedUtil.chineseName(user.getUsername())),
                                new WxMpTemplateData("time4", DateUtil.formatDateTime(new Date())),
                                new WxMpTemplateData("const3", statusMap.get(existTask.getStatus())));
                        String sentMsg = wechatMod.sendMsg("ueJlVya7uOfYhFlIv28pC0kiHPe1b6Q-gkWsYKkoRWo", openid, wxMpTemplateDataList, null);
                    });
        }

        Opt.ofNullable(data.getFiles())
                .ifPresent(fileList ->
                        Arrays.stream(fileList).forEach(infile -> {
                            //上传url地址
                            String orgName = infile.getOriginalFilename();
                            String fileName = orgName.substring(0, orgName.lastIndexOf("."));
                            String fileExt = orgName.substring(orgName.lastIndexOf("."));
                            String filename = fileName + "_" + DateUtil.format(new Date(), "yyyyMMdd_HHmmss") + fileExt;
                            String path = fileUrl + FileUtil.FILE_SEPARATOR + data.getStoreId() + FileUtil.FILE_SEPARATOR + task.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(task.getStoreId());
                            fileInfo.setSourceId(task.getId());
                            fileInfo.setSourceType(3);
                            fileInfo.setName(filename);
                            fileInfo.setUrl(path);
                            fileInfo.setType(FileUtil.extName(file));
                            fileInfo.setSha256(SecureUtil.sha256(file).toUpperCase());
                            fileInfo.setUploader(user.getUsername());
                            fileService.save(fileInfo);
                        }));
        return task.getId();
    }

    JSONObject buildMsg(String userid, String storeName, Task task) {
        List<Dictionary> orderStatus = dictionaryService.list(Wrappers.<Dictionary>lambdaQuery().eq(Dictionary::getType, "order_status"));
        Map<Integer, String> orderStatusMap = orderStatus.stream().collect(Collectors.toMap(Dictionary::getKey, Dictionary::getValue));

        JSONObject jsonObj = new JSONObject();
        jsonObj.set("agent_id", 2358374016L);
        jsonObj.set("userid_list", userid);

        JSONObject msg = new JSONObject();
        JSONObject content = new JSONObject();
        content.set("title", "您有一条新工单请及时处理哦~_~");
        content.set("markdown", "门店信息: " + storeName + "[FullOfVitality]" +
                "  \n  报修人:" + task.getRepairPeople() +
                "  \n  联系方式:" + task.getRepairPhone() +
                "  \n  当前工单状态:" + orderStatusMap.get(task.getStatus()) +
                "  \n  故障描述:" + task.getFaultDescription() +
                "  \n  发送时间:" + DateUtil.now());
        content.set("btn_orientation", "1");

        JSONArray jsonArray = new JSONArray();
        jsonArray.add(new JSONObject().set("title", "查看详情").set("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%3FstoreId%3D" + task.getStoreId() + "%26taskId%3D" + task.getId()));
        content.set("btn_json_list", jsonArray);

        msg.set("msgtype", "action_card");
        msg.set("action_card", content);
        jsonObj.set("msg", msg);
        return jsonObj;
    }
}