jiaxing.zhou

Merge remote-tracking branch 'origin/dev'

...@@ -2539,8 +2539,418 @@ Authorization: Bearer <JWT_TOKEN> ...@@ -2539,8 +2539,418 @@ Authorization: Bearer <JWT_TOKEN>
2539 2539
2540 **响应:** 返回Excel文件流,文件名格式:`发票数据_yyyyMMdd_HHmmss.xlsx` 2540 **响应:** 返回Excel文件流,文件名格式:`发票数据_yyyyMMdd_HHmmss.xlsx`
2541 2541
2542 +### 4. 异常工单数据导出
2543 +
2544 +**接口路径:** `POST /api/exception-workorder/export`
2545 +**请求方法:** POST
2546 +**权限要求:** `exception:workorder:export`
2547 +
2548 +**请求参数:** 同异常工单查询接口参数
2549 +
2550 +**响应:** 返回Excel文件流,文件名格式:`异常工单数据_yyyyMMdd_HHmmss.xlsx`
2551 +
2552 +## 12. 异常工单管理 (ExceptionWorkorderController)
2553 +
2554 +### 12.1 分页查询异常工单列表
2555 +
2556 +**接口路径:** `GET /api/exception-workorder/list`
2557 +
2558 +**功能描述:** 根据条件分页查询异常工单列表
2559 +
2560 +**请求头:**
2561 +```
2562 +Authorization: Bearer <JWT_TOKEN>
2563 +```
2564 +
2565 +**请求参数:**
2566 +| 参数名 | 类型 | 必填 | 说明 |
2567 +|--------|------|------|------|
2568 +| workorderNo | String | 否 | 工单编号(模糊查询) |
2569 +| orderNo | String | 否 | 关联订单号(模糊查询) |
2570 +| dealerCode | String | 否 | 经销商编码 |
2571 +| dealerName | String | 否 | 经销商名称(模糊查询) |
2572 +| workorderStatus | Integer | 否 | 工单状态(1-待处理/2-处理中/3-已解决/4-已关闭) |
2573 +| exceptionType | Integer | 否 | 异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常) |
2574 +| severityLevel | Integer | 否 | 严重程度(1-高/2-中/3-低) |
2575 +| handlerUser | String | 否 | 处理人(模糊查询) |
2576 +| startTime | String | 否 | 创建开始时间(yyyy-MM-dd HH:mm:ss) |
2577 +| endTime | String | 否 | 创建结束时间(yyyy-MM-dd HH:mm:ss) |
2578 +| pageNum | Integer | 是 | 页码,默认1 |
2579 +| pageSize | Integer | 是 | 每页大小,默认10 |
2580 +
2581 +**权限要求:** `exception:workorder:list`
2582 +
2583 +**响应示例:**
2584 +```json
2585 +{
2586 + "code": 200,
2587 + "message": "操作成功",
2588 + "data": {
2589 + "records": [
2590 + {
2591 + "workorderId": 1,
2592 + "workorderNo": "EW202501290001",
2593 + "orderNo": "ORD202501290001",
2594 + "dealerCode": "D001",
2595 + "dealerName": "北京经销商",
2596 + "exceptionType": 1,
2597 + "exceptionTypeName": "逻辑验证异常",
2598 + "severityLevel": 1,
2599 + "severityLevelName": "高",
2600 + "workorderStatus": 1,
2601 + "workorderStatusName": "待处理",
2602 + "createTime": "2025-01-29 10:00:00",
2603 + "expectCompleteTime": "2025-01-30 18:00:00",
2604 + "handlerUser": "张三",
2605 + "exceptionDesc": "订单金额与产品单价不匹配",
2606 + "handleSuggest": "请核实订单明细",
2607 + "dataSource": "系统自动生成",
2608 + "createBy": "system",
2609 + "updateBy": null,
2610 + "updateTime": null,
2611 + "workorderLogs": []
2612 + }
2613 + ],
2614 + "total": 1,
2615 + "size": 10,
2616 + "current": 1,
2617 + "pages": 1
2618 + }
2619 +}
2620 +```
2621 +
2622 +### 12.2 获取异常工单详情
2623 +
2624 +**接口路径:** `GET /api/exception-workorder/{workorderId}`
2625 +
2626 +**功能描述:** 根据工单ID获取异常工单详细信息,包含处理日志
2627 +
2628 +**请求头:**
2629 +```
2630 +Authorization: Bearer <JWT_TOKEN>
2631 +```
2632 +
2633 +**路径参数:**
2634 +| 参数名 | 类型 | 必填 | 说明 |
2635 +|--------|------|------|------|
2636 +| workorderId | Long | 是 | 工单ID |
2637 +
2638 +**权限要求:** `exception:workorder:detail`
2639 +
2640 +**响应示例:**
2641 +```json
2642 +{
2643 + "code": 200,
2644 + "message": "操作成功",
2645 + "data": {
2646 + "workorderId": 1,
2647 + "workorderNo": "EW202501290001",
2648 + "orderNo": "ORD202501290001",
2649 + "dealerCode": "D001",
2650 + "dealerName": "北京经销商",
2651 + "exceptionType": 1,
2652 + "exceptionTypeName": "逻辑验证异常",
2653 + "severityLevel": 1,
2654 + "severityLevelName": "高",
2655 + "workorderStatus": 2,
2656 + "workorderStatusName": "处理中",
2657 + "createTime": "2025-01-29 10:00:00",
2658 + "expectCompleteTime": "2025-01-30 18:00:00",
2659 + "handlerUser": "张三",
2660 + "exceptionDesc": "订单金额与产品单价不匹配",
2661 + "handleSuggest": "请核实订单明细",
2662 + "dataSource": "系统自动生成",
2663 + "createBy": "system",
2664 + "updateBy": "张三",
2665 + "updateTime": "2025-01-29 11:00:00",
2666 + "workorderLogs": [
2667 + {
2668 + "logId": 1,
2669 + "workorderId": 1,
2670 + "workorderNo": "EW202501290001",
2671 + "handleUser": "张三",
2672 + "handleTime": "2025-01-29 11:00:00",
2673 + "beforeStatus": 1,
2674 + "beforeStatusName": "待处理",
2675 + "afterStatus": 2,
2676 + "afterStatusName": "处理中",
2677 + "handleOpinion": "开始处理此工单",
2678 + "attachUrl": null,
2679 + "createBy": "张三",
2680 + "createTime": "2025-01-29 11:00:00"
2681 + }
2682 + ]
2683 + }
2684 +}
2685 +```
2686 +
2687 +### 12.3 新增异常工单
2688 +
2689 +**接口路径:** `POST /api/exception-workorder`
2690 +
2691 +**功能描述:** 创建新的异常工单
2692 +
2693 +**请求头:**
2694 +```
2695 +Authorization: Bearer <JWT_TOKEN>
2696 +Content-Type: application/json
2697 +```
2698 +
2699 +**请求体:**
2700 +```json
2701 +{
2702 + "workorderNo": "EW202501290002",
2703 + "orderNo": "ORD202501290002",
2704 + "dealerCode": "D002",
2705 + "dealerName": "上海经销商",
2706 + "exceptionType": 2,
2707 + "severityLevel": 2,
2708 + "workorderStatus": 1,
2709 + "expectCompleteTime": "2025-01-30 18:00:00",
2710 + "handlerUser": "李四",
2711 + "exceptionDesc": "经销商信息不完整",
2712 + "handleSuggest": "请补充经销商详细信息",
2713 + "dataSource": "手动创建"
2714 +}
2715 +```
2716 +
2717 +**权限要求:** `exception:workorder:add`
2718 +
2719 +**响应示例:**
2720 +```json
2721 +{
2722 + "code": 200,
2723 + "message": "新增异常工单成功",
2724 + "data": null
2725 +}
2726 +```
2727 +
2728 +### 12.4 更新异常工单
2729 +
2730 +**接口路径:** `PUT /api/exception-workorder`
2731 +
2732 +**功能描述:** 更新异常工单信息
2733 +
2734 +**请求头:**
2735 +```
2736 +Authorization: Bearer <JWT_TOKEN>
2737 +Content-Type: application/json
2738 +```
2739 +
2740 +**请求体:**
2741 +```json
2742 +{
2743 + "workorderId": 1,
2744 + "workorderNo": "EW202501290001",
2745 + "orderNo": "ORD202501290001",
2746 + "dealerCode": "D001",
2747 + "dealerName": "北京经销商",
2748 + "exceptionType": 1,
2749 + "severityLevel": 1,
2750 + "workorderStatus": 2,
2751 + "expectCompleteTime": "2025-01-30 18:00:00",
2752 + "handlerUser": "张三",
2753 + "exceptionDesc": "订单金额与产品单价不匹配",
2754 + "handleSuggest": "请核实订单明细并联系客户确认",
2755 + "dataSource": "系统自动生成"
2756 +}
2757 +```
2758 +
2759 +**权限要求:** `exception:workorder:edit`
2760 +
2761 +**响应示例:**
2762 +```json
2763 +{
2764 + "code": 200,
2765 + "message": "更新异常工单成功",
2766 + "data": null
2767 +}
2768 +```
2769 +
2770 +### 12.5 更新工单状态
2771 +
2772 +**接口路径:** `POST /api/exception-workorder/status`
2773 +
2774 +**功能描述:** 更新异常工单状态并记录处理日志
2775 +
2776 +**请求头:**
2777 +```
2778 +Authorization: Bearer <JWT_TOKEN>
2779 +Content-Type: application/json
2780 +```
2781 +
2782 +**请求体:**
2783 +```json
2784 +{
2785 + "workorderId": 1,
2786 + "workorderStatus": 3,
2787 + "handlerUser": "张三",
2788 + "handleOpinion": "问题已解决,客户确认无误",
2789 + "attachUrl": "http://example.com/attachment.pdf"
2790 +}
2791 +```
2792 +
2793 +**权限要求:** `exception:workorder:edit`
2794 +
2795 +**响应示例:**
2796 +```json
2797 +{
2798 + "code": 200,
2799 + "message": "更新工单状态成功",
2800 + "data": null
2801 +}
2802 +```
2803 +
2804 +### 12.6 删除异常工单
2805 +
2806 +**接口路径:** `DELETE /api/exception-workorder/{workorderId}`
2807 +
2808 +**功能描述:** 根据工单ID逻辑删除异常工单
2809 +
2810 +**请求头:**
2811 +```
2812 +Authorization: Bearer <JWT_TOKEN>
2813 +```
2814 +
2815 +**路径参数:**
2816 +| 参数名 | 类型 | 必填 | 说明 |
2817 +|--------|------|------|------|
2818 +| workorderId | Long | 是 | 工单ID |
2819 +
2820 +**权限要求:** `exception:workorder:delete`
2821 +
2822 +**响应示例:**
2823 +```json
2824 +{
2825 + "code": 200,
2826 + "message": "删除异常工单成功",
2827 + "data": null
2828 +}
2829 +```
2830 +
2831 +### 12.7 批量删除异常工单
2832 +
2833 +**接口路径:** `DELETE /api/exception-workorder/batch`
2834 +
2835 +**功能描述:** 根据工单ID列表批量逻辑删除异常工单
2836 +
2837 +**请求头:**
2838 +```
2839 +Authorization: Bearer <JWT_TOKEN>
2840 +Content-Type: application/json
2841 +```
2842 +
2843 +**请求体:**
2844 +```json
2845 +[1, 2, 3]
2846 +```
2847 +
2848 +**权限要求:** `exception:workorder:delete`
2849 +
2850 +**响应示例:**
2851 +```json
2852 +{
2853 + "code": 200,
2854 + "message": "批量删除异常工单成功",
2855 + "data": null
2856 +}
2857 +```
2858 +
2859 +### 12.8 批量更新工单状态
2860 +
2861 +**接口路径:** `POST /api/exception-workorder/batch-status`
2862 +
2863 +**功能描述:** 批量更新异常工单状态
2864 +
2865 +**请求头:**
2866 +```
2867 +Authorization: Bearer <JWT_TOKEN>
2868 +```
2869 +
2870 +**请求参数:**
2871 +| 参数名 | 类型 | 必填 | 说明 |
2872 +|--------|------|------|------|
2873 +| workorderIds | String | 是 | 工单ID列表,逗号分隔 |
2874 +| workorderStatus | Integer | 是 | 工单状态 |
2875 +| handlerUser | String | 是 | 处理人 |
2876 +
2877 +**权限要求:** `exception:workorder:edit`
2878 +
2879 +**响应示例:**
2880 +```json
2881 +{
2882 + "code": 200,
2883 + "message": "批量更新工单状态成功",
2884 + "data": null
2885 +}
2886 +```
2887 +
2888 +### 12.9 获取异常工单统计信息
2889 +
2890 +**接口路径:** `GET /api/exception-workorder/stats`
2891 +
2892 +**功能描述:** 获取异常工单的统计信息
2893 +
2894 +**请求头:**
2895 +```
2896 +Authorization: Bearer <JWT_TOKEN>
2897 +```
2898 +
2899 +**权限要求:** `exception:workorder:list`
2900 +
2901 +**响应示例:**
2902 +```json
2903 +{
2904 + "code": 200,
2905 + "message": "操作成功",
2906 + "data": [
2907 + {
2908 + "workorderNo": "total",
2909 + "workorderId": 10,
2910 + "exceptionType": 3,
2911 + "severityLevel": 2,
2912 + "workorderStatus": 4,
2913 + "handlerUser": 1,
2914 + "exceptionDesc": 5,
2915 + "handleSuggest": 3,
2916 + "dataSource": 2
2917 + }
2918 + ]
2919 +}
2920 +```
2921 +
2922 +### 12.10 导出异常工单数据
2923 +
2924 +**接口路径:** `POST /api/exception-workorder/export`
2925 +
2926 +**功能描述:** 根据查询条件导出异常工单数据到Excel
2927 +
2928 +**请求头:**
2929 +```
2930 +Authorization: Bearer <JWT_TOKEN>
2931 +Content-Type: application/json
2932 +```
2933 +
2934 +**请求体:** 同异常工单查询接口参数(可选,为空时导出所有数据)
2935 +
2936 +**权限要求:** `exception:workorder:export`
2937 +
2938 +**响应:** 返回Excel文件流,文件名格式:`异常工单数据_yyyyMMdd_HHmmss.xlsx`
2939 +
2940 +**导出字段:**
2941 +- 工单ID
2942 +- 工单编号
2943 +- 工单类型(异常类型名称)
2944 +- 严重程度(严重程度名称)
2945 +- 工单状态(工单状态名称)
2946 +- 问题描述
2947 +- 处理人
2948 +- 创建人
2949 +- 创建时间
2950 +- 更新时间
2951 +
2542 --- 2952 ---
2543 2953
2544 **文档版本:** 1.0.0 2954 **文档版本:** 1.0.0
2545 -**最后更新:** 2025-01-27 2955 +**最后更新:** 2025-01-29
2546 **维护人员:** Apple ERP Team 2956 **维护人员:** Apple ERP Team
......
...@@ -6,12 +6,14 @@ import com.apple.erp.dto.ExceptionWorkorderRes; ...@@ -6,12 +6,14 @@ import com.apple.erp.dto.ExceptionWorkorderRes;
6 import com.apple.erp.dto.ExceptionWorkorderStatusUpdateReq; 6 import com.apple.erp.dto.ExceptionWorkorderStatusUpdateReq;
7 import com.apple.erp.dto.ExceptionWorkorderUpdateReq; 7 import com.apple.erp.dto.ExceptionWorkorderUpdateReq;
8 import com.apple.erp.service.ExceptionWorkorderService; 8 import com.apple.erp.service.ExceptionWorkorderService;
9 +import com.apple.erp.service.ExcelExportService;
9 import com.apple.erp.dto.response.ApiRes; 10 import com.apple.erp.dto.response.ApiRes;
10 import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 11 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
11 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
12 import io.swagger.v3.oas.annotations.Parameter; 13 import io.swagger.v3.oas.annotations.Parameter;
13 import io.swagger.v3.oas.annotations.tags.Tag; 14 import io.swagger.v3.oas.annotations.tags.Tag;
14 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.beans.factory.annotation.Autowired;
16 +import org.springframework.http.ResponseEntity;
15 import org.springframework.security.access.prepost.PreAuthorize; 17 import org.springframework.security.access.prepost.PreAuthorize;
16 import org.springframework.validation.annotation.Validated; 18 import org.springframework.validation.annotation.Validated;
17 import org.springframework.web.bind.annotation.*; 19 import org.springframework.web.bind.annotation.*;
...@@ -33,6 +35,9 @@ public class ExceptionWorkorderController { ...@@ -33,6 +35,9 @@ public class ExceptionWorkorderController {
33 35
34 @Autowired 36 @Autowired
35 private ExceptionWorkorderService exceptionWorkorderService; 37 private ExceptionWorkorderService exceptionWorkorderService;
38 +
39 + @Autowired
40 + private ExcelExportService excelExportService;
36 41
37 @Operation(summary = "分页查询异常工单列表", description = "根据条件分页查询异常工单列表") 42 @Operation(summary = "分页查询异常工单列表", description = "根据条件分页查询异常工单列表")
38 @GetMapping("/list") 43 @GetMapping("/list")
...@@ -168,4 +173,22 @@ public class ExceptionWorkorderController { ...@@ -168,4 +173,22 @@ public class ExceptionWorkorderController {
168 List<ExceptionWorkorderRes> stats = exceptionWorkorderService.getExceptionWorkorderStats(); 173 List<ExceptionWorkorderRes> stats = exceptionWorkorderService.getExceptionWorkorderStats();
169 return ApiRes.success(stats); 174 return ApiRes.success(stats);
170 } 175 }
176 +
177 + @Operation(summary = "导出异常工单数据", description = "根据查询条件导出异常工单数据到Excel")
178 + @PostMapping("/export")
179 + @PreAuthorize("hasAuthority('exception:workorder:export')")
180 + public ResponseEntity<byte[]> exportExceptionWorkorders(@RequestBody(required = false) ExceptionWorkorderQueryReq queryReq) {
181 + try {
182 + // 如果请求体为空,创建默认查询条件
183 + if (queryReq == null) {
184 + queryReq = new ExceptionWorkorderQueryReq();
185 + }
186 + // 获取异常工单数据
187 + List<ExceptionWorkorderRes> workorders = exceptionWorkorderService.getExceptionWorkorderListForExport(queryReq);
188 + // 导出Excel
189 + return excelExportService.exportExceptionWorkorders(workorders);
190 + } catch (Exception e) {
191 + throw new RuntimeException("导出异常工单数据失败: " + e.getMessage());
192 + }
193 + }
171 } 194 }
......
...@@ -54,4 +54,12 @@ public interface ExceptionWorkorderMapper extends BaseMapper<ExceptionWorkorder> ...@@ -54,4 +54,12 @@ public interface ExceptionWorkorderMapper extends BaseMapper<ExceptionWorkorder>
54 int batchUpdateWorkorderStatus(@Param("workorderIds") List<Long> workorderIds, 54 int batchUpdateWorkorderStatus(@Param("workorderIds") List<Long> workorderIds,
55 @Param("workorderStatus") Integer workorderStatus, 55 @Param("workorderStatus") Integer workorderStatus,
56 @Param("handlerUser") String handlerUser); 56 @Param("handlerUser") String handlerUser);
57 +
58 + /**
59 + * 获取异常工单列表用于导出
60 + *
61 + * @param queryReq 查询条件
62 + * @return 异常工单列表(不分页)
63 + */
64 + List<ExceptionWorkorderRes> selectExceptionWorkorderListForExport(@Param("query") ExceptionWorkorderQueryReq queryReq);
57 } 65 }
......
...@@ -73,6 +73,14 @@ public interface DeliveryMainService extends IService<DeliveryMain> { ...@@ -73,6 +73,14 @@ public interface DeliveryMainService extends IService<DeliveryMain> {
73 * @return 待出库数量 73 * @return 待出库数量
74 */ 74 */
75 Integer getPendingDeliveryCount(); 75 Integer getPendingDeliveryCount();
76 +
77 + /**
78 + * 获取最近的出库记录
79 + *
80 + * @param limit 限制数量
81 + * @return 最近出库列表
82 + */
83 + List<DeliveryRes> getRecentDeliveries(Integer limit);
76 } 84 }
77 85
78 86
......
...@@ -91,4 +91,12 @@ public interface ExceptionWorkorderService extends IService<ExceptionWorkorder> ...@@ -91,4 +91,12 @@ public interface ExceptionWorkorderService extends IService<ExceptionWorkorder>
91 * @return 统计信息 91 * @return 统计信息
92 */ 92 */
93 List<ExceptionWorkorderRes> getExceptionWorkorderStats(); 93 List<ExceptionWorkorderRes> getExceptionWorkorderStats();
94 +
95 + /**
96 + * 获取异常工单列表用于导出
97 + *
98 + * @param queryReq 查询条件
99 + * @return 异常工单列表(不分页)
100 + */
101 + List<ExceptionWorkorderRes> getExceptionWorkorderListForExport(ExceptionWorkorderQueryReq queryReq);
94 } 102 }
......
...@@ -73,6 +73,14 @@ public interface InvoiceMainService extends IService<InvoiceMain> { ...@@ -73,6 +73,14 @@ public interface InvoiceMainService extends IService<InvoiceMain> {
73 * @return 待开票数量 73 * @return 待开票数量
74 */ 74 */
75 Integer getPendingInvoiceCount(); 75 Integer getPendingInvoiceCount();
76 +
77 + /**
78 + * 获取最近的发票记录
79 + *
80 + * @param limit 限制数量
81 + * @return 最近发票列表
82 + */
83 + List<InvoiceRes> getRecentInvoices(Integer limit);
76 } 84 }
77 85
78 86
......
...@@ -108,5 +108,13 @@ public interface OrderMainService extends IService<OrderMain> { ...@@ -108,5 +108,13 @@ public interface OrderMainService extends IService<OrderMain> {
108 * @return 销售额 108 * @return 销售额
109 */ 109 */
110 Double getTodaySalesAmount(String date); 110 Double getTodaySalesAmount(String date);
111 +
112 + /**
113 + * 获取最近的订单记录
114 + *
115 + * @param limit 限制数量
116 + * @return 最近订单列表
117 + */
118 + List<OrderRes> getRecentOrders(Integer limit);
111 } 119 }
112 120
......
...@@ -139,4 +139,12 @@ public interface RebateService extends IService<Rebate> { ...@@ -139,4 +139,12 @@ public interface RebateService extends IService<Rebate> {
139 * @return 趋势统计数据 139 * @return 趋势统计数据
140 */ 140 */
141 List<Map<String, Object>> getRebateTrendStats(String startDate, String endDate); 141 List<Map<String, Object>> getRebateTrendStats(String startDate, String endDate);
142 +
143 + /**
144 + * 获取最近的返利记录
145 + *
146 + * @param limit 限制数量
147 + * @return 最近返利列表
148 + */
149 + List<RebateRes> getRecentRebates(Integer limit);
142 } 150 }
......
1 package com.apple.erp.service.impl; 1 package com.apple.erp.service.impl;
2 2
3 import com.apple.erp.dto.response.DashboardStatsRes; 3 import com.apple.erp.dto.response.DashboardStatsRes;
4 +import com.apple.erp.dto.OrderRes;
5 +import com.apple.erp.dto.DeliveryRes;
6 +import com.apple.erp.dto.InvoiceRes;
7 +import com.apple.erp.dto.response.RebateRes;
4 import com.apple.erp.service.DashboardService; 8 import com.apple.erp.service.DashboardService;
5 import com.apple.erp.service.OrderMainService; 9 import com.apple.erp.service.OrderMainService;
6 import com.apple.erp.service.DeliveryMainService; 10 import com.apple.erp.service.DeliveryMainService;
7 import com.apple.erp.service.InvoiceMainService; 11 import com.apple.erp.service.InvoiceMainService;
12 +import com.apple.erp.service.RebateService;
8 import com.apple.erp.service.SessionService; 13 import com.apple.erp.service.SessionService;
9 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
10 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.beans.factory.annotation.Autowired;
...@@ -16,7 +21,6 @@ import java.util.ArrayList; ...@@ -16,7 +21,6 @@ import java.util.ArrayList;
16 import java.util.HashMap; 21 import java.util.HashMap;
17 import java.util.List; 22 import java.util.List;
18 import java.util.Map; 23 import java.util.Map;
19 -import java.util.Set;
20 24
21 /** 25 /**
22 * 首页仪表板服务实现 26 * 首页仪表板服务实现
...@@ -35,6 +39,9 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -35,6 +39,9 @@ public class DashboardServiceImpl implements DashboardService {
35 private InvoiceMainService invoiceMainService; 39 private InvoiceMainService invoiceMainService;
36 40
37 @Autowired 41 @Autowired
42 + private RebateService rebateService;
43 +
44 + @Autowired
38 private SessionService sessionService; 45 private SessionService sessionService;
39 46
40 @Override 47 @Override
...@@ -130,14 +137,15 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -130,14 +137,15 @@ public class DashboardServiceImpl implements DashboardService {
130 private List<Map<String, Object>> getRecentOrders() { 137 private List<Map<String, Object>> getRecentOrders() {
131 List<Map<String, Object>> activities = new ArrayList<>(); 138 List<Map<String, Object>> activities = new ArrayList<>();
132 try { 139 try {
133 - // 这里应该从数据库查询最近的订单 140 + List<OrderRes> recentOrders = orderMainService.getRecentOrders(2);
134 - // 暂时返回模拟数据 141 + for (OrderRes order : recentOrders) {
135 - Map<String, Object> activity = new HashMap<>(); 142 + Map<String, Object> activity = new HashMap<>();
136 - activity.put("id", 1); 143 + activity.put("id", order.getOrderId());
137 - activity.put("type", "order"); 144 + activity.put("type", "order");
138 - activity.put("title", "新订单 ORD-2025-001 已创建"); 145 + activity.put("title", "新订单 " + order.getOrderNo() + " 已创建");
139 - activity.put("time", "2分钟前"); 146 + activity.put("time", formatTimeAgo(order.getCreateTime()));
140 - activities.add(activity); 147 + activities.add(activity);
148 + }
141 } catch (Exception e) { 149 } catch (Exception e) {
142 log.error("获取最近订单活动失败", e); 150 log.error("获取最近订单活动失败", e);
143 } 151 }
...@@ -150,14 +158,15 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -150,14 +158,15 @@ public class DashboardServiceImpl implements DashboardService {
150 private List<Map<String, Object>> getRecentDeliveries() { 158 private List<Map<String, Object>> getRecentDeliveries() {
151 List<Map<String, Object>> activities = new ArrayList<>(); 159 List<Map<String, Object>> activities = new ArrayList<>();
152 try { 160 try {
153 - // 这里应该从数据库查询最近的出库记录 161 + List<DeliveryRes> recentDeliveries = deliveryMainService.getRecentDeliveries(2);
154 - // 暂时返回模拟数据 162 + for (DeliveryRes delivery : recentDeliveries) {
155 - Map<String, Object> activity = new HashMap<>(); 163 + Map<String, Object> activity = new HashMap<>();
156 - activity.put("id", 2); 164 + activity.put("id", delivery.getDeliveryId());
157 - activity.put("type", "delivery"); 165 + activity.put("type", "delivery");
158 - activity.put("title", "出库单 DEL-2025-001 已完成"); 166 + activity.put("title", "出库单 " + delivery.getDeliveryNo() + " 已创建");
159 - activity.put("time", "15分钟前"); 167 + activity.put("time", formatTimeAgo(delivery.getCreateTime()));
160 - activities.add(activity); 168 + activities.add(activity);
169 + }
161 } catch (Exception e) { 170 } catch (Exception e) {
162 log.error("获取最近出库活动失败", e); 171 log.error("获取最近出库活动失败", e);
163 } 172 }
...@@ -170,14 +179,15 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -170,14 +179,15 @@ public class DashboardServiceImpl implements DashboardService {
170 private List<Map<String, Object>> getRecentInvoices() { 179 private List<Map<String, Object>> getRecentInvoices() {
171 List<Map<String, Object>> activities = new ArrayList<>(); 180 List<Map<String, Object>> activities = new ArrayList<>();
172 try { 181 try {
173 - // 这里应该从数据库查询最近的发票记录 182 + List<InvoiceRes> recentInvoices = invoiceMainService.getRecentInvoices(2);
174 - // 暂时返回模拟数据 183 + for (InvoiceRes invoice : recentInvoices) {
175 - Map<String, Object> activity = new HashMap<>(); 184 + Map<String, Object> activity = new HashMap<>();
176 - activity.put("id", 3); 185 + activity.put("id", invoice.getInvoiceId());
177 - activity.put("type", "invoice"); 186 + activity.put("type", "invoice");
178 - activity.put("title", "发票 INV-2025-001 已开具"); 187 + activity.put("title", "发票 " + invoice.getInvoiceNo() + " 已开具");
179 - activity.put("time", "1小时前"); 188 + activity.put("time", formatTimeAgo(invoice.getCreateTime()));
180 - activities.add(activity); 189 + activities.add(activity);
190 + }
181 } catch (Exception e) { 191 } catch (Exception e) {
182 log.error("获取最近发票活动失败", e); 192 log.error("获取最近发票活动失败", e);
183 } 193 }
...@@ -190,14 +200,15 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -190,14 +200,15 @@ public class DashboardServiceImpl implements DashboardService {
190 private List<Map<String, Object>> getRecentRebates() { 200 private List<Map<String, Object>> getRecentRebates() {
191 List<Map<String, Object>> activities = new ArrayList<>(); 201 List<Map<String, Object>> activities = new ArrayList<>();
192 try { 202 try {
193 - // 这里应该从数据库查询最近的返利记录 203 + List<RebateRes> recentRebates = rebateService.getRecentRebates(2);
194 - // 暂时返回模拟数据 204 + for (RebateRes rebate : recentRebates) {
195 - Map<String, Object> activity = new HashMap<>(); 205 + Map<String, Object> activity = new HashMap<>();
196 - activity.put("id", 4); 206 + activity.put("id", rebate.getRebateId());
197 - activity.put("type", "rebate"); 207 + activity.put("type", "rebate");
198 - activity.put("title", "返利计算已完成,共处理 25 条记录"); 208 + activity.put("title", "返利 " + rebate.getRebateNo() + " 已计算");
199 - activity.put("time", "2小时前"); 209 + activity.put("time", formatTimeAgo(rebate.getCreateTime()));
200 - activities.add(activity); 210 + activities.add(activity);
211 + }
201 } catch (Exception e) { 212 } catch (Exception e) {
202 log.error("获取最近返利活动失败", e); 213 log.error("获取最近返利活动失败", e);
203 } 214 }
...@@ -294,4 +305,28 @@ public class DashboardServiceImpl implements DashboardService { ...@@ -294,4 +305,28 @@ public class DashboardServiceImpl implements DashboardService {
294 return "0%"; 305 return "0%";
295 } 306 }
296 } 307 }
308 +
309 + /**
310 + * 格式化时间为相对时间
311 + */
312 + private String formatTimeAgo(java.time.LocalDateTime dateTime) {
313 + if (dateTime == null) {
314 + return "未知时间";
315 + }
316 +
317 + java.time.LocalDateTime now = java.time.LocalDateTime.now();
318 + long minutes = java.time.Duration.between(dateTime, now).toMinutes();
319 +
320 + if (minutes < 1) {
321 + return "刚刚";
322 + } else if (minutes < 60) {
323 + return minutes + "分钟前";
324 + } else if (minutes < 1440) { // 24小时
325 + long hours = minutes / 60;
326 + return hours + "小时前";
327 + } else {
328 + long days = minutes / 1440;
329 + return days + "天前";
330 + }
331 + }
297 } 332 }
......
...@@ -20,6 +20,7 @@ import org.springframework.util.StringUtils; ...@@ -20,6 +20,7 @@ import org.springframework.util.StringUtils;
20 20
21 import java.time.LocalDateTime; 21 import java.time.LocalDateTime;
22 import java.time.format.DateTimeFormatter; 22 import java.time.format.DateTimeFormatter;
23 +import java.util.ArrayList;
23 import java.util.List; 24 import java.util.List;
24 import java.util.stream.Collectors; 25 import java.util.stream.Collectors;
25 26
...@@ -235,6 +236,26 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del ...@@ -235,6 +236,26 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del
235 .eq(DeliveryMain::getDeliveryStatus, 0); // 0表示待出库 236 .eq(DeliveryMain::getDeliveryStatus, 0); // 0表示待出库
236 return Math.toIntExact(count(wrapper)); 237 return Math.toIntExact(count(wrapper));
237 } 238 }
239 +
240 + @Override
241 + public List<DeliveryRes> getRecentDeliveries(Integer limit) {
242 + try {
243 + LambdaQueryWrapper<DeliveryMain> wrapper = new LambdaQueryWrapper<>();
244 + wrapper.eq(DeliveryMain::getDelFlag, "0")
245 + .orderByDesc(DeliveryMain::getCreateTime)
246 + .last("LIMIT " + (limit != null ? limit : 5));
247 +
248 + List<DeliveryMain> deliveries = list(wrapper);
249 + return deliveries.stream().map(delivery -> {
250 + DeliveryRes deliveryRes = new DeliveryRes();
251 + BeanUtils.copyProperties(delivery, deliveryRes);
252 + return deliveryRes;
253 + }).collect(Collectors.toList());
254 + } catch (Exception e) {
255 + log.error("获取最近出库记录失败", e);
256 + return new ArrayList<>();
257 + }
258 + }
238 } 259 }
239 260
240 261
......
...@@ -18,11 +18,9 @@ import org.springframework.beans.BeanUtils; ...@@ -18,11 +18,9 @@ import org.springframework.beans.BeanUtils;
18 import org.springframework.beans.factory.annotation.Autowired; 18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.stereotype.Service; 19 import org.springframework.stereotype.Service;
20 import org.springframework.transaction.annotation.Transactional; 20 import org.springframework.transaction.annotation.Transactional;
21 -import org.springframework.util.StringUtils;
22 21
23 import java.time.LocalDateTime; 22 import java.time.LocalDateTime;
24 import java.util.List; 23 import java.util.List;
25 -import java.util.stream.Collectors;
26 24
27 /** 25 /**
28 * 异常工单Service实现类 26 * 异常工单Service实现类
...@@ -200,4 +198,10 @@ public class ExceptionWorkorderServiceImpl extends ServiceImpl<ExceptionWorkorde ...@@ -200,4 +198,10 @@ public class ExceptionWorkorderServiceImpl extends ServiceImpl<ExceptionWorkorde
200 public List<ExceptionWorkorderRes> getExceptionWorkorderStats() { 198 public List<ExceptionWorkorderRes> getExceptionWorkorderStats() {
201 return exceptionWorkorderMapper.selectExceptionWorkorderStats(); 199 return exceptionWorkorderMapper.selectExceptionWorkorderStats();
202 } 200 }
201 +
202 + @Override
203 + public List<ExceptionWorkorderRes> getExceptionWorkorderListForExport(ExceptionWorkorderQueryReq queryReq) {
204 + // 不分页查询所有数据用于导出
205 + return exceptionWorkorderMapper.selectExceptionWorkorderListForExport(queryReq);
206 + }
203 } 207 }
......
...@@ -21,6 +21,7 @@ import org.springframework.util.StringUtils; ...@@ -21,6 +21,7 @@ import org.springframework.util.StringUtils;
21 import java.time.LocalDate; 21 import java.time.LocalDate;
22 import java.time.LocalDateTime; 22 import java.time.LocalDateTime;
23 import java.time.format.DateTimeFormatter; 23 import java.time.format.DateTimeFormatter;
24 +import java.util.ArrayList;
24 import java.util.List; 25 import java.util.List;
25 import java.util.stream.Collectors; 26 import java.util.stream.Collectors;
26 27
...@@ -236,5 +237,24 @@ public class InvoiceMainServiceImpl extends ServiceImpl<InvoiceMainMapper, Invoi ...@@ -236,5 +237,24 @@ public class InvoiceMainServiceImpl extends ServiceImpl<InvoiceMainMapper, Invoi
236 .eq(InvoiceMain::getInvoiceStatus, 0); // 0表示待开票 237 .eq(InvoiceMain::getInvoiceStatus, 0); // 0表示待开票
237 return Math.toIntExact(count(wrapper)); 238 return Math.toIntExact(count(wrapper));
238 } 239 }
239 - 240 +
241 + @Override
242 + public List<InvoiceRes> getRecentInvoices(Integer limit) {
243 + try {
244 + LambdaQueryWrapper<InvoiceMain> wrapper = new LambdaQueryWrapper<>();
245 + wrapper.eq(InvoiceMain::getDelFlag, "0")
246 + .orderByDesc(InvoiceMain::getCreateTime)
247 + .last("LIMIT " + (limit != null ? limit : 5));
248 +
249 + List<InvoiceMain> invoices = list(wrapper);
250 + return invoices.stream().map(invoice -> {
251 + InvoiceRes invoiceRes = new InvoiceRes();
252 + BeanUtils.copyProperties(invoice, invoiceRes);
253 + return invoiceRes;
254 + }).collect(Collectors.toList());
255 + } catch (Exception e) {
256 + log.error("获取最近发票记录失败", e);
257 + return new ArrayList<>();
258 + }
259 + }
240 } 260 }
......
...@@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
16 import org.springframework.util.StringUtils; 16 import org.springframework.util.StringUtils;
17 17
18 import java.time.LocalDateTime; 18 import java.time.LocalDateTime;
19 +import java.util.ArrayList;
19 import java.util.List; 20 import java.util.List;
20 import java.util.stream.Collectors; 21 import java.util.stream.Collectors;
21 22
...@@ -322,5 +323,25 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain ...@@ -322,5 +323,25 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
322 return 0.0; 323 return 0.0;
323 } 324 }
324 } 325 }
326 +
327 + @Override
328 + public List<OrderRes> getRecentOrders(Integer limit) {
329 + try {
330 + LambdaQueryWrapper<OrderMain> wrapper = new LambdaQueryWrapper<>();
331 + wrapper.eq(OrderMain::getDelFlag, "0")
332 + .orderByDesc(OrderMain::getCreateTime)
333 + .last("LIMIT " + (limit != null ? limit : 5));
334 +
335 + List<OrderMain> orders = list(wrapper);
336 + return orders.stream().map(order -> {
337 + OrderRes orderRes = new OrderRes();
338 + BeanUtils.copyProperties(order, orderRes);
339 + return orderRes;
340 + }).collect(Collectors.toList());
341 + } catch (Exception e) {
342 + log.error("获取最近订单失败", e);
343 + return new ArrayList<>();
344 + }
345 + }
325 } 346 }
326 347
......
...@@ -275,4 +275,24 @@ public class RebateServiceImpl extends ServiceImpl<RebateMapper, Rebate> impleme ...@@ -275,4 +275,24 @@ public class RebateServiceImpl extends ServiceImpl<RebateMapper, Rebate> impleme
275 log.info("获取返利趋势统计数据,开始日期:{},结束日期:{}", startDate, endDate); 275 log.info("获取返利趋势统计数据,开始日期:{},结束日期:{}", startDate, endDate);
276 return rebateMapper.getRebateTrendStats(startDate, endDate); 276 return rebateMapper.getRebateTrendStats(startDate, endDate);
277 } 277 }
278 +
279 + @Override
280 + public List<RebateRes> getRecentRebates(Integer limit) {
281 + try {
282 + LambdaQueryWrapper<Rebate> wrapper = new LambdaQueryWrapper<>();
283 + wrapper.eq(Rebate::getDelFlag, "0")
284 + .orderByDesc(Rebate::getCreateTime)
285 + .last("LIMIT " + (limit != null ? limit : 5));
286 +
287 + List<Rebate> rebates = list(wrapper);
288 + return rebates.stream().map(rebate -> {
289 + RebateRes rebateRes = new RebateRes();
290 + BeanUtils.copyProperties(rebate, rebateRes);
291 + return rebateRes;
292 + }).collect(Collectors.toList());
293 + } catch (Exception e) {
294 + log.error("获取最近返利记录失败", e);
295 + return new ArrayList<>();
296 + }
297 + }
278 } 298 }
......
...@@ -150,4 +150,76 @@ ...@@ -150,4 +150,76 @@
150 AND del_flag = '0' 150 AND del_flag = '0'
151 </update> 151 </update>
152 152
153 + <!-- 获取异常工单列表用于导出 -->
154 + <select id="selectExceptionWorkorderListForExport" resultType="com.apple.erp.dto.ExceptionWorkorderRes">
155 + SELECT
156 + ew.workorder_id,
157 + ew.workorder_no,
158 + ew.order_no,
159 + ew.dealer_code,
160 + ew.dealer_name,
161 + ew.exception_type,
162 + CASE ew.exception_type
163 + WHEN 1 THEN '逻辑验证异常'
164 + WHEN 2 THEN '源头验证异常'
165 + WHEN 3 THEN '交叉验证异常'
166 + ELSE '未知类型'
167 + END AS exception_type_name,
168 + ew.severity_level,
169 + CASE ew.severity_level
170 + WHEN 1 THEN '高'
171 + WHEN 2 THEN '中'
172 + WHEN 3 THEN '低'
173 + ELSE '未知'
174 + END AS severity_level_name,
175 + ew.workorder_status,
176 + CASE ew.workorder_status
177 + WHEN 1 THEN '待处理'
178 + WHEN 2 THEN '处理中'
179 + WHEN 3 THEN '已解决'
180 + WHEN 4 THEN '已关闭'
181 + ELSE '未知状态'
182 + END AS workorder_status_name,
183 + ew.exception_desc,
184 + ew.handler_user,
185 + ew.create_by,
186 + ew.create_time,
187 + ew.update_time
188 + FROM t_exception_workorder ew
189 + <where>
190 + ew.del_flag = '0'
191 + <if test="query.workorderNo != null and query.workorderNo != ''">
192 + AND ew.workorder_no LIKE CONCAT('%', #{query.workorderNo}, '%')
193 + </if>
194 + <if test="query.orderNo != null and query.orderNo != ''">
195 + AND ew.order_no LIKE CONCAT('%', #{query.orderNo}, '%')
196 + </if>
197 + <if test="query.dealerCode != null and query.dealerCode != ''">
198 + AND ew.dealer_code = #{query.dealerCode}
199 + </if>
200 + <if test="query.dealerName != null and query.dealerName != ''">
201 + AND ew.dealer_name LIKE CONCAT('%', #{query.dealerName}, '%')
202 + </if>
203 + <if test="query.workorderStatus != null">
204 + AND ew.workorder_status = #{query.workorderStatus}
205 + </if>
206 + <if test="query.exceptionType != null">
207 + AND ew.exception_type = #{query.exceptionType}
208 + </if>
209 + <if test="query.severityLevel != null">
210 + AND ew.severity_level = #{query.severityLevel}
211 + </if>
212 + <if test="query.handlerUser != null and query.handlerUser != ''">
213 + AND ew.handler_user LIKE CONCAT('%', #{query.handlerUser}, '%')
214 + </if>
215 + <if test="query.startTime != null">
216 + AND ew.create_time >= #{query.startTime}
217 + </if>
218 + <if test="query.endTime != null">
219 + AND ew.create_time &lt;= #{query.endTime}
220 + </if>
221 + </where>
222 + ORDER BY ew.create_time DESC
223 + </select>
224 +
153 </mapper> 225 </mapper>
......
...@@ -146,6 +146,13 @@ export const exceptionWorkorderApi = { ...@@ -146,6 +146,13 @@ export const exceptionWorkorderApi = {
146 // 获取异常工单统计信息 146 // 获取异常工单统计信息
147 getExceptionWorkorderStats: () => { 147 getExceptionWorkorderStats: () => {
148 return request.get('/api/exception-workorder/stats') 148 return request.get('/api/exception-workorder/stats')
149 + },
150 +
151 + // 导出异常工单数据
152 + exportExceptionWorkorders: (params: ExceptionWorkorderQueryReq) => {
153 + return request.post('/api/exception-workorder/export', params, {
154 + responseType: 'blob'
155 + })
149 } 156 }
150 } 157 }
151 158
......
...@@ -734,8 +734,38 @@ const handleBatchProcess = () => { ...@@ -734,8 +734,38 @@ const handleBatchProcess = () => {
734 } 734 }
735 735
736 // 导出 736 // 导出
737 -const handleExport = () => { 737 +const handleExport = async () => {
738 - ElMessage.info('导出功能开发中...') 738 + try {
739 + await ElMessageBox.confirm('确定要导出异常工单数据吗?', '确认导出', {
740 + confirmButtonText: '确定',
741 + cancelButtonText: '取消',
742 + type: 'warning'
743 + })
744 +
745 + ElMessage.info('正在导出数据,请稍候...')
746 +
747 + const response = await exceptionWorkorderApi.exportExceptionWorkorders(searchParams.value)
748 +
749 + // 创建下载链接
750 + const blob = new Blob([response as unknown as BlobPart], {
751 + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
752 + })
753 + const url = window.URL.createObjectURL(blob)
754 + const link = document.createElement('a')
755 + link.href = url
756 + link.download = `异常工单数据_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.xlsx`
757 + document.body.appendChild(link)
758 + link.click()
759 + document.body.removeChild(link)
760 + window.URL.revokeObjectURL(url)
761 +
762 + ElMessage.success('导出成功')
763 + } catch (error: any) {
764 + if (error !== 'cancel') {
765 + console.error('导出失败:', error)
766 + ElMessage.error('导出失败: ' + (error?.message || '未知错误'))
767 + }
768 + }
739 } 769 }
740 770
741 // 提交新增 771 // 提交新增
......