liusheng
3 小时以前 18f876d637cf1e9b0b264a4586e4a676a21f8166
ruoyi-phone/src/main/java/com/ruoyi/phone/service/impl/PhoneServiceImpl.java
@@ -329,6 +329,8 @@
                            ServiceSubtask ss = new ServiceSubtask();
                            ss.setId(serviceSubtask.getId());
                            ss.setSendstate(6L);
                            //电话已答完(完成):状态与完成时间一起写,避免"已完成却无完成时间"
                            ss.setFinishtime(new Date());
                            taskSubtaskApi.updateSubtask(ss);
                            String date = simpleDateFormat1.format(new Date());
                            log.error("没有下一题了,就结束了: {},uuid为:{}", date, phoneCallBackVO.getUuid());
@@ -374,6 +376,8 @@
                        ServiceSubtask ss = new ServiceSubtask();
                        ss.setId(serviceSubtask.getId());
                        ss.setSendstate(6L);
                        //电话已答完(完成):状态与完成时间一起写,避免"已完成却无完成时间"
                        ss.setFinishtime(new Date());
                        taskSubtaskApi.updateSubtask(ss);
                        String date = simpleDateFormat1.format(new Date());
@@ -607,12 +611,21 @@
                //去redis中,把该子任务ID删除
                Long id = serviceSubtask.getId();
                //先更新一下分数
                //⚠️ 静默挂机 = 电话没接通 / 患者一直没应答,属于"未通",不是"完成":
                //   ① 不写 finishtime —— 这条单子接下来要交给补偿任务(setFailPreachForm 置 5 或 3,
                //      再由 compensateTask 捞起来继续发下一种方式 / 判超时);一旦写了完成时间,
                //      后面被置成"超时(7)"时就会留下"超时却有完成时间"的脏数据,
                //      及时率、完成率(ServiceSubtaskMapper#selectTimelyRateBatch 认 finishtime 非空)也会被虚高;
                //   ② 不整行回写 serviceSubtask —— 那会把上面刚写的 sendstate=5(电话静默)覆盖回查库时的旧值,
                //      所以这里只回写 id + 分数 + 更新时间,状态交给下面的 setFailPreachForm 决定
                //      (最后一种方式 → 5 发送失败;还有下一种 → 3 已发送,两者都会被补偿任务捞起来)。
                double score = redisCache.getCacheObject(phoneCallReqYQVO.getUuid() + "SCORE");
                serviceSubtask.setScore(String.valueOf(score));
                serviceSubtask.setFinishtime(new Date());
                serviceSubtask.setUpdateTime(new Date());
                log.error("先更新一下分数,电话的serviceSubtask的值为:{}", serviceSubtask);
                taskSubtaskApi.updateSubtask(serviceSubtask);
                ServiceSubtask scoreUpdate = new ServiceSubtask();
                scoreUpdate.setId(id);
                scoreUpdate.setScore(String.valueOf(score));
                scoreUpdate.setUpdateTime(new Date());
                log.error("先更新一下分数,电话的scoreUpdate的值为:{}", scoreUpdate);
                taskSubtaskApi.updateSubtask(scoreUpdate);
                //记录状态
                setFailPreachForm(serviceSubtask, "3", "静默次数达到" + num + "次", "4");
@@ -669,6 +682,8 @@
                        ss.setId(serviceSubtask.getId());
                        ss.setSendstate(6L);
                        ss.setRemark("电话拨打已完成");
                        //电话已答完(完成):状态与完成时间一起写,避免"已完成却无完成时间"
                        ss.setFinishtime(new Date());
                        taskSubtaskApi.updateSubtask(ss);
                        //记录状态
                        setFailPreachForm(serviceSubtask, "3", "电话拨打已完成", "9");
@@ -854,6 +869,8 @@
                                    ss.setId(serviceSubtask.getId());
                                    ss.setSendstate(6L);
                                    ss.setRemark("电话拨打已完成");
                                    //电话已答完(完成):状态与完成时间一起写,避免"已完成却无完成时间"
                                    ss.setFinishtime(new Date());
                                    taskSubtaskApi.updateSubtask(ss);
                                    //记录状态
                                    setFailPreachForm(serviceSubtask, "3", "电话拨打已完成", "9");
@@ -1566,12 +1583,13 @@
                serviceSubtask.setCurrentPreachform(preachform);
                serviceSubtask.setSendstate(5L);
                serviceSubtask.setRemark(remark + ";所有执行方式均未获取结果,任务失败");
                taskSubtaskApi.updateSubtask(serviceSubtask);
                //只回写本次要改的列(不再整行回写,避免把库里的旧 finishtime 等一起带回来)
                updateSubtaskState(serviceSubtask, 5L, preachform, serviceSubtask.getRemark(), null);
                return true;
            } else {
                //加入目前补偿里的 remark
                serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + remark : remark);
                taskSubtaskApi.updateSubtask(serviceSubtask);
                updateSubtaskState(serviceSubtask, null, null, serviceSubtask.getRemark(), null);
            }
        }
@@ -1581,8 +1599,35 @@
        //如果等于9,则说明电话正常结束了
        if (failSendstate.equals("9")) serviceSubtask.setSendstate(6L);
        serviceSubtask.setVisitTime(getNextVisitTime(serviceSubtask.getId(), serviceSubtask.getTaskid(), serviceSubtask.getVisitTime()));
        taskSubtaskApi.updateSubtask(serviceSubtask);
        updateSubtaskState(serviceSubtask, serviceSubtask.getSendstate(), preachform, null, serviceSubtask.getVisitTime());
        return true;
    }
    /**
     * 只回写本次真正要改的列(替代"整行回写 serviceSubtask")。
     * <p>
     * 为什么必须收窄:mapper 的 updateServiceSubtask 是&lt;if test="xx != null"&gt;动态 SET,
     * 整行回写会把库里已有的 finishtime / visit_time / score 等旧值原样再写一遍 —— 既可能覆盖
     * 并发写入,也是"状态 3/5/7 却带着完成时间"这类脏数据的搬运工。
     * <p>
     * 完成时间口径:sendstate=6(完成)时补完成时间;3 已发送 / 5 发送失败 / 7 超时等非完成状态
     * 一律不写,Mapper 侧的"完成时间不变量"会顺手把旧值清掉。
     */
    private void updateSubtaskState(ServiceSubtask source, Long sendstate, String currentPreachform,
                                    String remark, Date visitTime) {
        if (source == null || source.getId() == null) {
            return;
        }
        ServiceSubtask update = new ServiceSubtask();
        update.setId(source.getId());
        update.setSendstate(sendstate);
        update.setCurrentPreachform(currentPreachform);
        update.setRemark(remark);
        update.setVisitTime(visitTime);
        if (sendstate != null && sendstate == 6L) {
            update.setFinishtime(source.getFinishtime() != null ? source.getFinishtime() : new Date());
        }
        taskSubtaskApi.updateSubtask(update);
    }
    private Date getNextVisitTime(Long subid, Long taskid, Date visitTime) {
@@ -1893,6 +1938,8 @@
                    ss.setId(serviceSubtask.getId());
                    ss.setSendstate(6L);
                    ss.setRemark("电话拨打已完成");
                    //电话已答完(完成):状态与完成时间一起写,避免"已完成却无完成时间"
                    ss.setFinishtime(new Date());
                    taskSubtaskApi.updateSubtask(ss);
                    //记录状态
                    setFailPreachForm(serviceSubtask, "3", "电话拨打已完成", "9");