Compare commits

...
5 Commits
16 changed files with 325 additions and 138 deletions
+1
View File
@@ -0,0 +1 @@
99c37edcf8c5f147315f31bda0fe0628fcae6075fbd9193fb93d228d4aea1d2c
@@ -1,5 +1,6 @@
package com.ruoyi;
import java.util.TimeZone;
import com.ruoyi.common.utils.license.LicenseException;
import com.ruoyi.common.utils.license.LicenseUtils;
import org.springframework.boot.SpringApplication;
@@ -21,6 +22,8 @@ public class RuoYiApplication
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
// 统一将服务进程默认时区固定为北京时间,避免 Java 时间与数据库会话时间不一致。
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
ConfigurableApplicationContext application = SpringApplication.run(RuoYiApplication.class, args);
verifyLicense(application.getEnvironment());
@@ -30,9 +33,18 @@ public class RuoYiApplication
/**
* 校验 License 授权,校验失败则退出程序。
*
* <p>本地开发环境可通过 af.license.enabled=false 显式关闭校验,
* 避免调试阶段因为本机授权文件不匹配导致服务无法启动。
*/
private static void verifyLicense(Environment env)
{
boolean licenseEnabled = Boolean.parseBoolean(env.getProperty("af.license.enabled", "true"));
if (!licenseEnabled)
{
return;
}
String licensePath = env.getProperty("af.license.path");
if (licensePath == null || licensePath.trim().isEmpty())
{
@@ -13,6 +13,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.system.domain.af.AfDevice;
import com.ruoyi.system.domain.af.AfStatusConstants;
import com.ruoyi.system.service.af.IAfDeviceService;
/**
@@ -37,6 +38,8 @@ public class AfDeviceController extends BaseController
@GetMapping("/list")
public TableDataInfo list(AfDevice device)
{
// PC 设备管理列表只展示当前在线设备,避免离线设备干扰日常调度。
device.setOnlineStatus(AfStatusConstants.DEVICE_ONLINE);
startPage();
List<AfDevice> list = deviceService.selectAfDeviceList(device);
return getDataTable(list);
@@ -58,4 +61,20 @@ public class AfDeviceController extends BaseController
String maintainReason = Convert.toStr(body.get("maintainReason"));
return toAjax(deviceService.disableDispatch(deviceId, maintainReason, getUsername()));
}
/**
* PC 端调整设备工作状态,直接复用移动端相同的设备工作状态字段。
*
* @param body 请求体
* @return 更新后的设备
*/
@PreAuthorize("@ss.hasPermi('af:device:edit')")
@PostMapping("/work/status")
public AjaxResult updateWorkStatus(@RequestBody java.util.Map<String, Object> body)
{
String userName = Convert.toStr(body.get("userName"));
String deviceCode = Convert.toStr(body.get("deviceCode"));
String workStatus = Convert.toStr(body.get("workStatus"));
return success(deviceService.updateWorkStatus(userName, deviceCode, workStatus, getUsername()));
}
}
@@ -1,6 +1,5 @@
package com.ruoyi.web.controller.af;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@@ -10,10 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.system.domain.af.AfDispatchPolicy;
import com.ruoyi.system.service.af.IAfDispatchPolicyService;
import com.ruoyi.system.service.af.IAfDispatchService;
@RestController
@RequestMapping("/af/dispatch")
@@ -22,9 +19,6 @@ public class AfDispatchController extends BaseController
@Autowired
private IAfDispatchPolicyService dispatchPolicyService;
@Autowired
private IAfDispatchService dispatchService;
@PreAuthorize("@ss.hasPermi('af:order:dispatch')")
@GetMapping("/policy")
public AjaxResult getPolicy()
@@ -39,15 +33,4 @@ public class AfDispatchController extends BaseController
return success(dispatchPolicyService.savePolicy(policy, getUsername()));
}
@PreAuthorize("@ss.hasPermi('af:order:dispatch')")
@PostMapping("/trigger")
public AjaxResult trigger(@RequestBody(required = false) Map<String, Object> body)
{
Integer limit = body == null ? null : Convert.toInt(body.get("limit"));
String triggerType = body == null ? null : Convert.toStr(body.get("triggerType"));
Map<String, Object> triggerResult = dispatchService.triggerAutoDispatch(limit, triggerType, getUsername());
AjaxResult result = success();
result.putAll(triggerResult);
return result;
}
}
@@ -77,24 +77,6 @@ public class AfOrderController extends BaseController
return success(dispatchService.manualDispatch(orderId, deviceId, getUsername()));
}
/**
* 手动触发一轮自动分发。
*
* @param body 请求体
* @return 触发结果
*/
@PreAuthorize("@ss.hasPermi('af:order:dispatch')")
@PostMapping("/dispatch/auto")
public AjaxResult autoDispatch(@RequestBody(required = false) Map<String, Object> body)
{
Integer limit = body == null ? null : Convert.toInt(body.get("limit"));
String triggerType = body == null ? null : Convert.toStr(body.get("triggerType"));
Map<String, Object> triggerResult = dispatchService.triggerAutoDispatch(limit, triggerType, getUsername());
AjaxResult result = success();
result.putAll(triggerResult);
return result;
}
/**
* 取消订单。
*
@@ -111,17 +93,31 @@ public class AfOrderController extends BaseController
}
/**
* 重试订单。
* 人工标记订单完成。
*
* @param body 请求体
* @return 处理结果
*/
@PreAuthorize("@ss.hasPermi('af:order:retry')")
@PostMapping("/retry")
public AjaxResult retry(@RequestBody Map<String, Object> body)
@PreAuthorize("@ss.hasPermi('af:order:complete')")
@PostMapping("/complete")
public AjaxResult complete(@RequestBody Map<String, Object> body)
{
Long orderId = Convert.toLong(body.get("orderId"));
return toAjax(orderService.retryOrder(orderId, getUsername()));
return toAjax(orderService.completeOrder(orderId, getUsername()));
}
/**
* 人工重置订单状态为待分发。
*
* @param body 请求体
* @return 处理结果
*/
@PreAuthorize("@ss.hasPermi('af:order:reset')")
@PostMapping("/reset")
public AjaxResult reset(@RequestBody Map<String, Object> body)
{
Long orderId = Convert.toLong(body.get("orderId"));
return toAjax(orderService.resetOrder(orderId, getUsername()));
}
/**
@@ -17,9 +17,10 @@ spring:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
initialSize: 5
connectionInitSqls: SET time_zone = '+08:00'
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
@@ -58,4 +59,4 @@ spring:
merge-sql: true
wall:
config:
multi-statement-allow: true
multi-statement-allow: true
+17 -13
View File
@@ -46,9 +46,9 @@ user:
lockTime: 10
# Spring配置
spring:
# 资源信息
messages:
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
@@ -66,7 +66,7 @@ spring:
# 热部署开关
enabled: true
# redis 配置
redis:
redis:
# 地址
host: 38.76.220.172
# 端口,默认为6379
@@ -77,16 +77,19 @@ spring:
password: fenghp123456
# 连接超时时间
timeout: 10s
lettuce:
pool:
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
jackson:
time-zone: Asia/Shanghai
date-format: yyyy-MM-dd HH:mm:ss
# token配置
token:
@@ -127,10 +130,11 @@ referer:
allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip
# 自动充值业务配置
af:
license:
path: D:\license\license.lic
rechargeUrl: https://www.douyin.com/pay
af:
license:
enabled: false
path: /Users/fenghp/Desktop/DEV/project/autoFill/RuoYi-Vue/license.lic
rechargeUrl: https://www.douyin.com/pay
weidian:
wdToken: e96014f3
cookie: __spider__visitorid=884e5806506186bd; is_login=true; login_type=LOGIN_USER_TYPE_MASTER; login_source=LOGIN_USER_SOURCE_MASTER; uid=1774188581; duid=1774188581; sid=1619718241; smart_login_type=0; hi_dxh=; hold=; cn_merchant=; wdtoken=e96014f3; __spider__sessionid=d7756539bef26b5b; Hm_lvt_f3b91484e26c0d850ada494bff4b469b=1777446699,1778986671; HMACCOUNT=2383A5C40E664A02; login_token=_EwWqqVIQEKuI-Phw6hSEGFcEi9mlSZQq9CGPxfyUsL_A0Fnptw_8BdSEQvLn8r8oOo73sACMqrfJj3n0ichiWNcQwt0cS2Yxh1UgqGCs8bE5zqWBCXV2KZIxKzMApQbuf98L9hOdI1xlZH0pIJ6MT7WXbckhMUaS0juJhzzDpn1YnXxUAB9jy2G7fb2f15UK6_Thhr-eLwj54zYDhTghIixzfpTsmAVvlE_45xetReIESH7SYsHeO1JGiRIEey3yDnlo_-jJ; Hm_lpvt_f3b91484e26c0d850ada494bff4b469b=1778988001; cashier_token=558d8084586ea5a1ecf74c1d372296d5
@@ -3,22 +3,27 @@ package com.ruoyi.common.utils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.TimeZone;
import org.apache.commons.lang3.time.DateFormatUtils;
/**
* 时间工具类
*
* @author ruoyi
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
public static String YYYY = "yyyy";
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
private static final ZoneId BEIJING_ZONE_ID = ZoneId.of("Asia/Shanghai");
private static final TimeZone BEIJING_TIME_ZONE = TimeZone.getTimeZone(BEIJING_ZONE_ID);
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
@@ -38,10 +43,10 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
*
* @return Date() 当前日期
*/
public static Date getNowDate()
{
return new Date();
}
public static Date getNowDate()
{
return Date.from(ZonedDateTime.now(BEIJING_ZONE_ID).toInstant());
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
@@ -63,27 +68,31 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static final String dateTimeNow(final String format)
{
return parseDateToStr(format, new Date());
}
public static final String dateTimeNow(final String format)
{
return parseDateToStr(format, getNowDate());
}
public static final String dateTime(final Date date)
{
return parseDateToStr(YYYY_MM_DD, date);
}
public static final String parseDateToStr(final String format, final Date date)
{
return new SimpleDateFormat(format).format(date);
}
public static final String parseDateToStr(final String format, final Date date)
{
SimpleDateFormat formatter = new SimpleDateFormat(format);
formatter.setTimeZone(BEIJING_TIME_ZONE);
return formatter.format(date);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
return new SimpleDateFormat(format).parse(ts);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
SimpleDateFormat formatter = new SimpleDateFormat(format);
formatter.setTimeZone(BEIJING_TIME_ZONE);
return formatter.parse(ts);
}
catch (ParseException e)
{
throw new RuntimeException(e);
@@ -93,20 +102,20 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
public static final String datePath()
{
Date now = getNowDate();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* 日期路径 即年/月/日 如20180808
*/
public static final String dateTime()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
public static final String dateTime()
{
Date now = getNowDate();
return DateFormatUtils.format(now, "yyyyMMdd");
}
/**
* 日期型字符串转化为日期 格式
@@ -173,19 +182,19 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 增加 LocalDateTime ==> Date
*/
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(BEIJING_ZONE_ID);
return Date.from(zdt.toInstant());
}
/**
* 增加 LocalDate ==> Date
*/
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
}
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(BEIJING_ZONE_ID);
return Date.from(zdt.toInstant());
}
}
@@ -100,8 +100,8 @@ public class AfStatusConstants
/** 自动分发触发类型:定时扫描 */
public static final String DISPATCH_TRIGGER_CRON = "CRON";
/** 心跳超时分钟 */
public static final int HEARTBEAT_TIMEOUT_MINUTES = 2;
/** 心跳超时秒数 */
public static final int HEARTBEAT_TIMEOUT_SECONDS = 30;
/** 自动分发单次最大扫描数 */
public static final int AUTO_DISPATCH_LIMIT = 20;
@@ -191,11 +191,19 @@ public interface AfDeviceMapper
*/
public int countActiveTaskByDeviceId(@Param("deviceId") Long deviceId);
/**
* 查询心跳超时仍标记为在线的设备。
*
* @param timeoutSeconds 心跳超时秒数
* @return 设备列表
*/
public List<AfDevice> selectHeartbeatTimeoutOnlineList(@Param("timeoutSeconds") int timeoutSeconds);
/**
* 批量刷新离线状态
*
* @param timeoutMinutes 心跳超时分钟数
* @param timeoutSeconds 心跳超时秒数
* @return 结果
*/
public int refreshOfflineStatus(@Param("timeoutMinutes") int timeoutMinutes);
public int refreshOfflineStatus(@Param("timeoutSeconds") int timeoutSeconds);
}
@@ -38,13 +38,22 @@ public interface IAfOrderService
public int cancelOrder(Long orderId, String failReason, String operator);
/**
* 重试订单
* 人工标记订单完成
*
* @param orderId 订单ID
* @param operator 操作人
* @return 结果
*/
public int retryOrder(Long orderId, String operator);
public int completeOrder(Long orderId, String operator);
/**
* 人工重置订单为待分发
*
* @param orderId 订单ID
* @param operator 操作人
* @return 结果
*/
public int resetOrder(Long orderId, String operator);
/**
* 从微店拉取待充值订单并同步入库。
@@ -1,10 +1,14 @@
package com.ruoyi.system.service.af.impl;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -30,6 +34,9 @@ public class AfDeviceServiceImpl implements IAfDeviceService
@Autowired
private AfDispatchTaskMapper taskMapper;
@Autowired
private RedisCache redisCache;
@Lazy
@Autowired
private IAfDispatchService dispatchService;
@@ -347,6 +354,56 @@ public class AfDeviceServiceImpl implements IAfDeviceService
@Override
public void refreshOfflineStatus()
{
deviceMapper.refreshOfflineStatus(AfStatusConstants.HEARTBEAT_TIMEOUT_MINUTES);
List<AfDevice> timeoutDeviceList = deviceMapper.selectHeartbeatTimeoutOnlineList(AfStatusConstants.HEARTBEAT_TIMEOUT_SECONDS);
deviceMapper.refreshOfflineStatus(AfStatusConstants.HEARTBEAT_TIMEOUT_SECONDS);
clearLoginTokenByTimeoutDevice(timeoutDeviceList);
}
/**
* 心跳超时后主动清理该账号在线 token,避免离线设备继续持有登录态。
*
* @param timeoutDeviceList 超时设备列表
*/
private void clearLoginTokenByTimeoutDevice(List<AfDevice> timeoutDeviceList)
{
if (timeoutDeviceList == null || timeoutDeviceList.isEmpty())
{
return;
}
Collection<String> tokenKeys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
if (tokenKeys == null || tokenKeys.isEmpty())
{
return;
}
for (AfDevice device : timeoutDeviceList)
{
String userName = device.getUserName();
if (StringUtils.isEmpty(userName))
{
continue;
}
clearLoginTokenByUserName(tokenKeys, userName);
}
}
/**
* 按账号名清理在线 token,保证心跳超时后重新登录才能继续使用移动端。
*
* @param tokenKeys 在线 token key 集合
* @param userName 登录账号
*/
private void clearLoginTokenByUserName(Collection<String> tokenKeys, String userName)
{
for (String tokenKey : tokenKeys)
{
LoginUser loginUser = redisCache.getCacheObject(tokenKey);
if (loginUser == null || !StringUtils.equals(userName, loginUser.getUsername()))
{
continue;
}
redisCache.deleteObject(tokenKey);
}
}
}
@@ -7,6 +7,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.ruoyi.system.domain.af.AfDispatchPolicy;
import com.ruoyi.system.service.af.IAfDeviceService;
import com.ruoyi.system.service.af.IAfDispatchPolicyService;
import com.ruoyi.system.service.af.IAfDispatchService;
import com.ruoyi.system.service.af.IAfOrderService;
@@ -28,6 +29,9 @@ public class AfDispatchScheduler
@Autowired
private IAfOrderService orderService;
@Autowired
private IAfDeviceService deviceService;
@Scheduled(fixedDelay = 10000L, initialDelay = 15000L)
public void scanPendingOrders()
{
@@ -53,4 +57,20 @@ public class AfDispatchScheduler
}
dispatchService.triggerAutoDispatch(null, "CRON", "system");
}
/**
* 定时刷新超时设备的在线状态,避免无分发动作时设备一直停留在线。
*/
@Scheduled(fixedDelay = 10000L, initialDelay = 15000L)
public void refreshOfflineDevices()
{
try
{
deviceService.refreshOfflineStatus();
}
catch (Exception e)
{
log.error("定时刷新设备离线状态失败", e);
}
}
}
@@ -131,7 +131,7 @@ public class AfOrderServiceImpl implements IAfOrderService
}
/**
* 重试订单。
* 人工标记订单完成。
*
* @param orderId 订单ID
* @param operator 操作人
@@ -139,36 +139,95 @@ public class AfOrderServiceImpl implements IAfOrderService
*/
@Override
@Transactional
public int retryOrder(Long orderId, String operator)
public int completeOrder(Long orderId, String operator)
{
AfOrder order = orderMapper.selectAfOrderByIdForUpdate(orderId);
if (StringUtils.isNull(order))
{
throw new ServiceException("订单不存在");
}
if (!StringUtils.equalsAny(order.getStatus(), AfStatusConstants.ORDER_FAILED, AfStatusConstants.ORDER_CANCELLED))
if (StringUtils.equals(order.getStatus(), AfStatusConstants.ORDER_CANCELLED))
{
throw new ServiceException("只有失败或取消订单支持重试");
throw new ServiceException("已取消订单不允许标记完成");
}
Long oldTaskId = order.getCurrentTaskId();
orderMapper.resetOrderToPending(orderId, operator);
if (oldTaskId != null)
{
AfDispatchTask task = taskMapper.selectAfDispatchTaskByIdForUpdate(oldTaskId);
if (StringUtils.isNotNull(task) && task.getDeviceId() != null)
{
deviceMapper.updateDeviceToIdle(task.getDeviceId(), oldTaskId, operator);
}
}
dispatchService.onOrderPending(orderId);
orderMapper.updateOrderStatusById(orderId, AfStatusConstants.ORDER_SUCCESS, null, operator);
releaseCurrentTask(order, AfStatusConstants.TASK_SUCCESS, null, operator);
deliverOrderIfNeed(order, operator);
return 1;
}
/**
* 人工重置订单为待分发。
*
* @param orderId 订单ID
* @param operator 操作人
* @return 结果
*/
@Override
@Transactional
public int resetOrder(Long orderId, String operator)
{
AfOrder order = orderMapper.selectAfOrderByIdForUpdate(orderId);
if (StringUtils.isNull(order))
{
throw new ServiceException("订单不存在");
}
if (StringUtils.equals(order.getStatus(), AfStatusConstants.ORDER_SUCCESS))
{
throw new ServiceException("已完成订单不允许重置");
}
orderMapper.resetOrderToPending(orderId, operator);
releaseCurrentTask(order, AfStatusConstants.TASK_CANCELLED, "人工重置订单状态", operator);
return 1;
}
/**
* 人工改订单状态后释放当前任务和设备占用。
*
* @param order 订单
* @param taskStatus 任务目标状态
* @param failReason 任务原因
* @param operator 操作人
*/
private void releaseCurrentTask(AfOrder order, String taskStatus, String failReason, String operator)
{
if (order.getCurrentTaskId() == null)
{
return;
}
AfDispatchTask task = taskMapper.selectAfDispatchTaskByIdForUpdate(order.getCurrentTaskId());
if (StringUtils.isNull(task))
{
return;
}
if (StringUtils.equalsAny(task.getStatus(), AfStatusConstants.TASK_CREATED, AfStatusConstants.TASK_PUSHED,
AfStatusConstants.TASK_RECEIVED, AfStatusConstants.TASK_PROCESSING))
{
taskMapper.updateTaskStatusById(task.getId(), taskStatus, failReason, operator);
}
if (task.getDeviceId() != null)
{
deviceMapper.updateDeviceToIdle(task.getDeviceId(), task.getId(), operator);
}
}
/**
* 订单完成后同步通知外部来源订单。
*
* @param order 订单
* @param operator 操作人
*/
private void deliverOrderIfNeed(AfOrder order, String operator)
{
if (StringUtils.equals(order.getSource(), SOURCE_WEIDIAN))
{
deliverWeidianOrder(order.getSourceOrderNo(), operator);
}
}
/**
* 从微店拉取待充值订单并同步入库。
* 调用微店 seller.getOrderListForPC 接口,解析订单列表后逐条 INSERT IGNORE 写入。
@@ -112,7 +112,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
create_by, create_time, update_by, update_time, remark
) values (
#{userName}, #{deviceCode}, #{onlineStatus}, #{taskStatus}, #{currentTaskId},
#{dispatchEnabled}, #{workStatus}, #{idleTime}, #{maintainReason}, #{lastHeartbeatTime},
#{dispatchEnabled}, #{workStatus}, #{idleTime}, #{maintainReason}, sysdate(),
#{createBy}, sysdate(), #{updateBy}, sysdate(), #{remark}
)
</insert>
@@ -129,7 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="idleTime != null">idle_time = #{idleTime},</if>
<if test="maintainReason != null">maintain_reason = #{maintainReason},</if>
<if test="cooldownUntil != null">cooldown_until = #{cooldownUntil},</if>
<if test="lastHeartbeatTime != null">last_heartbeat_time = #{lastHeartbeatTime},</if>
<if test="lastHeartbeatTime != null">last_heartbeat_time = sysdate(),</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null">remark = #{remark},</if>
update_time = sysdate()
@@ -233,13 +233,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and status in ('CREATED', 'PUSHED', 'RECEIVED', 'PROCESSING')
</select>
<select id="selectHeartbeatTimeoutOnlineList" resultMap="AfDeviceResult">
<include refid="selectAfDeviceVo"/>
where online_status = 'ONLINE'
and last_heartbeat_time is not null
and last_heartbeat_time &lt; date_sub(now(), interval #{timeoutSeconds} second)
</select>
<update id="refreshOfflineStatus">
update af_device
set online_status = 'OFFLINE',
work_status = 'NOT_READY',
update_time = sysdate()
where online_status = 'ONLINE'
and last_heartbeat_time is not null
and last_heartbeat_time &lt; date_sub(now(), interval #{timeoutMinutes} minute)
and last_heartbeat_time &lt; date_sub(now(), interval #{timeoutSeconds} second)
</update>
</mapper>
+3 -2
View File
@@ -158,8 +158,9 @@ INSERT INTO sys_menu
VALUES
('订单查询', @AF_ORDER_ID, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:query', '#', 'admin', NOW(), ''),
('订单分发', @AF_ORDER_ID, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:dispatch', '#', 'admin', NOW(), ''),
('订单重试', @AF_ORDER_ID, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:retry', '#', 'admin', NOW(), ''),
('订单取消', @AF_ORDER_ID, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:cancel', '#', 'admin', NOW(), ''),
('标记完成', @AF_ORDER_ID, 3, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:complete','#', 'admin', NOW(), ''),
('重置状态', @AF_ORDER_ID, 4, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:reset', '#', 'admin', NOW(), ''),
('订单取消', @AF_ORDER_ID, 5, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:order:cancel', '#', 'admin', NOW(), ''),
('账号设备查询', @AF_DEVICE_ID, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:device:query', '#', 'admin', NOW(), ''),
('账号设备修改', @AF_DEVICE_ID, 2, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:device:edit', '#', 'admin', NOW(), ''),
('任务查询', @AF_TASK_ID, 1, '#', '', NULL, '', 1, 0, 'F', '0', '0', 'af:task:query', '#', 'admin', NOW(), ''),