diff --git a/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/BillingTaskMonitorController.java b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/BillingTaskMonitorController.java new file mode 100644 index 00000000..a8366639 --- /dev/null +++ b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/BillingTaskMonitorController.java @@ -0,0 +1,114 @@ +package com.ruoyi.web.controller.monitor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +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; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.price.domain.PrcBillingTask; +import com.ruoyi.price.enums.BillTaskSuccessStatus; +import com.ruoyi.price.service.IPrcBillingTaskService; + +/** + * Monitor: failed / waiting prc_billing_task list and manual resync. + */ +@RestController +@RequestMapping("/monitor/billingTask") +public class BillingTaskMonitorController extends BaseController +{ + @Autowired + private IPrcBillingTaskService billingTaskService; + + /** Default list = FAILED abnormal tasks. */ + @PreAuthorize("@ss.hasPermi('monitor:billingTask:list')") + @GetMapping("/list") + public TableDataInfo list(PrcBillingTask query) + { + if (query.getSuccessStatus() == null || query.getSuccessStatus().isEmpty()) + { + query.setSuccessStatus(BillTaskSuccessStatus.FAILED.getCode()); + } + else if ("ALL".equalsIgnoreCase(query.getSuccessStatus())) + { + query.setSuccessStatus(null); + } + startPage(); + List list = billingTaskService.selectList(query); + return getDataTable(list); + } + + @PreAuthorize("@ss.hasPermi('monitor:billingTask:list')") + @GetMapping("/{taskId}") + public AjaxResult getInfo(@PathVariable("taskId") Long taskId) + { + return success(billingTaskService.getById(taskId)); + } + + /** Manual resync one task (reset WAITING then process). */ + @PreAuthorize("@ss.hasPermi('monitor:billingTask:retry')") + @Log(title = "billing task retry", businessType = BusinessType.UPDATE) + @PostMapping("/retry/{taskId}") + public AjaxResult retry(@PathVariable("taskId") Long taskId) + { + return success(billingTaskService.retryTask(taskId)); + } + + /** Manual resync selected tasks. */ + @PreAuthorize("@ss.hasPermi('monitor:billingTask:retry')") + @Log(title = "billing task batch retry", businessType = BusinessType.UPDATE) + @PostMapping("/retry") + public AjaxResult retryBatch(@RequestBody Long[] taskIds) + { + if (taskIds == null || taskIds.length == 0) + { + return error("taskIds required"); + } + int ok = 0; + int fail = 0; + List> details = new ArrayList>(); + for (Long taskId : taskIds) + { + Map row = new HashMap(); + row.put("taskId", taskId); + try + { + PrcBillingTask task = billingTaskService.retryTask(taskId); + row.put("successStatus", task == null ? null : task.getSuccessStatus()); + row.put("errorMessage", task == null ? null : task.getErrorMessage()); + if (task != null && BillTaskSuccessStatus.SUCCESS.getCode().equals(task.getSuccessStatus())) + { + ok++; + } + else + { + fail++; + } + details.add(row); + } + catch (RuntimeException e) + { + fail++; + row.put("successStatus", "ERROR"); + row.put("errorMessage", e.getMessage()); + details.add(row); + } + } + Map data = new HashMap(); + data.put("ok", Integer.valueOf(ok)); + data.put("fail", Integer.valueOf(fail)); + data.put("details", details); + return success(data); + } +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcBillingTaskService.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcBillingTaskService.java index 19c40c2d..92e7a273 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcBillingTaskService.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcBillingTaskService.java @@ -1,5 +1,6 @@ package com.ruoyi.price.service; +import java.util.List; import com.ruoyi.price.domain.PrcBillingTask; import com.ruoyi.price.domain.vo.BillingTaskSubmitRequest; @@ -12,4 +13,13 @@ public interface IPrcBillingTaskService void processTask(Long taskId); PrcBillingTask getById(Long taskId); + + /** Admin list (failed / waiting / filter). */ + List selectList(PrcBillingTask query); + + /** + * Manual resync: reset to WAITING then process again. + * @return task after retry + */ + PrcBillingTask retryTask(Long taskId); } diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcBillingTaskServiceImpl.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcBillingTaskServiceImpl.java index dbfd1a5e..1cc3885b 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcBillingTaskServiceImpl.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcBillingTaskServiceImpl.java @@ -2,6 +2,7 @@ package com.ruoyi.price.service.impl; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -255,6 +256,41 @@ public class PrcBillingTaskServiceImpl implements IPrcBillingTaskService return billingTaskMapper.selectPrcBillingTaskById(taskId); } + @Override + public List selectList(PrcBillingTask query) + { + return billingTaskMapper.selectPrcBillingTaskList(query); + } + + @Override + public PrcBillingTask retryTask(Long taskId) + { + if (taskId == null) + { + throw new ServiceException("taskId required"); + } + PrcBillingTask task = billingTaskMapper.selectPrcBillingTaskById(taskId); + if (task == null) + { + throw new ServiceException("billing task not found"); + } + String st = task.getSuccessStatus(); + if (BillTaskSuccessStatus.SUCCESS.getCode().equals(st)) + { + throw new ServiceException("SUCCESS task cannot retry"); + } + // Reset to WAITING so UI reflects re-queue; then sync process (admin expects immediate result). + PrcBillingTask reset = new PrcBillingTask(); + reset.setTaskId(taskId); + reset.setSuccessStatus(BillTaskSuccessStatus.WAITING.getCode()); + reset.setBillId(null); + reset.setErrorMessage(null); + billingTaskMapper.updateBillingResult(reset); + + processTask(taskId); + return billingTaskMapper.selectPrcBillingTaskById(taskId); + } + private BillTaskType resolveAutoType(String transferNo, String trackingNo, String orderNo) { PrcOrderBill existed = null; diff --git a/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcBillingTaskMapper.xml b/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcBillingTaskMapper.xml index 71435b9e..6f46147d 100644 --- a/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcBillingTaskMapper.xml +++ b/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcBillingTaskMapper.xml @@ -35,13 +35,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - AND transfer_no = #{transferNo} + AND transfer_no like concat('%', #{transferNo}, '%') - AND tracking_no = #{trackingNo} + AND tracking_no like concat('%', #{trackingNo}, '%') - AND order_no = #{orderNo} + AND order_no like concat('%', #{orderNo}, '%') AND bill_type = #{billType} @@ -49,6 +49,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND success_status = #{successStatus} + + AND create_time >= #{params.beginTime} + + + AND create_time <= #{params.endTime} + order by task_id desc diff --git a/bms-back/sql/monitor/billing_task_menu.sql b/bms-back/sql/monitor/billing_task_menu.sql new file mode 100644 index 00000000..c3b44bc4 --- /dev/null +++ b/bms-back/sql/monitor/billing_task_menu.sql @@ -0,0 +1,18 @@ +-- Billing task abnormal list under system monitor (parent_id = 2) +SET NAMES utf8mb4; + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT 2322, N'计费任务异常', 2, 8, 'billingTask', 'monitor/billingTask/index', '', 'BillingTaskMonitor', 1, 0, 'C', '0', '0', 'monitor:billingTask:list', 'bug', 'admin', sysdate(), N'prc_billing_task异常订单,支持手工重新同步' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2322 OR perms = 'monitor:billingTask:list'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2323, N'查询', 2322, 1, '', NULL, 1, 0, 'F', '0', '0', 'monitor:billingTask:list', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2323); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT 2324, N'重新同步', 2322, 2, '', NULL, 1, 0, 'F', '0', '0', 'monitor:billingTask:retry', '#', 'admin', sysdate(), N'手工重试计费任务' +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2324 OR perms = 'monitor:billingTask:retry'); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT 1, m.menu_id FROM (SELECT 2322 AS menu_id UNION SELECT 2323 UNION SELECT 2324) m +WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 1 AND rm.menu_id = m.menu_id); diff --git a/bms-front/src/api/monitor/billingTask.js b/bms-front/src/api/monitor/billingTask.js new file mode 100644 index 00000000..c71d4aa1 --- /dev/null +++ b/bms-front/src/api/monitor/billingTask.js @@ -0,0 +1,31 @@ +import request from '@/utils/request' + +export function listBillingTask(query) { + return request({ + url: '/monitor/billingTask/list', + method: 'get', + params: query + }) +} + +export function getBillingTask(taskId) { + return request({ + url: '/monitor/billingTask/' + taskId, + method: 'get' + }) +} + +export function retryBillingTask(taskId) { + return request({ + url: '/monitor/billingTask/retry/' + taskId, + method: 'post' + }) +} + +export function retryBillingTaskBatch(taskIds) { + return request({ + url: '/monitor/billingTask/retry', + method: 'post', + data: taskIds + }) +} diff --git a/bms-front/src/views/monitor/billingTask/index.vue b/bms-front/src/views/monitor/billingTask/index.vue new file mode 100644 index 00000000..586d9f3f --- /dev/null +++ b/bms-front/src/views/monitor/billingTask/index.vue @@ -0,0 +1,277 @@ + + + + +