Merge branch 'master' of http://gitlab.erry.com/zhouhui.jiang/test_cursor
# Conflicts: # frontend/components.d.ts # frontend/src/views/delivery/index.vue
Showing
51 changed files
with
3159 additions
and
233 deletions
| ... | @@ -103,7 +103,7 @@ | ... | @@ -103,7 +103,7 @@ |
| 103 | 103 | ||
| 104 | **接口路径:** `GET /api/auth/userinfo` | 104 | **接口路径:** `GET /api/auth/userinfo` |
| 105 | 105 | ||
| 106 | -**功能描述:** 获取当前登录用户的详细信息 | 106 | +**功能描述:** 获取当前登录用户的详细信息,包括用户名、真实姓名、角色列表和权限列表 |
| 107 | 107 | ||
| 108 | **请求头:** `Authorization: Bearer {token}` | 108 | **请求头:** `Authorization: Bearer {token}` |
| 109 | 109 | ||
| ... | @@ -114,11 +114,46 @@ | ... | @@ -114,11 +114,46 @@ |
| 114 | "message": "获取用户信息成功", | 114 | "message": "获取用户信息成功", |
| 115 | "data": { | 115 | "data": { |
| 116 | "username": "admin", | 116 | "username": "admin", |
| 117 | - "authorities": ["ROLE_ADMIN"] | 117 | + "realName": "系统管理员", |
| 118 | + "roles": [ | ||
| 119 | + { | ||
| 120 | + "roleId": 1, | ||
| 121 | + "roleCode": "ADMIN", | ||
| 122 | + "roleName": "系统管理员", | ||
| 123 | + "status": 1, | ||
| 124 | + "statusText": "正常", | ||
| 125 | + "remark": "系统管理员角色", | ||
| 126 | + "createBy": "admin", | ||
| 127 | + "createTime": "2024-01-01T00:00:00", | ||
| 128 | + "updateBy": "admin", | ||
| 129 | + "updateTime": "2024-01-01T00:00:00" | ||
| 130 | + } | ||
| 131 | + ], | ||
| 132 | + "authorities": [ | ||
| 133 | + { | ||
| 134 | + "authority": "ROLE_ADMIN" | ||
| 135 | + } | ||
| 136 | + ] | ||
| 118 | } | 137 | } |
| 119 | } | 138 | } |
| 120 | ``` | 139 | ``` |
| 121 | 140 | ||
| 141 | +**响应字段说明:** | ||
| 142 | +- `username`: 用户名 | ||
| 143 | +- `realName`: 真实姓名 | ||
| 144 | +- `roles`: 用户角色列表 | ||
| 145 | + - `roleId`: 角色ID | ||
| 146 | + - `roleCode`: 角色编码 | ||
| 147 | + - `roleName`: 角色名称 | ||
| 148 | + - `status`: 角色状态(0-停用/1-启用) | ||
| 149 | + - `statusText`: 角色状态文本描述 | ||
| 150 | + - `remark`: 备注 | ||
| 151 | + - `createBy`: 创建者 | ||
| 152 | + - `createTime`: 创建时间 | ||
| 153 | + - `updateBy`: 更新者 | ||
| 154 | + - `updateTime`: 更新时间 | ||
| 155 | +- `authorities`: 用户权限列表(Spring Security权限对象) | ||
| 156 | + | ||
| 122 | ## 2. 用户管理 (SysUserController) | 157 | ## 2. 用户管理 (SysUserController) |
| 123 | 158 | ||
| 124 | ### 2.1 获取用户列表 | 159 | ### 2.1 获取用户列表 |
| ... | @@ -2412,6 +2447,50 @@ | ... | @@ -2412,6 +2447,50 @@ |
| 2412 | } | 2447 | } |
| 2413 | ``` | 2448 | ``` |
| 2414 | 2449 | ||
| 2450 | +### 8. 导出发票数据 | ||
| 2451 | + | ||
| 2452 | +**接口路径:** `POST /api/invoice/export` | ||
| 2453 | +**请求方法:** POST | ||
| 2454 | +**权限要求:** `invoice:export` | ||
| 2455 | + | ||
| 2456 | +**请求参数:** 同发票查询接口参数 | ||
| 2457 | + | ||
| 2458 | +**响应:** 返回Excel文件流 | ||
| 2459 | + | ||
| 2460 | +--- | ||
| 2461 | + | ||
| 2462 | +## 八、数据导出接口 | ||
| 2463 | + | ||
| 2464 | +### 1. 订单数据导出 | ||
| 2465 | + | ||
| 2466 | +**接口路径:** `POST /order/export` | ||
| 2467 | +**请求方法:** POST | ||
| 2468 | +**权限要求:** `order:export` | ||
| 2469 | + | ||
| 2470 | +**请求参数:** 同订单查询接口参数 | ||
| 2471 | + | ||
| 2472 | +**响应:** 返回Excel文件流,文件名格式:`订单数据_yyyyMMdd_HHmmss.xlsx` | ||
| 2473 | + | ||
| 2474 | +### 2. 出库数据导出 | ||
| 2475 | + | ||
| 2476 | +**接口路径:** `POST /api/delivery/export` | ||
| 2477 | +**请求方法:** POST | ||
| 2478 | +**权限要求:** `delivery:export` | ||
| 2479 | + | ||
| 2480 | +**请求参数:** 同出库查询接口参数 | ||
| 2481 | + | ||
| 2482 | +**响应:** 返回Excel文件流,文件名格式:`出库数据_yyyyMMdd_HHmmss.xlsx` | ||
| 2483 | + | ||
| 2484 | +### 3. 发票数据导出 | ||
| 2485 | + | ||
| 2486 | +**接口路径:** `POST /api/invoice/export` | ||
| 2487 | +**请求方法:** POST | ||
| 2488 | +**权限要求:** `invoice:export` | ||
| 2489 | + | ||
| 2490 | +**请求参数:** 同发票查询接口参数 | ||
| 2491 | + | ||
| 2492 | +**响应:** 返回Excel文件流,文件名格式:`发票数据_yyyyMMdd_HHmmss.xlsx` | ||
| 2493 | + | ||
| 2415 | --- | 2494 | --- |
| 2416 | 2495 | ||
| 2417 | **文档版本:** 1.0.0 | 2496 | **文档版本:** 1.0.0 | ... | ... |
| 1 | +package com.apple.erp.config; | ||
| 2 | + | ||
| 3 | +import java.util.HashMap; | ||
| 4 | +import java.util.Map; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 字典值配置类 | ||
| 8 | + * 集中管理所有字典值转换配置 | ||
| 9 | + * | ||
| 10 | + * @author Apple ERP System | ||
| 11 | + * @since 2025-01-01 | ||
| 12 | + */ | ||
| 13 | +public class DictConfig { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 操作类型字典 | ||
| 17 | + */ | ||
| 18 | + public static final Map<Integer, String> OPERATE_TYPE = new HashMap<Integer, String>() {{ | ||
| 19 | + put(1, "新增"); | ||
| 20 | + put(2, "修改"); | ||
| 21 | + put(3, "删除"); | ||
| 22 | + }}; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 计算状态字典 | ||
| 26 | + */ | ||
| 27 | + public static final Map<Integer, String> CALC_FLAG = new HashMap<Integer, String>() {{ | ||
| 28 | + put(0, "未计算"); | ||
| 29 | + put(1, "已计算"); | ||
| 30 | + }}; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 审核状态字典 | ||
| 34 | + */ | ||
| 35 | + public static final Map<Integer, String> AUDIT_STATUS = new HashMap<Integer, String>() {{ | ||
| 36 | + put(0, "待审核"); | ||
| 37 | + put(1, "审核通过"); | ||
| 38 | + put(2, "审核中"); | ||
| 39 | + put(3, "审核拒绝"); | ||
| 40 | + }}; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 出库状态字典 | ||
| 44 | + */ | ||
| 45 | + public static final Map<Integer, String> DELIVERY_STATUS = new HashMap<Integer, String>() {{ | ||
| 46 | + put(0, "未出库"); | ||
| 47 | + put(1, "已出库"); | ||
| 48 | + put(2, "部分出库"); | ||
| 49 | + }}; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * 发票状态字典 | ||
| 53 | + */ | ||
| 54 | + public static final Map<Integer, String> INVOICE_STATUS = new HashMap<Integer, String>() {{ | ||
| 55 | + put(0, "未开票"); | ||
| 56 | + put(1, "已开票"); | ||
| 57 | + put(2, "部分开票"); | ||
| 58 | + }}; | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 返利计算状态字典 | ||
| 62 | + */ | ||
| 63 | + public static final Map<Integer, String> REBATE_CALC_FLAG = new HashMap<Integer, String>() {{ | ||
| 64 | + put(0, "未计算"); | ||
| 65 | + put(1, "已计算"); | ||
| 66 | + }}; | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 审核状态字典 | ||
| 70 | + */ | ||
| 71 | + public static final Map<Integer, String> VERIFY_STATUS = new HashMap<Integer, String>() {{ | ||
| 72 | + put(0, "待审核"); | ||
| 73 | + put(1, "审核通过"); | ||
| 74 | + put(2, "审核中"); | ||
| 75 | + put(3, "审核拒绝"); | ||
| 76 | + }}; | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 工单状态字典 | ||
| 80 | + */ | ||
| 81 | + public static final Map<Integer, String> WORKORDER_STATUS = new HashMap<Integer, String>() {{ | ||
| 82 | + put(0, "待处理"); | ||
| 83 | + put(1, "处理中"); | ||
| 84 | + put(2, "已完成"); | ||
| 85 | + put(3, "已关闭"); | ||
| 86 | + }}; | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * 严重程度字典 | ||
| 90 | + */ | ||
| 91 | + public static final Map<Integer, String> SEVERITY_LEVEL = new HashMap<Integer, String>() {{ | ||
| 92 | + put(1, "低"); | ||
| 93 | + put(2, "中"); | ||
| 94 | + put(3, "高"); | ||
| 95 | + put(4, "紧急"); | ||
| 96 | + }}; | ||
| 97 | +} |
| 1 | +package com.apple.erp.config; | ||
| 2 | + | ||
| 3 | +import java.util.HashMap; | ||
| 4 | +import java.util.Map; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 导出配置类 | ||
| 8 | + * 定义各模块的导出字段映射配置 | ||
| 9 | + * | ||
| 10 | + * @author Apple ERP System | ||
| 11 | + * @since 2025-01-01 | ||
| 12 | + */ | ||
| 13 | +public class ExportConfig { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 订单导出配置 | ||
| 17 | + */ | ||
| 18 | + public static final Map<String, String[]> ORDER_EXPORT_CONFIG = new HashMap<String, String[]>() {{ | ||
| 19 | + put("headers", new String[]{ | ||
| 20 | + "订单ID", "订单编号", "经销商编码", "经销商名称", "订单日期", | ||
| 21 | + "订单金额", "返利金额", "出库状态", "开票状态", "返利计算状态", | ||
| 22 | + "数据来源", "审核状态", "上传时间", "创建时间" | ||
| 23 | + }); | ||
| 24 | + put("fields", new String[]{ | ||
| 25 | + "orderId", "orderNo", "dealerCode", "dealerName", "orderDate", | ||
| 26 | + "totalAmount", "rebateAmount", "deliveryStatus", "invoiceStatus", "rebateCalcFlag", | ||
| 27 | + "dataSource", "verifyStatus", "uploadTime", "createTime" | ||
| 28 | + }); | ||
| 29 | + }}; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 出库导出配置 | ||
| 33 | + */ | ||
| 34 | + public static final Map<String, String[]> DELIVERY_EXPORT_CONFIG = new HashMap<String, String[]>() {{ | ||
| 35 | + put("headers", new String[]{ | ||
| 36 | + "出库单ID", "出库单编号", "经销商编码", "经销商名称", "出库日期", | ||
| 37 | + "关联订单编号", "出库状态", "仓库编码", "数据来源", "创建时间" | ||
| 38 | + }); | ||
| 39 | + put("fields", new String[]{ | ||
| 40 | + "deliveryId", "deliveryNo", "dealerCode", "dealerName", "deliveryDate", | ||
| 41 | + "orderNo", "deliveryStatus", "warehouseCode", "dataSource", "createTime" | ||
| 42 | + }); | ||
| 43 | + }}; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 发票导出配置 | ||
| 47 | + */ | ||
| 48 | + public static final Map<String, String[]> INVOICE_EXPORT_CONFIG = new HashMap<String, String[]>() {{ | ||
| 49 | + put("headers", new String[]{ | ||
| 50 | + "发票ID", "发票编号", "订单编号", "出库单编号", "经销商编码", | ||
| 51 | + "经销商名称", "发票金额", "发票日期", "开票状态", "税率", | ||
| 52 | + "数据来源", "创建时间" | ||
| 53 | + }); | ||
| 54 | + put("fields", new String[]{ | ||
| 55 | + "invoiceId", "invoiceNo", "orderNo", "deliveryNo", "dealerCode", | ||
| 56 | + "dealerName", "totalAmount", "invoiceDate", "invoiceStatus", "taxRate", | ||
| 57 | + "dataSource", "createTime" | ||
| 58 | + }); | ||
| 59 | + }}; | ||
| 60 | + | ||
| 61 | + /** | ||
| 62 | + * 返利导出配置 | ||
| 63 | + */ | ||
| 64 | + public static final Map<String, String[]> REBATE_EXPORT_CONFIG = new HashMap<String, String[]>() {{ | ||
| 65 | + put("headers", new String[]{ | ||
| 66 | + "返利ID", "返利编号", "订单编号", "经销商编码", "经销商名称", | ||
| 67 | + "返利金额", "返利类型", "计算状态", "审核状态", "数据来源", | ||
| 68 | + "创建时间", "更新时间" | ||
| 69 | + }); | ||
| 70 | + put("fields", new String[]{ | ||
| 71 | + "rebateId", "rebateNo", "orderNo", "dealerCode", "dealerName", | ||
| 72 | + "rebateAmount", "operateType", "calcFlag", "auditStatus", "dataSource", | ||
| 73 | + "createTime", "updateTime" | ||
| 74 | + }); | ||
| 75 | + }}; | ||
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * 异常工单导出配置 | ||
| 79 | + */ | ||
| 80 | + public static final Map<String, String[]> EXCEPTION_WORKORDER_EXPORT_CONFIG = new HashMap<String, String[]>() {{ | ||
| 81 | + put("headers", new String[]{ | ||
| 82 | + "工单ID", "工单编号", "工单类型", "严重程度", "工单状态", | ||
| 83 | + "问题描述", "处理人", "创建人", "创建时间", "更新时间" | ||
| 84 | + }); | ||
| 85 | + put("fields", new String[]{ | ||
| 86 | + "workorderId", "workorderNo", "workorderType", "severityLevel", "workorderStatus", | ||
| 87 | + "problemDescription", "assignee", "creator", "createTime", "updateTime" | ||
| 88 | + }); | ||
| 89 | + }}; | ||
| 90 | +} |
| ... | @@ -4,6 +4,7 @@ import com.apple.erp.dto.request.LoginReq; | ... | @@ -4,6 +4,7 @@ import com.apple.erp.dto.request.LoginReq; |
| 4 | import com.apple.erp.dto.request.RefreshTokenReq; | 4 | import com.apple.erp.dto.request.RefreshTokenReq; |
| 5 | import com.apple.erp.dto.response.ApiRes; | 5 | import com.apple.erp.dto.response.ApiRes; |
| 6 | import com.apple.erp.dto.response.LoginRes; | 6 | import com.apple.erp.dto.response.LoginRes; |
| 7 | +import com.apple.erp.dto.response.RoleRes; | ||
| 7 | import com.apple.erp.dto.response.UserInfoRes; | 8 | import com.apple.erp.dto.response.UserInfoRes; |
| 8 | import com.apple.erp.entity.SysUser; | 9 | import com.apple.erp.entity.SysUser; |
| 9 | import com.apple.erp.service.SysUserService; | 10 | import com.apple.erp.service.SysUserService; |
| ... | @@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.*; | ... | @@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.*; |
| 23 | 24 | ||
| 24 | import javax.servlet.http.HttpServletRequest; | 25 | import javax.servlet.http.HttpServletRequest; |
| 25 | import javax.validation.Valid; | 26 | import javax.validation.Valid; |
| 27 | +import java.util.List; | ||
| 26 | 28 | ||
| 27 | /** | 29 | /** |
| 28 | * 认证控制器 | 30 | * 认证控制器 |
| ... | @@ -214,9 +216,34 @@ public class AuthController { | ... | @@ -214,9 +216,34 @@ public class AuthController { |
| 214 | if (authentication != null && authentication.isAuthenticated()) { | 216 | if (authentication != null && authentication.isAuthenticated()) { |
| 215 | String username = authentication.getName(); | 217 | String username = authentication.getName(); |
| 216 | 218 | ||
| 217 | - UserInfoRes userInfo = new UserInfoRes(username, authentication.getAuthorities()); | 219 | + try { |
| 218 | - ApiRes<UserInfoRes> response = ApiRes.success("获取用户信息成功", userInfo); | 220 | + // 获取用户详细信息 |
| 219 | - return ResponseEntity.ok(response); | 221 | + SysUser user = sysUserService.findByUsername(username); |
| 222 | + if (user != null) { | ||
| 223 | + // 获取用户角色信息 | ||
| 224 | + List<RoleRes> roles = sysUserService.getUserRoles(user.getUserId()); | ||
| 225 | + | ||
| 226 | + UserInfoRes userInfo = new UserInfoRes( | ||
| 227 | + user.getUsername(), | ||
| 228 | + user.getRealName(), | ||
| 229 | + roles, | ||
| 230 | + authentication.getAuthorities() | ||
| 231 | + ); | ||
| 232 | + ApiRes<UserInfoRes> response = ApiRes.success("获取用户信息成功", userInfo); | ||
| 233 | + return ResponseEntity.ok(response); | ||
| 234 | + } else { | ||
| 235 | + // 如果找不到用户信息,返回基本信息 | ||
| 236 | + UserInfoRes userInfo = new UserInfoRes(username, authentication.getAuthorities()); | ||
| 237 | + ApiRes<UserInfoRes> response = ApiRes.success("获取用户信息成功", userInfo); | ||
| 238 | + return ResponseEntity.ok(response); | ||
| 239 | + } | ||
| 240 | + } catch (Exception e) { | ||
| 241 | + log.error("获取用户详细信息失败: " + e.getMessage(), e); | ||
| 242 | + // 如果获取详细信息失败,返回基本信息 | ||
| 243 | + UserInfoRes userInfo = new UserInfoRes(username, authentication.getAuthorities()); | ||
| 244 | + ApiRes<UserInfoRes> response = ApiRes.success("获取用户信息成功", userInfo); | ||
| 245 | + return ResponseEntity.ok(response); | ||
| 246 | + } | ||
| 220 | } else { | 247 | } else { |
| 221 | ApiRes<UserInfoRes> response = ApiRes.error("未认证"); | 248 | ApiRes<UserInfoRes> response = ApiRes.error("未认证"); |
| 222 | return ResponseEntity.status(401).body(response); | 249 | return ResponseEntity.status(401).body(response); | ... | ... |
| ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.DeliveryRes; | ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.DeliveryRes; |
| 6 | import com.apple.erp.dto.DeliveryUpdateReq; | 6 | import com.apple.erp.dto.DeliveryUpdateReq; |
| 7 | import com.apple.erp.service.DeliveryMainService; | 7 | import com.apple.erp.service.DeliveryMainService; |
| 8 | import com.apple.erp.dto.response.ApiRes; | 8 | import com.apple.erp.dto.response.ApiRes; |
| 9 | +import com.apple.erp.service.ExcelExportService; | ||
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 10 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| 10 | import io.swagger.v3.oas.annotations.Operation; | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | import io.swagger.v3.oas.annotations.Parameter; | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import org.springframework.beans.factory.annotation.Autowired; | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | +import org.springframework.http.ResponseEntity; | ||
| 14 | import org.springframework.security.access.prepost.PreAuthorize; | 16 | import org.springframework.security.access.prepost.PreAuthorize; |
| 15 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 16 | import org.springframework.web.bind.annotation.*; | 18 | import org.springframework.web.bind.annotation.*; |
| 17 | 19 | ||
| 18 | import javax.validation.Valid; | 20 | import javax.validation.Valid; |
| 21 | +import java.time.LocalDateTime; | ||
| 22 | +import java.time.format.DateTimeFormatter; | ||
| 19 | import java.util.List; | 23 | import java.util.List; |
| 20 | 24 | ||
| 21 | /** | 25 | /** |
| ... | @@ -32,6 +36,9 @@ public class DeliveryMainController { | ... | @@ -32,6 +36,9 @@ public class DeliveryMainController { |
| 32 | 36 | ||
| 33 | @Autowired | 37 | @Autowired |
| 34 | private DeliveryMainService deliveryMainService; | 38 | private DeliveryMainService deliveryMainService; |
| 39 | + | ||
| 40 | + @Autowired | ||
| 41 | + private ExcelExportService excelExportService; | ||
| 35 | 42 | ||
| 36 | @Operation(summary = "分页查询出库列表", description = "根据查询条件分页获取出库列表") | 43 | @Operation(summary = "分页查询出库列表", description = "根据查询条件分页获取出库列表") |
| 37 | @GetMapping("/list") | 44 | @GetMapping("/list") |
| ... | @@ -139,6 +146,40 @@ public class DeliveryMainController { | ... | @@ -139,6 +146,40 @@ public class DeliveryMainController { |
| 139 | return ApiRes.error("修改出库状态失败: " + e.getMessage()); | 146 | return ApiRes.error("修改出库状态失败: " + e.getMessage()); |
| 140 | } | 147 | } |
| 141 | } | 148 | } |
| 149 | + | ||
| 150 | + @Operation(summary = "导出出库数据", description = "根据查询条件导出出库数据到Excel") | ||
| 151 | + @PostMapping("/export") | ||
| 152 | + @PreAuthorize("hasAuthority('delivery:export')") | ||
| 153 | + public ResponseEntity<byte[]> exportDeliveries(@Valid @RequestBody DeliveryQueryReq queryReq) { | ||
| 154 | + try { | ||
| 155 | + // 获取所有符合条件的数据(不分页) | ||
| 156 | + DeliveryQueryReq exportQuery = new DeliveryQueryReq(); | ||
| 157 | + exportQuery.setDeliveryNo(queryReq.getDeliveryNo()); | ||
| 158 | + exportQuery.setDealerCode(queryReq.getDealerCode()); | ||
| 159 | + exportQuery.setDealerName(queryReq.getDealerName()); | ||
| 160 | + exportQuery.setDeliveryStatus(queryReq.getDeliveryStatus()); | ||
| 161 | + exportQuery.setWarehouseCode(queryReq.getWarehouseCode()); | ||
| 162 | + exportQuery.setDataSource(queryReq.getDataSource()); | ||
| 163 | + exportQuery.setDeliveryStartDate(queryReq.getDeliveryStartDate()); | ||
| 164 | + exportQuery.setDeliveryEndDate(queryReq.getDeliveryEndDate()); | ||
| 165 | + // 设置大分页获取所有数据 | ||
| 166 | + exportQuery.setPageNum(1); | ||
| 167 | + exportQuery.setPageSize(10000); | ||
| 168 | + | ||
| 169 | + Page<DeliveryRes> result = deliveryMainService.getDeliveryList(exportQuery); | ||
| 170 | + List<DeliveryRes> deliveries = result.getRecords(); | ||
| 171 | + | ||
| 172 | + // 生成文件名 | ||
| 173 | + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); | ||
| 174 | + String fileName = "出库数据_" + timestamp; | ||
| 175 | + | ||
| 176 | + // 导出到Excel | ||
| 177 | + return excelExportService.exportDeliveries(deliveries); | ||
| 178 | + | ||
| 179 | + } catch (Exception e) { | ||
| 180 | + throw new RuntimeException("导出出库数据失败: " + e.getMessage(), e); | ||
| 181 | + } | ||
| 182 | + } | ||
| 142 | } | 183 | } |
| 143 | 184 | ||
| 144 | 185 | ... | ... |
| 1 | +package com.apple.erp.controller; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.dto.ExceptionWorkorderAddReq; | ||
| 4 | +import com.apple.erp.dto.ExceptionWorkorderQueryReq; | ||
| 5 | +import com.apple.erp.dto.ExceptionWorkorderRes; | ||
| 6 | +import com.apple.erp.dto.ExceptionWorkorderStatusUpdateReq; | ||
| 7 | +import com.apple.erp.dto.ExceptionWorkorderUpdateReq; | ||
| 8 | +import com.apple.erp.service.ExceptionWorkorderService; | ||
| 9 | +import com.apple.erp.dto.response.ApiRes; | ||
| 10 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 11 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 15 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 16 | +import org.springframework.validation.annotation.Validated; | ||
| 17 | +import org.springframework.web.bind.annotation.*; | ||
| 18 | + | ||
| 19 | +import javax.validation.Valid; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 异常工单Controller | ||
| 24 | + * | ||
| 25 | + * @author Apple ERP System | ||
| 26 | + * @since 2025-01-27 | ||
| 27 | + */ | ||
| 28 | +@Tag(name = "异常工单管理", description = "异常工单相关接口") | ||
| 29 | +@RestController | ||
| 30 | +@RequestMapping("/api/exception-workorder") | ||
| 31 | +@Validated | ||
| 32 | +public class ExceptionWorkorderController { | ||
| 33 | + | ||
| 34 | + @Autowired | ||
| 35 | + private ExceptionWorkorderService exceptionWorkorderService; | ||
| 36 | + | ||
| 37 | + @Operation(summary = "分页查询异常工单列表", description = "根据条件分页查询异常工单列表") | ||
| 38 | + @GetMapping("/list") | ||
| 39 | + @PreAuthorize("hasAuthority('exception:workorder:list')") | ||
| 40 | + public ApiRes<Page<ExceptionWorkorderRes>> getExceptionWorkorderList(@Valid ExceptionWorkorderQueryReq queryReq) { | ||
| 41 | + Page<ExceptionWorkorderRes> page = exceptionWorkorderService.getExceptionWorkorderList(queryReq); | ||
| 42 | + return ApiRes.success(page); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Operation(summary = "获取异常工单详情", description = "根据工单ID获取异常工单详细信息,包含处理日志") | ||
| 46 | + @GetMapping("/{workorderId}") | ||
| 47 | + @PreAuthorize("hasAuthority('exception:workorder:detail')") | ||
| 48 | + public ApiRes<ExceptionWorkorderRes> getExceptionWorkorderDetail( | ||
| 49 | + @Parameter(description = "工单ID", required = true) @PathVariable Long workorderId) { | ||
| 50 | + ExceptionWorkorderRes workorderRes = exceptionWorkorderService.getExceptionWorkorderDetail(workorderId); | ||
| 51 | + if (workorderRes != null) { | ||
| 52 | + return ApiRes.success(workorderRes); | ||
| 53 | + } | ||
| 54 | + return ApiRes.error("异常工单不存在或已删除"); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Operation(summary = "新增异常工单", description = "创建新的异常工单") | ||
| 58 | + @PostMapping | ||
| 59 | + @PreAuthorize("hasAuthority('exception:workorder:add')") | ||
| 60 | + public ApiRes<Void> addExceptionWorkorder(@Valid @RequestBody ExceptionWorkorderAddReq addReq) { | ||
| 61 | + try { | ||
| 62 | + boolean result = exceptionWorkorderService.addExceptionWorkorder(addReq); | ||
| 63 | + if (result) { | ||
| 64 | + return ApiRes.success("新增异常工单成功", null); | ||
| 65 | + } else { | ||
| 66 | + return ApiRes.error("新增异常工单失败"); | ||
| 67 | + } | ||
| 68 | + } catch (Exception e) { | ||
| 69 | + return ApiRes.error("新增异常工单失败: " + e.getMessage()); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Operation(summary = "更新异常工单", description = "更新异常工单信息") | ||
| 74 | + @PutMapping | ||
| 75 | + @PreAuthorize("hasAuthority('exception:workorder:edit')") | ||
| 76 | + public ApiRes<Void> updateExceptionWorkorder(@Valid @RequestBody ExceptionWorkorderUpdateReq updateReq) { | ||
| 77 | + try { | ||
| 78 | + boolean result = exceptionWorkorderService.updateExceptionWorkorder(updateReq); | ||
| 79 | + if (result) { | ||
| 80 | + return ApiRes.success("更新异常工单成功", null); | ||
| 81 | + } else { | ||
| 82 | + return ApiRes.error("更新异常工单失败"); | ||
| 83 | + } | ||
| 84 | + } catch (Exception e) { | ||
| 85 | + return ApiRes.error("更新异常工单失败: " + e.getMessage()); | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Operation(summary = "更新工单状态", description = "更新异常工单状态并记录处理日志") | ||
| 90 | + @PostMapping("/status") | ||
| 91 | + @PreAuthorize("hasAuthority('exception:workorder:edit')") | ||
| 92 | + public ApiRes<Void> updateWorkorderStatus(@Valid @RequestBody ExceptionWorkorderStatusUpdateReq statusUpdateReq) { | ||
| 93 | + try { | ||
| 94 | + boolean result = exceptionWorkorderService.updateWorkorderStatus(statusUpdateReq); | ||
| 95 | + if (result) { | ||
| 96 | + return ApiRes.success("更新工单状态成功", null); | ||
| 97 | + } else { | ||
| 98 | + return ApiRes.error("更新工单状态失败"); | ||
| 99 | + } | ||
| 100 | + } catch (Exception e) { | ||
| 101 | + return ApiRes.error("更新工单状态失败: " + e.getMessage()); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + @Operation(summary = "删除异常工单", description = "根据工单ID逻辑删除异常工单") | ||
| 106 | + @DeleteMapping("/{workorderId}") | ||
| 107 | + @PreAuthorize("hasAuthority('exception:workorder:delete')") | ||
| 108 | + public ApiRes<Void> deleteExceptionWorkorder( | ||
| 109 | + @Parameter(description = "工单ID", required = true) @PathVariable Long workorderId) { | ||
| 110 | + try { | ||
| 111 | + boolean result = exceptionWorkorderService.deleteExceptionWorkorder(workorderId); | ||
| 112 | + if (result) { | ||
| 113 | + return ApiRes.success("删除异常工单成功", null); | ||
| 114 | + } else { | ||
| 115 | + return ApiRes.error("删除异常工单失败"); | ||
| 116 | + } | ||
| 117 | + } catch (Exception e) { | ||
| 118 | + return ApiRes.error("删除异常工单失败: " + e.getMessage()); | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Operation(summary = "批量删除异常工单", description = "根据工单ID列表批量逻辑删除异常工单") | ||
| 123 | + @DeleteMapping("/batch") | ||
| 124 | + @PreAuthorize("hasAuthority('exception:workorder:delete')") | ||
| 125 | + public ApiRes<Void> batchDeleteExceptionWorkorders( | ||
| 126 | + @Parameter(description = "工单ID列表", required = true) @RequestBody List<Long> workorderIds) { | ||
| 127 | + try { | ||
| 128 | + if (workorderIds == null || workorderIds.isEmpty()) { | ||
| 129 | + return ApiRes.error("工单ID列表不能为空"); | ||
| 130 | + } | ||
| 131 | + boolean result = exceptionWorkorderService.batchDeleteExceptionWorkorders(workorderIds); | ||
| 132 | + if (result) { | ||
| 133 | + return ApiRes.success("批量删除异常工单成功", null); | ||
| 134 | + } else { | ||
| 135 | + return ApiRes.error("批量删除异常工单失败"); | ||
| 136 | + } | ||
| 137 | + } catch (Exception e) { | ||
| 138 | + return ApiRes.error("批量删除异常工单失败: " + e.getMessage()); | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + @Operation(summary = "批量更新工单状态", description = "批量更新异常工单状态") | ||
| 143 | + @PostMapping("/batch-status") | ||
| 144 | + @PreAuthorize("hasAuthority('exception:workorder:edit')") | ||
| 145 | + public ApiRes<Void> batchUpdateWorkorderStatus( | ||
| 146 | + @Parameter(description = "工单ID列表", required = true) @RequestParam List<Long> workorderIds, | ||
| 147 | + @Parameter(description = "工单状态", required = true) @RequestParam Integer workorderStatus, | ||
| 148 | + @Parameter(description = "处理人", required = true) @RequestParam String handlerUser) { | ||
| 149 | + try { | ||
| 150 | + if (workorderIds == null || workorderIds.isEmpty()) { | ||
| 151 | + return ApiRes.error("工单ID列表不能为空"); | ||
| 152 | + } | ||
| 153 | + boolean result = exceptionWorkorderService.batchUpdateWorkorderStatus(workorderIds, workorderStatus, handlerUser); | ||
| 154 | + if (result) { | ||
| 155 | + return ApiRes.success("批量更新工单状态成功", null); | ||
| 156 | + } else { | ||
| 157 | + return ApiRes.error("批量更新工单状态失败"); | ||
| 158 | + } | ||
| 159 | + } catch (Exception e) { | ||
| 160 | + return ApiRes.error("批量更新工单状态失败: " + e.getMessage()); | ||
| 161 | + } | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + @Operation(summary = "获取异常工单统计信息", description = "获取异常工单的统计信息") | ||
| 165 | + @GetMapping("/stats") | ||
| 166 | + @PreAuthorize("hasAuthority('exception:workorder:list')") | ||
| 167 | + public ApiRes<List<ExceptionWorkorderRes>> getExceptionWorkorderStats() { | ||
| 168 | + List<ExceptionWorkorderRes> stats = exceptionWorkorderService.getExceptionWorkorderStats(); | ||
| 169 | + return ApiRes.success(stats); | ||
| 170 | + } | ||
| 171 | +} |
| ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.InvoiceRes; | ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.InvoiceRes; |
| 6 | import com.apple.erp.dto.InvoiceUpdateReq; | 6 | import com.apple.erp.dto.InvoiceUpdateReq; |
| 7 | import com.apple.erp.service.InvoiceMainService; | 7 | import com.apple.erp.service.InvoiceMainService; |
| 8 | import com.apple.erp.dto.response.ApiRes; | 8 | import com.apple.erp.dto.response.ApiRes; |
| 9 | +import com.apple.erp.service.ExcelExportService; | ||
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 10 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| 10 | import io.swagger.v3.oas.annotations.Operation; | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | import io.swagger.v3.oas.annotations.Parameter; | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import org.springframework.beans.factory.annotation.Autowired; | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | +import org.springframework.http.ResponseEntity; | ||
| 14 | import org.springframework.security.access.prepost.PreAuthorize; | 16 | import org.springframework.security.access.prepost.PreAuthorize; |
| 15 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 16 | import org.springframework.web.bind.annotation.*; | 18 | import org.springframework.web.bind.annotation.*; |
| 17 | 19 | ||
| 18 | import javax.validation.Valid; | 20 | import javax.validation.Valid; |
| 21 | +import java.time.LocalDateTime; | ||
| 22 | +import java.time.format.DateTimeFormatter; | ||
| 19 | import java.util.List; | 23 | import java.util.List; |
| 20 | 24 | ||
| 21 | /** | 25 | /** |
| ... | @@ -32,6 +36,9 @@ public class InvoiceMainController { | ... | @@ -32,6 +36,9 @@ public class InvoiceMainController { |
| 32 | 36 | ||
| 33 | @Autowired | 37 | @Autowired |
| 34 | private InvoiceMainService invoiceMainService; | 38 | private InvoiceMainService invoiceMainService; |
| 39 | + | ||
| 40 | + @Autowired | ||
| 41 | + private ExcelExportService excelExportService; | ||
| 35 | 42 | ||
| 36 | @Operation(summary = "分页查询发票列表", description = "根据查询条件分页获取发票列表") | 43 | @Operation(summary = "分页查询发票列表", description = "根据查询条件分页获取发票列表") |
| 37 | @GetMapping("/list") | 44 | @GetMapping("/list") |
| ... | @@ -139,6 +146,43 @@ public class InvoiceMainController { | ... | @@ -139,6 +146,43 @@ public class InvoiceMainController { |
| 139 | return ApiRes.error("修改发票状态失败: " + e.getMessage()); | 146 | return ApiRes.error("修改发票状态失败: " + e.getMessage()); |
| 140 | } | 147 | } |
| 141 | } | 148 | } |
| 149 | + | ||
| 150 | + @Operation(summary = "导出发票数据", description = "根据查询条件导出发票数据到Excel") | ||
| 151 | + @PostMapping("/export") | ||
| 152 | + @PreAuthorize("hasAuthority('invoice:export')") | ||
| 153 | + public ResponseEntity<byte[]> exportInvoices(@Valid @RequestBody InvoiceQueryReq queryReq) { | ||
| 154 | + try { | ||
| 155 | + // 获取所有符合条件的数据(不分页) | ||
| 156 | + InvoiceQueryReq exportQuery = new InvoiceQueryReq(); | ||
| 157 | + exportQuery.setInvoiceNo(queryReq.getInvoiceNo()); | ||
| 158 | + exportQuery.setOrderNo(queryReq.getOrderNo()); | ||
| 159 | + exportQuery.setDeliveryNo(queryReq.getDeliveryNo()); | ||
| 160 | + exportQuery.setDealerCode(queryReq.getDealerCode()); | ||
| 161 | + exportQuery.setDealerName(queryReq.getDealerName()); | ||
| 162 | + exportQuery.setInvoiceStatus(queryReq.getInvoiceStatus()); | ||
| 163 | + exportQuery.setDataSource(queryReq.getDataSource()); | ||
| 164 | + exportQuery.setInvoiceStartDate(queryReq.getInvoiceStartDate()); | ||
| 165 | + exportQuery.setInvoiceEndDate(queryReq.getInvoiceEndDate()); | ||
| 166 | + exportQuery.setMinAmount(queryReq.getMinAmount()); | ||
| 167 | + exportQuery.setMaxAmount(queryReq.getMaxAmount()); | ||
| 168 | + // 设置大分页获取所有数据 | ||
| 169 | + exportQuery.setPageNum(1); | ||
| 170 | + exportQuery.setPageSize(10000); | ||
| 171 | + | ||
| 172 | + Page<InvoiceRes> result = invoiceMainService.getInvoiceList(exportQuery); | ||
| 173 | + List<InvoiceRes> invoices = result.getRecords(); | ||
| 174 | + | ||
| 175 | + // 生成文件名 | ||
| 176 | + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); | ||
| 177 | + String fileName = "发票数据_" + timestamp; | ||
| 178 | + | ||
| 179 | + // 导出到Excel | ||
| 180 | + return excelExportService.exportInvoices(invoices); | ||
| 181 | + | ||
| 182 | + } catch (Exception e) { | ||
| 183 | + throw new RuntimeException("导出发票数据失败: " + e.getMessage(), e); | ||
| 184 | + } | ||
| 185 | + } | ||
| 142 | } | 186 | } |
| 143 | 187 | ||
| 144 | 188 | ... | ... |
| ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.OrderRes; | ... | @@ -6,16 +6,20 @@ import com.apple.erp.dto.OrderRes; |
| 6 | import com.apple.erp.dto.OrderUpdateReq; | 6 | import com.apple.erp.dto.OrderUpdateReq; |
| 7 | import com.apple.erp.service.OrderMainService; | 7 | import com.apple.erp.service.OrderMainService; |
| 8 | import com.apple.erp.dto.response.ApiRes; | 8 | import com.apple.erp.dto.response.ApiRes; |
| 9 | +import com.apple.erp.service.ExcelExportService; | ||
| 9 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | 10 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| 10 | import io.swagger.v3.oas.annotations.Operation; | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | import io.swagger.v3.oas.annotations.Parameter; | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import org.springframework.beans.factory.annotation.Autowired; | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | +import org.springframework.http.ResponseEntity; | ||
| 14 | import org.springframework.security.access.prepost.PreAuthorize; | 16 | import org.springframework.security.access.prepost.PreAuthorize; |
| 15 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 16 | import org.springframework.web.bind.annotation.*; | 18 | import org.springframework.web.bind.annotation.*; |
| 17 | 19 | ||
| 18 | import javax.validation.Valid; | 20 | import javax.validation.Valid; |
| 21 | +import java.time.LocalDateTime; | ||
| 22 | +import java.time.format.DateTimeFormatter; | ||
| 19 | import java.util.List; | 23 | import java.util.List; |
| 20 | 24 | ||
| 21 | /** | 25 | /** |
| ... | @@ -32,6 +36,9 @@ public class OrderMainController { | ... | @@ -32,6 +36,9 @@ public class OrderMainController { |
| 32 | 36 | ||
| 33 | @Autowired | 37 | @Autowired |
| 34 | private OrderMainService orderMainService; | 38 | private OrderMainService orderMainService; |
| 39 | + | ||
| 40 | + @Autowired | ||
| 41 | + private ExcelExportService excelExportService; | ||
| 35 | 42 | ||
| 36 | @Operation(summary = "分页查询订单列表", description = "根据条件分页查询订单列表") | 43 | @Operation(summary = "分页查询订单列表", description = "根据条件分页查询订单列表") |
| 37 | @GetMapping("/list") | 44 | @GetMapping("/list") |
| ... | @@ -182,4 +189,42 @@ public class OrderMainController { | ... | @@ -182,4 +189,42 @@ public class OrderMainController { |
| 182 | return ApiRes.error("修改返利计算状态失败: " + e.getMessage()); | 189 | return ApiRes.error("修改返利计算状态失败: " + e.getMessage()); |
| 183 | } | 190 | } |
| 184 | } | 191 | } |
| 192 | + | ||
| 193 | + @Operation(summary = "导出订单数据", description = "根据查询条件导出订单数据到Excel") | ||
| 194 | + @PostMapping("/export") | ||
| 195 | + @PreAuthorize("hasAuthority('order:export')") | ||
| 196 | + public ResponseEntity<byte[]> exportOrders(@Valid @RequestBody OrderQueryReq queryReq) { | ||
| 197 | + try { | ||
| 198 | + // 获取所有符合条件的数据(不分页) | ||
| 199 | + OrderQueryReq exportQuery = new OrderQueryReq(); | ||
| 200 | + exportQuery.setOrderNo(queryReq.getOrderNo()); | ||
| 201 | + exportQuery.setDealerCode(queryReq.getDealerCode()); | ||
| 202 | + exportQuery.setDealerName(queryReq.getDealerName()); | ||
| 203 | + exportQuery.setDeliveryStatus(queryReq.getDeliveryStatus()); | ||
| 204 | + exportQuery.setInvoiceStatus(queryReq.getInvoiceStatus()); | ||
| 205 | + exportQuery.setRebateCalcFlag(queryReq.getRebateCalcFlag()); | ||
| 206 | + exportQuery.setDataSource(queryReq.getDataSource()); | ||
| 207 | + exportQuery.setVerifyStatus(queryReq.getVerifyStatus()); | ||
| 208 | + exportQuery.setOrderStartDate(queryReq.getOrderStartDate()); | ||
| 209 | + exportQuery.setOrderEndDate(queryReq.getOrderEndDate()); | ||
| 210 | + exportQuery.setMinAmount(queryReq.getMinAmount()); | ||
| 211 | + exportQuery.setMaxAmount(queryReq.getMaxAmount()); | ||
| 212 | + // 设置大分页获取所有数据 | ||
| 213 | + exportQuery.setPageNum(1); | ||
| 214 | + exportQuery.setPageSize(10000); | ||
| 215 | + | ||
| 216 | + Page<OrderRes> result = orderMainService.getOrderList(exportQuery); | ||
| 217 | + List<OrderRes> orders = result.getRecords(); | ||
| 218 | + | ||
| 219 | + // 生成文件名 | ||
| 220 | + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); | ||
| 221 | + String fileName = "订单数据_" + timestamp; | ||
| 222 | + | ||
| 223 | + // 导出到Excel | ||
| 224 | + return excelExportService.exportOrders(orders); | ||
| 225 | + | ||
| 226 | + } catch (Exception e) { | ||
| 227 | + throw new RuntimeException("导出订单数据失败: " + e.getMessage(), e); | ||
| 228 | + } | ||
| 229 | + } | ||
| 185 | } | 230 | } | ... | ... |
| ... | @@ -7,6 +7,7 @@ import com.apple.erp.dto.response.ApiRes; | ... | @@ -7,6 +7,7 @@ import com.apple.erp.dto.response.ApiRes; |
| 7 | import com.apple.erp.dto.response.RebateRes; | 7 | import com.apple.erp.dto.response.RebateRes; |
| 8 | import com.apple.erp.entity.Rebate; | 8 | import com.apple.erp.entity.Rebate; |
| 9 | import com.apple.erp.service.RebateService; | 9 | import com.apple.erp.service.RebateService; |
| 10 | +import com.apple.erp.service.ExcelExportService; | ||
| 10 | import com.baomidou.mybatisplus.core.metadata.IPage; | 11 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 11 | import io.swagger.v3.oas.annotations.Operation; | 12 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | @@ -17,8 +18,12 @@ import org.springframework.web.bind.annotation.*; | ... | @@ -17,8 +18,12 @@ import org.springframework.web.bind.annotation.*; |
| 17 | 18 | ||
| 18 | import javax.validation.Valid; | 19 | import javax.validation.Valid; |
| 19 | import java.math.BigDecimal; | 20 | import java.math.BigDecimal; |
| 21 | +import java.time.LocalDateTime; | ||
| 22 | +import java.time.format.DateTimeFormatter; | ||
| 20 | import java.util.List; | 23 | import java.util.List; |
| 21 | import java.util.Map; | 24 | import java.util.Map; |
| 25 | +import org.springframework.http.ResponseEntity; | ||
| 26 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 22 | 27 | ||
| 23 | /** | 28 | /** |
| 24 | * 返利台账明细管理控制器 | 29 | * 返利台账明细管理控制器 |
| ... | @@ -36,6 +41,9 @@ public class RebateController { | ... | @@ -36,6 +41,9 @@ public class RebateController { |
| 36 | 41 | ||
| 37 | @Autowired | 42 | @Autowired |
| 38 | private RebateService rebateService; | 43 | private RebateService rebateService; |
| 44 | + | ||
| 45 | + @Autowired | ||
| 46 | + private ExcelExportService excelExportService; | ||
| 39 | 47 | ||
| 40 | @Operation(summary = "分页查询返利明细列表") | 48 | @Operation(summary = "分页查询返利明细列表") |
| 41 | @PostMapping("/page") | 49 | @PostMapping("/page") |
| ... | @@ -277,4 +285,40 @@ public class RebateController { | ... | @@ -277,4 +285,40 @@ public class RebateController { |
| 277 | return ApiRes.error(e.getMessage()); | 285 | return ApiRes.error(e.getMessage()); |
| 278 | } | 286 | } |
| 279 | } | 287 | } |
| 288 | + | ||
| 289 | + @Operation(summary = "导出返利数据", description = "根据查询条件导出返利数据到Excel") | ||
| 290 | + @PostMapping("/export") | ||
| 291 | + @PreAuthorize("hasAuthority('rebate:export')") | ||
| 292 | + public ResponseEntity<byte[]> exportRebates(@Valid @RequestBody RebateQueryReq queryReq) { | ||
| 293 | + log.info("导出返利数据,参数:{}", queryReq); | ||
| 294 | + try { | ||
| 295 | + // 获取所有符合条件的数据(不分页) | ||
| 296 | + RebateQueryReq exportQuery = new RebateQueryReq(); | ||
| 297 | + exportQuery.setRebateNo(queryReq.getRebateNo()); | ||
| 298 | + exportQuery.setOrderNo(queryReq.getOrderNo()); | ||
| 299 | + exportQuery.setDealerCode(queryReq.getDealerCode()); | ||
| 300 | + exportQuery.setDealerName(queryReq.getDealerName()); | ||
| 301 | + exportQuery.setOperateType(queryReq.getOperateType()); | ||
| 302 | + exportQuery.setCalcFlag(queryReq.getCalcFlag()); | ||
| 303 | + exportQuery.setAuditStatus(queryReq.getAuditStatus()); | ||
| 304 | + exportQuery.setDataSource(queryReq.getDataSource()); | ||
| 305 | + exportQuery.setStartDate(queryReq.getStartDate()); | ||
| 306 | + exportQuery.setEndDate(queryReq.getEndDate()); | ||
| 307 | + exportQuery.setMinAmount(queryReq.getMinAmount()); | ||
| 308 | + exportQuery.setMaxAmount(queryReq.getMaxAmount()); | ||
| 309 | + // 设置大分页获取所有数据 | ||
| 310 | + exportQuery.setPageNum(1); | ||
| 311 | + exportQuery.setPageSize(10000); | ||
| 312 | + | ||
| 313 | + IPage<RebateRes> result = rebateService.getRebatePage(exportQuery); | ||
| 314 | + List<RebateRes> rebates = result.getRecords(); | ||
| 315 | + | ||
| 316 | + // 导出到Excel | ||
| 317 | + return excelExportService.exportRebates(rebates); | ||
| 318 | + | ||
| 319 | + } catch (Exception e) { | ||
| 320 | + log.error("导出返利数据失败", e); | ||
| 321 | + throw new RuntimeException("导出返利数据失败: " + e.getMessage(), e); | ||
| 322 | + } | ||
| 323 | + } | ||
| 280 | } | 324 | } | ... | ... |
| ... | @@ -193,6 +193,25 @@ public class SysDictItemController { | ... | @@ -193,6 +193,25 @@ public class SysDictItemController { |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | /** | 195 | /** |
| 196 | + * 刷新字典缓存 | ||
| 197 | + * 当字典项发生变化时,刷新Redis缓存以保持数据一致性 | ||
| 198 | + * | ||
| 199 | + * @return 操作结果 | ||
| 200 | + */ | ||
| 201 | + @Operation(summary = "刷新字典缓存", description = "刷新Redis字典缓存以保持数据一致性") | ||
| 202 | + @PostMapping("/refreshCache") | ||
| 203 | + @PreAuthorize("hasAuthority('sys:dict:edit')") | ||
| 204 | + public ApiRes<Void> refreshCache() { | ||
| 205 | + try { | ||
| 206 | + // 调用字典值转换器的刷新方法 | ||
| 207 | + com.apple.erp.util.DictValueConverter.refreshCache(); | ||
| 208 | + return ApiRes.success("字典缓存刷新成功", null); | ||
| 209 | + } catch (Exception e) { | ||
| 210 | + return ApiRes.error("刷新字典缓存失败: " + e.getMessage()); | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + /** | ||
| 196 | * 转换SysDictItem为DictItemRes | 215 | * 转换SysDictItem为DictItemRes |
| 197 | * | 216 | * |
| 198 | * @param dictItem 字典项实体 | 217 | * @param dictItem 字典项实体 | ... | ... |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import javax.validation.constraints.NotBlank; | ||
| 7 | +import javax.validation.constraints.NotNull; | ||
| 8 | +import java.time.LocalDateTime; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 异常工单新增请求DTO | ||
| 12 | + * | ||
| 13 | + * @author Apple ERP System | ||
| 14 | + * @since 2025-01-27 | ||
| 15 | + */ | ||
| 16 | +@Data | ||
| 17 | +@Schema(description = "异常工单新增请求") | ||
| 18 | +public class ExceptionWorkorderAddReq { | ||
| 19 | + | ||
| 20 | + @NotBlank(message = "工单编号不能为空") | ||
| 21 | + @Schema(description = "工单编号", required = true) | ||
| 22 | + private String workorderNo; | ||
| 23 | + | ||
| 24 | + @Schema(description = "关联订单编号") | ||
| 25 | + private String orderNo; | ||
| 26 | + | ||
| 27 | + @Schema(description = "经销商编码") | ||
| 28 | + private String dealerCode; | ||
| 29 | + | ||
| 30 | + @Schema(description = "经销商名称") | ||
| 31 | + private String dealerName; | ||
| 32 | + | ||
| 33 | + @NotNull(message = "异常类型不能为空") | ||
| 34 | + @Schema(description = "异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)", required = true) | ||
| 35 | + private Integer exceptionType; | ||
| 36 | + | ||
| 37 | + @NotNull(message = "严重程度不能为空") | ||
| 38 | + @Schema(description = "严重程度(1-高/2-中/3-低)", required = true) | ||
| 39 | + private Integer severityLevel; | ||
| 40 | + | ||
| 41 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)") | ||
| 42 | + private Integer workorderStatus = 1; | ||
| 43 | + | ||
| 44 | + @Schema(description = "预计处理完成时间") | ||
| 45 | + private LocalDateTime expectCompleteTime; | ||
| 46 | + | ||
| 47 | + @Schema(description = "处理人") | ||
| 48 | + private String handlerUser; | ||
| 49 | + | ||
| 50 | + @Schema(description = "异常描述") | ||
| 51 | + private String exceptionDesc; | ||
| 52 | + | ||
| 53 | + @Schema(description = "处理建议") | ||
| 54 | + private String handleSuggest; | ||
| 55 | + | ||
| 56 | + @Schema(description = "数据来源") | ||
| 57 | + private String dataSource; | ||
| 58 | +} |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 异常工单处理日志响应DTO | ||
| 11 | + * | ||
| 12 | + * @author Apple ERP System | ||
| 13 | + * @since 2025-01-27 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@Schema(description = "异常工单处理日志响应") | ||
| 17 | +public class ExceptionWorkorderLogRes { | ||
| 18 | + | ||
| 19 | + @Schema(description = "日志ID") | ||
| 20 | + private Long logId; | ||
| 21 | + | ||
| 22 | + @Schema(description = "关联工单ID") | ||
| 23 | + private Long workorderId; | ||
| 24 | + | ||
| 25 | + @Schema(description = "关联工单编号") | ||
| 26 | + private String workorderNo; | ||
| 27 | + | ||
| 28 | + @Schema(description = "处理人") | ||
| 29 | + private String handleUser; | ||
| 30 | + | ||
| 31 | + @Schema(description = "处理时间") | ||
| 32 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
| 33 | + private LocalDateTime handleTime; | ||
| 34 | + | ||
| 35 | + @Schema(description = "处理前状态") | ||
| 36 | + private Integer beforeStatus; | ||
| 37 | + | ||
| 38 | + @Schema(description = "处理前状态名称") | ||
| 39 | + private String beforeStatusName; | ||
| 40 | + | ||
| 41 | + @Schema(description = "处理后状态") | ||
| 42 | + private Integer afterStatus; | ||
| 43 | + | ||
| 44 | + @Schema(description = "处理后状态名称") | ||
| 45 | + private String afterStatusName; | ||
| 46 | + | ||
| 47 | + @Schema(description = "处理意见") | ||
| 48 | + private String handleOpinion; | ||
| 49 | + | ||
| 50 | + @Schema(description = "附件URL") | ||
| 51 | + private String attachUrl; | ||
| 52 | + | ||
| 53 | + @Schema(description = "创建者") | ||
| 54 | + private String createBy; | ||
| 55 | + | ||
| 56 | + @Schema(description = "创建时间") | ||
| 57 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
| 58 | + private LocalDateTime createTime; | ||
| 59 | +} |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 异常工单查询请求DTO | ||
| 10 | + * | ||
| 11 | + * @author Apple ERP System | ||
| 12 | + * @since 2025-01-27 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +@Schema(description = "异常工单查询请求") | ||
| 16 | +public class ExceptionWorkorderQueryReq { | ||
| 17 | + | ||
| 18 | + @Schema(description = "工单编号") | ||
| 19 | + private String workorderNo; | ||
| 20 | + | ||
| 21 | + @Schema(description = "关联订单编号") | ||
| 22 | + private String orderNo; | ||
| 23 | + | ||
| 24 | + @Schema(description = "经销商编码") | ||
| 25 | + private String dealerCode; | ||
| 26 | + | ||
| 27 | + @Schema(description = "经销商名称") | ||
| 28 | + private String dealerName; | ||
| 29 | + | ||
| 30 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)") | ||
| 31 | + private Integer workorderStatus; | ||
| 32 | + | ||
| 33 | + @Schema(description = "异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)") | ||
| 34 | + private Integer exceptionType; | ||
| 35 | + | ||
| 36 | + @Schema(description = "严重程度(1-高/2-中/3-低)") | ||
| 37 | + private Integer severityLevel; | ||
| 38 | + | ||
| 39 | + @Schema(description = "处理人") | ||
| 40 | + private String handlerUser; | ||
| 41 | + | ||
| 42 | + @Schema(description = "开始时间") | ||
| 43 | + private LocalDateTime startTime; | ||
| 44 | + | ||
| 45 | + @Schema(description = "结束时间") | ||
| 46 | + private LocalDateTime endTime; | ||
| 47 | + | ||
| 48 | + @Schema(description = "页码") | ||
| 49 | + private Integer pageNum = 1; | ||
| 50 | + | ||
| 51 | + @Schema(description = "每页大小") | ||
| 52 | + private Integer pageSize = 10; | ||
| 53 | +} |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 异常工单响应DTO | ||
| 12 | + * | ||
| 13 | + * @author Apple ERP System | ||
| 14 | + * @since 2025-01-27 | ||
| 15 | + */ | ||
| 16 | +@Data | ||
| 17 | +@Schema(description = "异常工单响应") | ||
| 18 | +public class ExceptionWorkorderRes { | ||
| 19 | + | ||
| 20 | + @Schema(description = "工单ID") | ||
| 21 | + private Long workorderId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "工单编号") | ||
| 24 | + private String workorderNo; | ||
| 25 | + | ||
| 26 | + @Schema(description = "关联订单编号") | ||
| 27 | + private String orderNo; | ||
| 28 | + | ||
| 29 | + @Schema(description = "经销商编码") | ||
| 30 | + private String dealerCode; | ||
| 31 | + | ||
| 32 | + @Schema(description = "经销商名称") | ||
| 33 | + private String dealerName; | ||
| 34 | + | ||
| 35 | + @Schema(description = "异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)") | ||
| 36 | + private Integer exceptionType; | ||
| 37 | + | ||
| 38 | + @Schema(description = "异常类型名称") | ||
| 39 | + private String exceptionTypeName; | ||
| 40 | + | ||
| 41 | + @Schema(description = "严重程度(1-高/2-中/3-低)") | ||
| 42 | + private Integer severityLevel; | ||
| 43 | + | ||
| 44 | + @Schema(description = "严重程度名称") | ||
| 45 | + private String severityLevelName; | ||
| 46 | + | ||
| 47 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)") | ||
| 48 | + private Integer workorderStatus; | ||
| 49 | + | ||
| 50 | + @Schema(description = "工单状态名称") | ||
| 51 | + private String workorderStatusName; | ||
| 52 | + | ||
| 53 | + @Schema(description = "工单创建时间") | ||
| 54 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
| 55 | + private LocalDateTime createTime; | ||
| 56 | + | ||
| 57 | + @Schema(description = "预计处理完成时间") | ||
| 58 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
| 59 | + private LocalDateTime expectCompleteTime; | ||
| 60 | + | ||
| 61 | + @Schema(description = "处理人") | ||
| 62 | + private String handlerUser; | ||
| 63 | + | ||
| 64 | + @Schema(description = "异常描述") | ||
| 65 | + private String exceptionDesc; | ||
| 66 | + | ||
| 67 | + @Schema(description = "处理建议") | ||
| 68 | + private String handleSuggest; | ||
| 69 | + | ||
| 70 | + @Schema(description = "数据来源") | ||
| 71 | + private String dataSource; | ||
| 72 | + | ||
| 73 | + @Schema(description = "创建者") | ||
| 74 | + private String createBy; | ||
| 75 | + | ||
| 76 | + @Schema(description = "更新者") | ||
| 77 | + private String updateBy; | ||
| 78 | + | ||
| 79 | + @Schema(description = "更新时间") | ||
| 80 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
| 81 | + private LocalDateTime updateTime; | ||
| 82 | + | ||
| 83 | + @Schema(description = "处理日志列表") | ||
| 84 | + private List<ExceptionWorkorderLogRes> workorderLogs; | ||
| 85 | +} |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import javax.validation.constraints.NotNull; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 异常工单状态更新请求DTO | ||
| 10 | + * | ||
| 11 | + * @author Apple ERP System | ||
| 12 | + * @since 2025-01-27 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +@Schema(description = "异常工单状态更新请求") | ||
| 16 | +public class ExceptionWorkorderStatusUpdateReq { | ||
| 17 | + | ||
| 18 | + @NotNull(message = "工单ID不能为空") | ||
| 19 | + @Schema(description = "工单ID", required = true) | ||
| 20 | + private Long workorderId; | ||
| 21 | + | ||
| 22 | + @NotNull(message = "工单状态不能为空") | ||
| 23 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)", required = true) | ||
| 24 | + private Integer workorderStatus; | ||
| 25 | + | ||
| 26 | + @Schema(description = "处理人") | ||
| 27 | + private String handlerUser; | ||
| 28 | + | ||
| 29 | + @Schema(description = "处理意见") | ||
| 30 | + private String handleOpinion; | ||
| 31 | + | ||
| 32 | + @Schema(description = "附件URL") | ||
| 33 | + private String attachUrl; | ||
| 34 | +} |
| 1 | +package com.apple.erp.dto; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import javax.validation.constraints.NotNull; | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 异常工单更新请求DTO | ||
| 11 | + * | ||
| 12 | + * @author Apple ERP System | ||
| 13 | + * @since 2025-01-27 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@Schema(description = "异常工单更新请求") | ||
| 17 | +public class ExceptionWorkorderUpdateReq { | ||
| 18 | + | ||
| 19 | + @NotNull(message = "工单ID不能为空") | ||
| 20 | + @Schema(description = "工单ID", required = true) | ||
| 21 | + private Long workorderId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "工单编号") | ||
| 24 | + private String workorderNo; | ||
| 25 | + | ||
| 26 | + @Schema(description = "关联订单编号") | ||
| 27 | + private String orderNo; | ||
| 28 | + | ||
| 29 | + @Schema(description = "经销商编码") | ||
| 30 | + private String dealerCode; | ||
| 31 | + | ||
| 32 | + @Schema(description = "经销商名称") | ||
| 33 | + private String dealerName; | ||
| 34 | + | ||
| 35 | + @Schema(description = "异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)") | ||
| 36 | + private Integer exceptionType; | ||
| 37 | + | ||
| 38 | + @Schema(description = "严重程度(1-高/2-中/3-低)") | ||
| 39 | + private Integer severityLevel; | ||
| 40 | + | ||
| 41 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)") | ||
| 42 | + private Integer workorderStatus; | ||
| 43 | + | ||
| 44 | + @Schema(description = "预计处理完成时间") | ||
| 45 | + private LocalDateTime expectCompleteTime; | ||
| 46 | + | ||
| 47 | + @Schema(description = "处理人") | ||
| 48 | + private String handlerUser; | ||
| 49 | + | ||
| 50 | + @Schema(description = "异常描述") | ||
| 51 | + private String exceptionDesc; | ||
| 52 | + | ||
| 53 | + @Schema(description = "处理建议") | ||
| 54 | + private String handleSuggest; | ||
| 55 | + | ||
| 56 | + @Schema(description = "数据来源") | ||
| 57 | + private String dataSource; | ||
| 58 | +} |
| ... | @@ -58,6 +58,36 @@ public class RebateQueryReq { | ... | @@ -58,6 +58,36 @@ public class RebateQueryReq { |
| 58 | private String rebateEndDate; | 58 | private String rebateEndDate; |
| 59 | 59 | ||
| 60 | /** | 60 | /** |
| 61 | + * 审核状态 | ||
| 62 | + */ | ||
| 63 | + private Integer auditStatus; | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 数据来源 | ||
| 67 | + */ | ||
| 68 | + private String dataSource; | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 开始日期 | ||
| 72 | + */ | ||
| 73 | + private String startDate; | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * 结束日期 | ||
| 77 | + */ | ||
| 78 | + private String endDate; | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 最小金额 | ||
| 82 | + */ | ||
| 83 | + private java.math.BigDecimal minAmount; | ||
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * 最大金额 | ||
| 87 | + */ | ||
| 88 | + private java.math.BigDecimal maxAmount; | ||
| 89 | + | ||
| 90 | + /** | ||
| 61 | * 页码 | 91 | * 页码 |
| 62 | */ | 92 | */ |
| 63 | private Integer pageNum = 1; | 93 | private Integer pageNum = 1; | ... | ... |
| ... | @@ -5,6 +5,7 @@ import lombok.Data; | ... | @@ -5,6 +5,7 @@ import lombok.Data; |
| 5 | import org.springframework.security.core.GrantedAuthority; | 5 | import org.springframework.security.core.GrantedAuthority; |
| 6 | 6 | ||
| 7 | import java.util.Collection; | 7 | import java.util.Collection; |
| 8 | +import java.util.List; | ||
| 8 | 9 | ||
| 9 | /** | 10 | /** |
| 10 | * 用户信息响应对象 | 11 | * 用户信息响应对象 |
| ... | @@ -20,6 +21,12 @@ public class UserInfoRes { | ... | @@ -20,6 +21,12 @@ public class UserInfoRes { |
| 20 | @Schema(description = "用户名", example = "admin") | 21 | @Schema(description = "用户名", example = "admin") |
| 21 | private String username; | 22 | private String username; |
| 22 | 23 | ||
| 24 | + @Schema(description = "真实姓名", example = "管理员") | ||
| 25 | + private String realName; | ||
| 26 | + | ||
| 27 | + @Schema(description = "用户角色列表") | ||
| 28 | + private List<RoleRes> roles; | ||
| 29 | + | ||
| 23 | @Schema(description = "用户权限列表") | 30 | @Schema(description = "用户权限列表") |
| 24 | private Collection<? extends GrantedAuthority> authorities; | 31 | private Collection<? extends GrantedAuthority> authorities; |
| 25 | 32 | ||
| ... | @@ -29,4 +36,11 @@ public class UserInfoRes { | ... | @@ -29,4 +36,11 @@ public class UserInfoRes { |
| 29 | this.username = username; | 36 | this.username = username; |
| 30 | this.authorities = authorities; | 37 | this.authorities = authorities; |
| 31 | } | 38 | } |
| 39 | + | ||
| 40 | + public UserInfoRes(String username, String realName, List<RoleRes> roles, Collection<? extends GrantedAuthority> authorities) { | ||
| 41 | + this.username = username; | ||
| 42 | + this.realName = realName; | ||
| 43 | + this.roles = roles; | ||
| 44 | + this.authorities = authorities; | ||
| 45 | + } | ||
| 32 | } | 46 | } | ... | ... |
| 1 | +package com.apple.erp.entity; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.annotation.IdType; | ||
| 4 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.EqualsAndHashCode; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 异常工单表实体类 | ||
| 14 | + * | ||
| 15 | + * @author Apple ERP System | ||
| 16 | + * @since 2025-01-27 | ||
| 17 | + */ | ||
| 18 | +@Data | ||
| 19 | +@EqualsAndHashCode(callSuper = false) | ||
| 20 | +@TableName("t_exception_workorder") | ||
| 21 | +@Schema(description = "异常工单表") | ||
| 22 | +public class ExceptionWorkorder { | ||
| 23 | + | ||
| 24 | + @TableId(value = "workorder_id", type = IdType.AUTO) | ||
| 25 | + @Schema(description = "工单ID") | ||
| 26 | + private Long workorderId; | ||
| 27 | + | ||
| 28 | + @Schema(description = "工单编号") | ||
| 29 | + private String workorderNo; | ||
| 30 | + | ||
| 31 | + @Schema(description = "关联订单编号") | ||
| 32 | + private String orderNo; | ||
| 33 | + | ||
| 34 | + @Schema(description = "经销商编码") | ||
| 35 | + private String dealerCode; | ||
| 36 | + | ||
| 37 | + @Schema(description = "经销商名称") | ||
| 38 | + private String dealerName; | ||
| 39 | + | ||
| 40 | + @Schema(description = "异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)") | ||
| 41 | + private Integer exceptionType; | ||
| 42 | + | ||
| 43 | + @Schema(description = "严重程度(1-高/2-中/3-低)") | ||
| 44 | + private Integer severityLevel; | ||
| 45 | + | ||
| 46 | + @Schema(description = "工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)") | ||
| 47 | + private Integer workorderStatus; | ||
| 48 | + | ||
| 49 | + @Schema(description = "工单创建时间") | ||
| 50 | + private LocalDateTime createTime; | ||
| 51 | + | ||
| 52 | + @Schema(description = "预计处理完成时间") | ||
| 53 | + private LocalDateTime expectCompleteTime; | ||
| 54 | + | ||
| 55 | + @Schema(description = "处理人") | ||
| 56 | + private String handlerUser; | ||
| 57 | + | ||
| 58 | + @Schema(description = "异常描述") | ||
| 59 | + private String exceptionDesc; | ||
| 60 | + | ||
| 61 | + @Schema(description = "处理建议") | ||
| 62 | + private String handleSuggest; | ||
| 63 | + | ||
| 64 | + @Schema(description = "数据来源") | ||
| 65 | + private String dataSource; | ||
| 66 | + | ||
| 67 | + @Schema(description = "创建者") | ||
| 68 | + private String createBy; | ||
| 69 | + | ||
| 70 | + @Schema(description = "更新者") | ||
| 71 | + private String updateBy; | ||
| 72 | + | ||
| 73 | + @Schema(description = "更新时间") | ||
| 74 | + private LocalDateTime updateTime; | ||
| 75 | + | ||
| 76 | + @Schema(description = "删除标志(0代表存在 2代表删除)") | ||
| 77 | + private String delFlag; | ||
| 78 | +} |
| 1 | +package com.apple.erp.entity; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.annotation.IdType; | ||
| 4 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.EqualsAndHashCode; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 异常工单处理日志表实体类 | ||
| 14 | + * | ||
| 15 | + * @author Apple ERP System | ||
| 16 | + * @since 2025-01-27 | ||
| 17 | + */ | ||
| 18 | +@Data | ||
| 19 | +@EqualsAndHashCode(callSuper = false) | ||
| 20 | +@TableName("t_exception_workorder_log") | ||
| 21 | +@Schema(description = "异常工单处理日志表") | ||
| 22 | +public class ExceptionWorkorderLog { | ||
| 23 | + | ||
| 24 | + @TableId(value = "log_id", type = IdType.AUTO) | ||
| 25 | + @Schema(description = "日志ID") | ||
| 26 | + private Long logId; | ||
| 27 | + | ||
| 28 | + @Schema(description = "关联工单ID") | ||
| 29 | + private Long workorderId; | ||
| 30 | + | ||
| 31 | + @Schema(description = "关联工单编号") | ||
| 32 | + private String workorderNo; | ||
| 33 | + | ||
| 34 | + @Schema(description = "处理人") | ||
| 35 | + private String handleUser; | ||
| 36 | + | ||
| 37 | + @Schema(description = "处理时间") | ||
| 38 | + private LocalDateTime handleTime; | ||
| 39 | + | ||
| 40 | + @Schema(description = "处理前状态") | ||
| 41 | + private Integer beforeStatus; | ||
| 42 | + | ||
| 43 | + @Schema(description = "处理后状态") | ||
| 44 | + private Integer afterStatus; | ||
| 45 | + | ||
| 46 | + @Schema(description = "处理意见") | ||
| 47 | + private String handleOpinion; | ||
| 48 | + | ||
| 49 | + @Schema(description = "附件URL") | ||
| 50 | + private String attachUrl; | ||
| 51 | + | ||
| 52 | + @Schema(description = "创建者") | ||
| 53 | + private String createBy; | ||
| 54 | + | ||
| 55 | + @Schema(description = "创建时间") | ||
| 56 | + private LocalDateTime createTime; | ||
| 57 | + | ||
| 58 | + @Schema(description = "更新者") | ||
| 59 | + private String updateBy; | ||
| 60 | + | ||
| 61 | + @Schema(description = "更新时间") | ||
| 62 | + private LocalDateTime updateTime; | ||
| 63 | + | ||
| 64 | + @Schema(description = "删除标志(0代表存在 2代表删除)") | ||
| 65 | + private String delFlag; | ||
| 66 | +} |
| 1 | +package com.apple.erp.mapper; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.dto.ExceptionWorkorderLogRes; | ||
| 4 | +import com.apple.erp.entity.ExceptionWorkorderLog; | ||
| 5 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 6 | +import org.apache.ibatis.annotations.Mapper; | ||
| 7 | +import org.apache.ibatis.annotations.Param; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 异常工单处理日志Mapper接口 | ||
| 13 | + * | ||
| 14 | + * @author Apple ERP System | ||
| 15 | + * @since 2025-01-27 | ||
| 16 | + */ | ||
| 17 | +@Mapper | ||
| 18 | +public interface ExceptionWorkorderLogMapper extends BaseMapper<ExceptionWorkorderLog> { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 根据工单ID获取处理日志列表 | ||
| 22 | + * | ||
| 23 | + * @param workorderId 工单ID | ||
| 24 | + * @return 处理日志列表 | ||
| 25 | + */ | ||
| 26 | + List<ExceptionWorkorderLogRes> selectWorkorderLogsByWorkorderId(@Param("workorderId") Long workorderId); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 根据工单ID列表批量获取处理日志 | ||
| 30 | + * | ||
| 31 | + * @param workorderIds 工单ID列表 | ||
| 32 | + * @return 处理日志列表 | ||
| 33 | + */ | ||
| 34 | + List<ExceptionWorkorderLogRes> selectWorkorderLogsByWorkorderIds(@Param("workorderIds") List<Long> workorderIds); | ||
| 35 | +} |
| 1 | +package com.apple.erp.mapper; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.dto.ExceptionWorkorderQueryReq; | ||
| 4 | +import com.apple.erp.dto.ExceptionWorkorderRes; | ||
| 5 | +import com.apple.erp.entity.ExceptionWorkorder; | ||
| 6 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | +import org.apache.ibatis.annotations.Param; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 异常工单Mapper接口 | ||
| 15 | + * | ||
| 16 | + * @author Apple ERP System | ||
| 17 | + * @since 2025-01-27 | ||
| 18 | + */ | ||
| 19 | +@Mapper | ||
| 20 | +public interface ExceptionWorkorderMapper extends BaseMapper<ExceptionWorkorder> { | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 分页查询异常工单列表 | ||
| 24 | + * | ||
| 25 | + * @param page 分页参数 | ||
| 26 | + * @param queryReq 查询条件 | ||
| 27 | + * @return 异常工单列表 | ||
| 28 | + */ | ||
| 29 | + Page<ExceptionWorkorderRes> selectExceptionWorkorderPage(Page<ExceptionWorkorderRes> page, @Param("query") ExceptionWorkorderQueryReq queryReq); | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 根据工单ID获取异常工单详情 | ||
| 33 | + * | ||
| 34 | + * @param workorderId 工单ID | ||
| 35 | + * @return 异常工单详情 | ||
| 36 | + */ | ||
| 37 | + ExceptionWorkorderRes selectExceptionWorkorderDetail(@Param("workorderId") Long workorderId); | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * 获取异常工单统计信息 | ||
| 41 | + * | ||
| 42 | + * @return 统计信息 | ||
| 43 | + */ | ||
| 44 | + List<ExceptionWorkorderRes> selectExceptionWorkorderStats(); | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 批量更新工单状态 | ||
| 48 | + * | ||
| 49 | + * @param workorderIds 工单ID列表 | ||
| 50 | + * @param workorderStatus 工单状态 | ||
| 51 | + * @param handlerUser 处理人 | ||
| 52 | + * @return 更新数量 | ||
| 53 | + */ | ||
| 54 | + int batchUpdateWorkorderStatus(@Param("workorderIds") List<Long> workorderIds, | ||
| 55 | + @Param("workorderStatus") Integer workorderStatus, | ||
| 56 | + @Param("handlerUser") String handlerUser); | ||
| 57 | +} |
| 1 | +package com.apple.erp.service; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.config.ExportConfig; | ||
| 4 | +import com.apple.erp.util.GenericExcelExportUtil; | ||
| 5 | +import org.springframework.stereotype.Service; | ||
| 6 | + | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | +import java.time.format.DateTimeFormatter; | ||
| 9 | +import java.util.List; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * Excel导出服务类 | ||
| 14 | + * 提供统一的导出接口,各模块可独立使用 | ||
| 15 | + * | ||
| 16 | + * @author Apple ERP System | ||
| 17 | + * @since 2025-01-01 | ||
| 18 | + */ | ||
| 19 | +@Service | ||
| 20 | +public class ExcelExportService { | ||
| 21 | + | ||
| 22 | + private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"); | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 导出订单数据 | ||
| 26 | + */ | ||
| 27 | + public org.springframework.http.ResponseEntity<byte[]> exportOrders(List<?> data) { | ||
| 28 | + Map<String, String[]> config = ExportConfig.ORDER_EXPORT_CONFIG; | ||
| 29 | + String fileName = "订单数据_" + LocalDateTime.now().format(TIMESTAMP_FORMATTER); | ||
| 30 | + return GenericExcelExportUtil.exportToExcel(data, config.get("headers"), config.get("fields"), fileName); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 导出出库数据 | ||
| 35 | + */ | ||
| 36 | + public org.springframework.http.ResponseEntity<byte[]> exportDeliveries(List<?> data) { | ||
| 37 | + Map<String, String[]> config = ExportConfig.DELIVERY_EXPORT_CONFIG; | ||
| 38 | + String fileName = "出库数据_" + LocalDateTime.now().format(TIMESTAMP_FORMATTER); | ||
| 39 | + return GenericExcelExportUtil.exportToExcel(data, config.get("headers"), config.get("fields"), fileName); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 导出发票数据 | ||
| 44 | + */ | ||
| 45 | + public org.springframework.http.ResponseEntity<byte[]> exportInvoices(List<?> data) { | ||
| 46 | + Map<String, String[]> config = ExportConfig.INVOICE_EXPORT_CONFIG; | ||
| 47 | + String fileName = "发票数据_" + LocalDateTime.now().format(TIMESTAMP_FORMATTER); | ||
| 48 | + return GenericExcelExportUtil.exportToExcel(data, config.get("headers"), config.get("fields"), fileName); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * 导出返利数据 | ||
| 53 | + */ | ||
| 54 | + public org.springframework.http.ResponseEntity<byte[]> exportRebates(List<?> data) { | ||
| 55 | + Map<String, String[]> config = ExportConfig.REBATE_EXPORT_CONFIG; | ||
| 56 | + String fileName = "返利数据_" + LocalDateTime.now().format(TIMESTAMP_FORMATTER); | ||
| 57 | + return GenericExcelExportUtil.exportToExcel(data, config.get("headers"), config.get("fields"), fileName); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 导出异常工单数据 | ||
| 62 | + */ | ||
| 63 | + public org.springframework.http.ResponseEntity<byte[]> exportExceptionWorkorders(List<?> data) { | ||
| 64 | + Map<String, String[]> config = ExportConfig.EXCEPTION_WORKORDER_EXPORT_CONFIG; | ||
| 65 | + String fileName = "异常工单数据_" + LocalDateTime.now().format(TIMESTAMP_FORMATTER); | ||
| 66 | + return GenericExcelExportUtil.exportToExcel(data, config.get("headers"), config.get("fields"), fileName); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * 通用导出方法 | ||
| 71 | + * 支持自定义表头和字段映射 | ||
| 72 | + */ | ||
| 73 | + public org.springframework.http.ResponseEntity<byte[]> exportCustom(List<?> data, String[] headers, String[] fieldNames, String fileName) { | ||
| 74 | + return GenericExcelExportUtil.exportToExcel(data, headers, fieldNames, fileName); | ||
| 75 | + } | ||
| 76 | +} |
| 1 | +package com.apple.erp.service; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.dto.ExceptionWorkorderAddReq; | ||
| 4 | +import com.apple.erp.dto.ExceptionWorkorderQueryReq; | ||
| 5 | +import com.apple.erp.dto.ExceptionWorkorderRes; | ||
| 6 | +import com.apple.erp.dto.ExceptionWorkorderStatusUpdateReq; | ||
| 7 | +import com.apple.erp.dto.ExceptionWorkorderUpdateReq; | ||
| 8 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 9 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 10 | +import com.apple.erp.entity.ExceptionWorkorder; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 异常工单Service接口 | ||
| 16 | + * | ||
| 17 | + * @author Apple ERP System | ||
| 18 | + * @since 2025-01-27 | ||
| 19 | + */ | ||
| 20 | +public interface ExceptionWorkorderService extends IService<ExceptionWorkorder> { | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 分页查询异常工单列表 | ||
| 24 | + * | ||
| 25 | + * @param queryReq 查询条件 | ||
| 26 | + * @return 异常工单列表(带分页信息) | ||
| 27 | + */ | ||
| 28 | + Page<ExceptionWorkorderRes> getExceptionWorkorderList(ExceptionWorkorderQueryReq queryReq); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 获取异常工单详情 | ||
| 32 | + * | ||
| 33 | + * @param workorderId 工单ID | ||
| 34 | + * @return 异常工单详情(包含处理日志) | ||
| 35 | + */ | ||
| 36 | + ExceptionWorkorderRes getExceptionWorkorderDetail(Long workorderId); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 新增异常工单 | ||
| 40 | + * | ||
| 41 | + * @param addReq 异常工单新增请求 | ||
| 42 | + * @return 是否成功 | ||
| 43 | + */ | ||
| 44 | + boolean addExceptionWorkorder(ExceptionWorkorderAddReq addReq); | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 更新异常工单 | ||
| 48 | + * | ||
| 49 | + * @param updateReq 异常工单更新请求 | ||
| 50 | + * @return 是否成功 | ||
| 51 | + */ | ||
| 52 | + boolean updateExceptionWorkorder(ExceptionWorkorderUpdateReq updateReq); | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * 更新工单状态 | ||
| 56 | + * | ||
| 57 | + * @param statusUpdateReq 状态更新请求 | ||
| 58 | + * @return 是否成功 | ||
| 59 | + */ | ||
| 60 | + boolean updateWorkorderStatus(ExceptionWorkorderStatusUpdateReq statusUpdateReq); | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * 删除异常工单 | ||
| 64 | + * | ||
| 65 | + * @param workorderId 工单ID | ||
| 66 | + * @return 是否成功 | ||
| 67 | + */ | ||
| 68 | + boolean deleteExceptionWorkorder(Long workorderId); | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 批量删除异常工单 | ||
| 72 | + * | ||
| 73 | + * @param workorderIds 工单ID列表 | ||
| 74 | + * @return 是否成功 | ||
| 75 | + */ | ||
| 76 | + boolean batchDeleteExceptionWorkorders(List<Long> workorderIds); | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 批量更新工单状态 | ||
| 80 | + * | ||
| 81 | + * @param workorderIds 工单ID列表 | ||
| 82 | + * @param workorderStatus 工单状态 | ||
| 83 | + * @param handlerUser 处理人 | ||
| 84 | + * @return 是否成功 | ||
| 85 | + */ | ||
| 86 | + boolean batchUpdateWorkorderStatus(List<Long> workorderIds, Integer workorderStatus, String handlerUser); | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * 获取异常工单统计信息 | ||
| 90 | + * | ||
| 91 | + * @return 统计信息 | ||
| 92 | + */ | ||
| 93 | + List<ExceptionWorkorderRes> getExceptionWorkorderStats(); | ||
| 94 | +} |
| 1 | +package com.apple.erp.service.impl; | ||
| 2 | + | ||
| 3 | +import com.apple.erp.dto.ExceptionWorkorderAddReq; | ||
| 4 | +import com.apple.erp.dto.ExceptionWorkorderLogRes; | ||
| 5 | +import com.apple.erp.dto.ExceptionWorkorderQueryReq; | ||
| 6 | +import com.apple.erp.dto.ExceptionWorkorderRes; | ||
| 7 | +import com.apple.erp.dto.ExceptionWorkorderStatusUpdateReq; | ||
| 8 | +import com.apple.erp.dto.ExceptionWorkorderUpdateReq; | ||
| 9 | +import com.apple.erp.entity.ExceptionWorkorder; | ||
| 10 | +import com.apple.erp.entity.ExceptionWorkorderLog; | ||
| 11 | +import com.apple.erp.mapper.ExceptionWorkorderLogMapper; | ||
| 12 | +import com.apple.erp.mapper.ExceptionWorkorderMapper; | ||
| 13 | +import com.apple.erp.service.ExceptionWorkorderService; | ||
| 14 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
| 15 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 16 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 17 | +import org.springframework.beans.BeanUtils; | ||
| 18 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 19 | +import org.springframework.stereotype.Service; | ||
| 20 | +import org.springframework.transaction.annotation.Transactional; | ||
| 21 | +import org.springframework.util.StringUtils; | ||
| 22 | + | ||
| 23 | +import java.time.LocalDateTime; | ||
| 24 | +import java.util.List; | ||
| 25 | +import java.util.stream.Collectors; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * 异常工单Service实现类 | ||
| 29 | + * | ||
| 30 | + * @author Apple ERP System | ||
| 31 | + * @since 2025-01-27 | ||
| 32 | + */ | ||
| 33 | +@Service | ||
| 34 | +public class ExceptionWorkorderServiceImpl extends ServiceImpl<ExceptionWorkorderMapper, ExceptionWorkorder> implements ExceptionWorkorderService { | ||
| 35 | + | ||
| 36 | + @Autowired | ||
| 37 | + private ExceptionWorkorderMapper exceptionWorkorderMapper; | ||
| 38 | + | ||
| 39 | + @Autowired | ||
| 40 | + private ExceptionWorkorderLogMapper exceptionWorkorderLogMapper; | ||
| 41 | + | ||
| 42 | + @Override | ||
| 43 | + public Page<ExceptionWorkorderRes> getExceptionWorkorderList(ExceptionWorkorderQueryReq queryReq) { | ||
| 44 | + Page<ExceptionWorkorderRes> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize()); | ||
| 45 | + return exceptionWorkorderMapper.selectExceptionWorkorderPage(page, queryReq); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public ExceptionWorkorderRes getExceptionWorkorderDetail(Long workorderId) { | ||
| 50 | + ExceptionWorkorderRes workorderRes = exceptionWorkorderMapper.selectExceptionWorkorderDetail(workorderId); | ||
| 51 | + if (workorderRes != null) { | ||
| 52 | + // 获取处理日志 | ||
| 53 | + List<ExceptionWorkorderLogRes> logs = exceptionWorkorderLogMapper.selectWorkorderLogsByWorkorderId(workorderId); | ||
| 54 | + workorderRes.setWorkorderLogs(logs); | ||
| 55 | + } | ||
| 56 | + return workorderRes; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + @Transactional | ||
| 61 | + public boolean addExceptionWorkorder(ExceptionWorkorderAddReq addReq) { | ||
| 62 | + ExceptionWorkorder workorder = new ExceptionWorkorder(); | ||
| 63 | + BeanUtils.copyProperties(addReq, workorder); | ||
| 64 | + workorder.setCreateTime(LocalDateTime.now()); | ||
| 65 | + workorder.setDelFlag("0"); | ||
| 66 | + | ||
| 67 | + int result = exceptionWorkorderMapper.insert(workorder); | ||
| 68 | + | ||
| 69 | + // 记录处理日志 | ||
| 70 | + if (result > 0) { | ||
| 71 | + ExceptionWorkorderLog log = new ExceptionWorkorderLog(); | ||
| 72 | + log.setWorkorderId(workorder.getWorkorderId()); | ||
| 73 | + log.setWorkorderNo(workorder.getWorkorderNo()); | ||
| 74 | + log.setHandleUser(addReq.getHandlerUser()); | ||
| 75 | + log.setHandleTime(LocalDateTime.now()); | ||
| 76 | + log.setBeforeStatus(0); | ||
| 77 | + log.setAfterStatus(workorder.getWorkorderStatus()); | ||
| 78 | + log.setHandleOpinion("工单创建"); | ||
| 79 | + log.setCreateTime(LocalDateTime.now()); | ||
| 80 | + log.setDelFlag("0"); | ||
| 81 | + exceptionWorkorderLogMapper.insert(log); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + return result > 0; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + @Override | ||
| 88 | + @Transactional | ||
| 89 | + public boolean updateExceptionWorkorder(ExceptionWorkorderUpdateReq updateReq) { | ||
| 90 | + ExceptionWorkorder workorder = exceptionWorkorderMapper.selectById(updateReq.getWorkorderId()); | ||
| 91 | + if (workorder == null || "2".equals(workorder.getDelFlag())) { | ||
| 92 | + return false; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + BeanUtils.copyProperties(updateReq, workorder); | ||
| 96 | + workorder.setUpdateTime(LocalDateTime.now()); | ||
| 97 | + | ||
| 98 | + return exceptionWorkorderMapper.updateById(workorder) > 0; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Override | ||
| 102 | + @Transactional | ||
| 103 | + public boolean updateWorkorderStatus(ExceptionWorkorderStatusUpdateReq statusUpdateReq) { | ||
| 104 | + ExceptionWorkorder workorder = exceptionWorkorderMapper.selectById(statusUpdateReq.getWorkorderId()); | ||
| 105 | + if (workorder == null || "2".equals(workorder.getDelFlag())) { | ||
| 106 | + return false; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + Integer beforeStatus = workorder.getWorkorderStatus(); | ||
| 110 | + workorder.setWorkorderStatus(statusUpdateReq.getWorkorderStatus()); | ||
| 111 | + workorder.setHandlerUser(statusUpdateReq.getHandlerUser()); | ||
| 112 | + workorder.setUpdateTime(LocalDateTime.now()); | ||
| 113 | + | ||
| 114 | + int result = exceptionWorkorderMapper.updateById(workorder); | ||
| 115 | + | ||
| 116 | + // 记录处理日志 | ||
| 117 | + if (result > 0) { | ||
| 118 | + ExceptionWorkorderLog log = new ExceptionWorkorderLog(); | ||
| 119 | + log.setWorkorderId(workorder.getWorkorderId()); | ||
| 120 | + log.setWorkorderNo(workorder.getWorkorderNo()); | ||
| 121 | + log.setHandleUser(statusUpdateReq.getHandlerUser()); | ||
| 122 | + log.setHandleTime(LocalDateTime.now()); | ||
| 123 | + log.setBeforeStatus(beforeStatus); | ||
| 124 | + log.setAfterStatus(statusUpdateReq.getWorkorderStatus()); | ||
| 125 | + log.setHandleOpinion(statusUpdateReq.getHandleOpinion()); | ||
| 126 | + log.setAttachUrl(statusUpdateReq.getAttachUrl()); | ||
| 127 | + log.setCreateTime(LocalDateTime.now()); | ||
| 128 | + log.setDelFlag("0"); | ||
| 129 | + exceptionWorkorderLogMapper.insert(log); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + return result > 0; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + @Override | ||
| 136 | + @Transactional | ||
| 137 | + public boolean deleteExceptionWorkorder(Long workorderId) { | ||
| 138 | + ExceptionWorkorder workorder = exceptionWorkorderMapper.selectById(workorderId); | ||
| 139 | + if (workorder == null || "2".equals(workorder.getDelFlag())) { | ||
| 140 | + return false; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + workorder.setDelFlag("2"); | ||
| 144 | + workorder.setUpdateTime(LocalDateTime.now()); | ||
| 145 | + | ||
| 146 | + return exceptionWorkorderMapper.updateById(workorder) > 0; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + @Override | ||
| 150 | + @Transactional | ||
| 151 | + public boolean batchDeleteExceptionWorkorders(List<Long> workorderIds) { | ||
| 152 | + if (workorderIds == null || workorderIds.isEmpty()) { | ||
| 153 | + return false; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + ExceptionWorkorder workorder = new ExceptionWorkorder(); | ||
| 157 | + workorder.setDelFlag("2"); | ||
| 158 | + workorder.setUpdateTime(LocalDateTime.now()); | ||
| 159 | + | ||
| 160 | + LambdaQueryWrapper<ExceptionWorkorder> queryWrapper = new LambdaQueryWrapper<>(); | ||
| 161 | + queryWrapper.in(ExceptionWorkorder::getWorkorderId, workorderIds); | ||
| 162 | + queryWrapper.eq(ExceptionWorkorder::getDelFlag, "0"); | ||
| 163 | + | ||
| 164 | + return exceptionWorkorderMapper.update(workorder, queryWrapper) > 0; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @Override | ||
| 168 | + @Transactional | ||
| 169 | + public boolean batchUpdateWorkorderStatus(List<Long> workorderIds, Integer workorderStatus, String handlerUser) { | ||
| 170 | + if (workorderIds == null || workorderIds.isEmpty()) { | ||
| 171 | + return false; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + int result = exceptionWorkorderMapper.batchUpdateWorkorderStatus(workorderIds, workorderStatus, handlerUser); | ||
| 175 | + | ||
| 176 | + // 记录批量处理日志 | ||
| 177 | + if (result > 0) { | ||
| 178 | + for (Long workorderId : workorderIds) { | ||
| 179 | + ExceptionWorkorder workorder = exceptionWorkorderMapper.selectById(workorderId); | ||
| 180 | + if (workorder != null && "0".equals(workorder.getDelFlag())) { | ||
| 181 | + ExceptionWorkorderLog log = new ExceptionWorkorderLog(); | ||
| 182 | + log.setWorkorderId(workorderId); | ||
| 183 | + log.setWorkorderNo(workorder.getWorkorderNo()); | ||
| 184 | + log.setHandleUser(handlerUser); | ||
| 185 | + log.setHandleTime(LocalDateTime.now()); | ||
| 186 | + log.setBeforeStatus(workorder.getWorkorderStatus()); | ||
| 187 | + log.setAfterStatus(workorderStatus); | ||
| 188 | + log.setHandleOpinion("批量状态更新"); | ||
| 189 | + log.setCreateTime(LocalDateTime.now()); | ||
| 190 | + log.setDelFlag("0"); | ||
| 191 | + exceptionWorkorderLogMapper.insert(log); | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + return result > 0; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + @Override | ||
| 200 | + public List<ExceptionWorkorderRes> getExceptionWorkorderStats() { | ||
| 201 | + return exceptionWorkorderMapper.selectExceptionWorkorderStats(); | ||
| 202 | + } | ||
| 203 | +} |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
| 1 | +package com.apple.erp.util; | ||
| 2 | + | ||
| 3 | +import org.apache.poi.ss.usermodel.*; | ||
| 4 | +import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||
| 5 | +import org.springframework.http.HttpHeaders; | ||
| 6 | +import org.springframework.http.HttpStatus; | ||
| 7 | +import org.springframework.http.MediaType; | ||
| 8 | +import org.springframework.http.ResponseEntity; | ||
| 9 | + | ||
| 10 | +import java.io.ByteArrayOutputStream; | ||
| 11 | +import java.io.IOException; | ||
| 12 | +import java.lang.reflect.Field; | ||
| 13 | +import java.time.LocalDateTime; | ||
| 14 | +import java.time.format.DateTimeFormatter; | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 通用Excel导出工具类 | ||
| 19 | + * 支持任意实体类的Excel导出,通过注解配置字段映射 | ||
| 20 | + * | ||
| 21 | + * @author Apple ERP System | ||
| 22 | + * @since 2025-01-01 | ||
| 23 | + */ | ||
| 24 | +public class GenericExcelExportUtil { | ||
| 25 | + | ||
| 26 | + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | ||
| 27 | + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 通用Excel导出方法 | ||
| 31 | + * | ||
| 32 | + * @param data 数据列表 | ||
| 33 | + * @param headers 表头数组 | ||
| 34 | + * @param fieldNames 字段名数组(与表头对应) | ||
| 35 | + * @param fileName 文件名(不含扩展名) | ||
| 36 | + * @return ResponseEntity<byte[]> | ||
| 37 | + */ | ||
| 38 | + public static ResponseEntity<byte[]> exportToExcel(List<?> data, String[] headers, String[] fieldNames, String fileName) { | ||
| 39 | + try (Workbook workbook = new XSSFWorkbook()) { | ||
| 40 | + Sheet sheet = workbook.createSheet("数据导出"); | ||
| 41 | + | ||
| 42 | + // 创建样式 | ||
| 43 | + CellStyle headerStyle = createHeaderStyle(workbook); | ||
| 44 | + CellStyle dataStyle = createDataStyle(workbook); | ||
| 45 | + | ||
| 46 | + // 创建表头 | ||
| 47 | + Row headerRow = sheet.createRow(0); | ||
| 48 | + for (int i = 0; i < headers.length; i++) { | ||
| 49 | + Cell cell = headerRow.createCell(i); | ||
| 50 | + cell.setCellValue(headers[i]); | ||
| 51 | + cell.setCellStyle(headerStyle); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + // 填充数据 | ||
| 55 | + if (data != null && !data.isEmpty()) { | ||
| 56 | + for (int i = 0; i < data.size(); i++) { | ||
| 57 | + Row row = sheet.createRow(i + 1); | ||
| 58 | + Object item = data.get(i); | ||
| 59 | + fillRowData(row, item, fieldNames, dataStyle); | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // 自动调整列宽 | ||
| 64 | + for (int i = 0; i < headers.length; i++) { | ||
| 65 | + sheet.autoSizeColumn(i); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 转换为字节数组 | ||
| 69 | + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
| 70 | + workbook.write(outputStream); | ||
| 71 | + byte[] bytes = outputStream.toByteArray(); | ||
| 72 | + | ||
| 73 | + // 设置响应头 | ||
| 74 | + HttpHeaders httpHeaders = new HttpHeaders(); | ||
| 75 | + httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); | ||
| 76 | + | ||
| 77 | + // 对文件名进行URL编码以支持中文 | ||
| 78 | + String encodedFileName; | ||
| 79 | + try { | ||
| 80 | + encodedFileName = java.net.URLEncoder.encode(fileName + ".xlsx", "UTF-8"); | ||
| 81 | + } catch (Exception e) { | ||
| 82 | + encodedFileName = fileName + ".xlsx"; | ||
| 83 | + } | ||
| 84 | + httpHeaders.set("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName); | ||
| 85 | + httpHeaders.setContentLength(bytes.length); | ||
| 86 | + | ||
| 87 | + return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK); | ||
| 88 | + | ||
| 89 | + } catch (IOException e) { | ||
| 90 | + throw new RuntimeException("Excel导出失败", e); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * 创建表头样式 | ||
| 96 | + */ | ||
| 97 | + private static CellStyle createHeaderStyle(Workbook workbook) { | ||
| 98 | + CellStyle style = workbook.createCellStyle(); | ||
| 99 | + Font font = workbook.createFont(); | ||
| 100 | + font.setBold(true); | ||
| 101 | + font.setFontHeightInPoints((short) 12); | ||
| 102 | + style.setFont(font); | ||
| 103 | + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 104 | + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); | ||
| 105 | + style.setBorderBottom(BorderStyle.THIN); | ||
| 106 | + style.setBorderTop(BorderStyle.THIN); | ||
| 107 | + style.setBorderRight(BorderStyle.THIN); | ||
| 108 | + style.setBorderLeft(BorderStyle.THIN); | ||
| 109 | + style.setAlignment(HorizontalAlignment.CENTER); | ||
| 110 | + style.setVerticalAlignment(VerticalAlignment.CENTER); | ||
| 111 | + return style; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * 创建数据样式 | ||
| 116 | + */ | ||
| 117 | + private static CellStyle createDataStyle(Workbook workbook) { | ||
| 118 | + CellStyle style = workbook.createCellStyle(); | ||
| 119 | + style.setBorderBottom(BorderStyle.THIN); | ||
| 120 | + style.setBorderTop(BorderStyle.THIN); | ||
| 121 | + style.setBorderRight(BorderStyle.THIN); | ||
| 122 | + style.setBorderLeft(BorderStyle.THIN); | ||
| 123 | + style.setVerticalAlignment(VerticalAlignment.CENTER); | ||
| 124 | + return style; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + /** | ||
| 128 | + * 填充行数据 | ||
| 129 | + */ | ||
| 130 | + private static void fillRowData(Row row, Object item, String[] fieldNames, CellStyle dataStyle) { | ||
| 131 | + try { | ||
| 132 | + Class<?> clazz = item.getClass(); | ||
| 133 | + | ||
| 134 | + for (int i = 0; i < fieldNames.length; i++) { | ||
| 135 | + Cell cell = row.createCell(i); | ||
| 136 | + cell.setCellStyle(dataStyle); | ||
| 137 | + | ||
| 138 | + Object value = getFieldValue(clazz, item, fieldNames[i]); | ||
| 139 | + | ||
| 140 | + // 对特定字段进行字典值转换 | ||
| 141 | + String convertedValue = convertDictValue(value, fieldNames[i]); | ||
| 142 | + System.out.println("字段转换: " + fieldNames[i] + " = " + value + " -> " + convertedValue); | ||
| 143 | + if (convertedValue != null && !convertedValue.equals(value != null ? value.toString() : "")) { | ||
| 144 | + // 如果字典转换成功,使用转换后的值 | ||
| 145 | + cell.setCellValue(convertedValue); | ||
| 146 | + } else { | ||
| 147 | + // 如果字典转换失败或没有转换,使用原始值 | ||
| 148 | + setCellValue(cell, value); | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + } catch (Exception e) { | ||
| 152 | + System.out.println("填充行数据失败: " + e.getMessage()); | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * 获取字段值(支持getter方法和直接字段访问) | ||
| 158 | + */ | ||
| 159 | + private static Object getFieldValue(Class<?> clazz, Object item, String fieldName) { | ||
| 160 | + try { | ||
| 161 | + // 首先尝试getter方法 | ||
| 162 | + String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); | ||
| 163 | + try { | ||
| 164 | + return clazz.getMethod(getterName).invoke(item); | ||
| 165 | + } catch (NoSuchMethodException e) { | ||
| 166 | + // 如果getter方法不存在,尝试直接访问字段 | ||
| 167 | + Field field = clazz.getDeclaredField(fieldName); | ||
| 168 | + field.setAccessible(true); | ||
| 169 | + return field.get(item); | ||
| 170 | + } | ||
| 171 | + } catch (Exception e) { | ||
| 172 | + return null; | ||
| 173 | + } | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + /** | ||
| 177 | + * 设置单元格值 | ||
| 178 | + */ | ||
| 179 | + private static void setCellValue(Cell cell, Object value) { | ||
| 180 | + if (value == null) { | ||
| 181 | + cell.setCellValue(""); | ||
| 182 | + } else if (value instanceof String) { | ||
| 183 | + cell.setCellValue((String) value); | ||
| 184 | + } else if (value instanceof Number) { | ||
| 185 | + cell.setCellValue(((Number) value).doubleValue()); | ||
| 186 | + } else if (value instanceof LocalDateTime) { | ||
| 187 | + cell.setCellValue(((LocalDateTime) value).format(DATE_TIME_FORMATTER)); | ||
| 188 | + } else if (value instanceof java.time.LocalDate) { | ||
| 189 | + cell.setCellValue(((java.time.LocalDate) value).format(DATE_FORMATTER)); | ||
| 190 | + } else if (value instanceof Boolean) { | ||
| 191 | + cell.setCellValue((Boolean) value ? "是" : "否"); | ||
| 192 | + } else { | ||
| 193 | + cell.setCellValue(value.toString()); | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + /** | ||
| 198 | + * 转换字典值 - 使用动态字典转换器 | ||
| 199 | + */ | ||
| 200 | + private static String convertDictValue(Object value, String fieldName) { | ||
| 201 | + String result = DictValueConverter.convert(value, fieldName); | ||
| 202 | + // 调试日志:输出字典转换过程 | ||
| 203 | + if (value != null && !value.toString().equals(result)) { | ||
| 204 | + System.out.println("字典转换: " + fieldName + " = " + value + " -> " + result); | ||
| 205 | + } | ||
| 206 | + return result; | ||
| 207 | + } | ||
| 208 | +} |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | +<mapper namespace="com.apple.erp.mapper.ExceptionWorkorderLogMapper"> | ||
| 4 | + | ||
| 5 | + <!-- 根据工单ID获取处理日志列表 --> | ||
| 6 | + <select id="selectWorkorderLogsByWorkorderId" resultType="com.apple.erp.dto.ExceptionWorkorderLogRes"> | ||
| 7 | + SELECT | ||
| 8 | + ewl.log_id, | ||
| 9 | + ewl.workorder_id, | ||
| 10 | + ewl.workorder_no, | ||
| 11 | + ewl.handle_user, | ||
| 12 | + ewl.handle_time, | ||
| 13 | + ewl.before_status, | ||
| 14 | + CASE ewl.before_status | ||
| 15 | + WHEN 1 THEN '待处理' | ||
| 16 | + WHEN 2 THEN '处理中' | ||
| 17 | + WHEN 3 THEN '已解决' | ||
| 18 | + WHEN 4 THEN '已关闭' | ||
| 19 | + ELSE '未知状态' | ||
| 20 | + END AS before_status_name, | ||
| 21 | + ewl.after_status, | ||
| 22 | + CASE ewl.after_status | ||
| 23 | + WHEN 1 THEN '待处理' | ||
| 24 | + WHEN 2 THEN '处理中' | ||
| 25 | + WHEN 3 THEN '已解决' | ||
| 26 | + WHEN 4 THEN '已关闭' | ||
| 27 | + ELSE '未知状态' | ||
| 28 | + END AS after_status_name, | ||
| 29 | + ewl.handle_opinion, | ||
| 30 | + ewl.attach_url, | ||
| 31 | + ewl.create_by, | ||
| 32 | + ewl.create_time | ||
| 33 | + FROM t_exception_workorder_log ewl | ||
| 34 | + WHERE ewl.workorder_id = #{workorderId} AND ewl.del_flag = '0' | ||
| 35 | + ORDER BY ewl.handle_time DESC | ||
| 36 | + </select> | ||
| 37 | + | ||
| 38 | + <!-- 根据工单ID列表批量获取处理日志 --> | ||
| 39 | + <select id="selectWorkorderLogsByWorkorderIds" resultType="com.apple.erp.dto.ExceptionWorkorderLogRes"> | ||
| 40 | + SELECT | ||
| 41 | + ewl.log_id, | ||
| 42 | + ewl.workorder_id, | ||
| 43 | + ewl.workorder_no, | ||
| 44 | + ewl.handle_user, | ||
| 45 | + ewl.handle_time, | ||
| 46 | + ewl.before_status, | ||
| 47 | + CASE ewl.before_status | ||
| 48 | + WHEN 1 THEN '待处理' | ||
| 49 | + WHEN 2 THEN '处理中' | ||
| 50 | + WHEN 3 THEN '已解决' | ||
| 51 | + WHEN 4 THEN '已关闭' | ||
| 52 | + ELSE '未知状态' | ||
| 53 | + END AS before_status_name, | ||
| 54 | + ewl.after_status, | ||
| 55 | + CASE ewl.after_status | ||
| 56 | + WHEN 1 THEN '待处理' | ||
| 57 | + WHEN 2 THEN '处理中' | ||
| 58 | + WHEN 3 THEN '已解决' | ||
| 59 | + WHEN 4 THEN '已关闭' | ||
| 60 | + ELSE '未知状态' | ||
| 61 | + END AS after_status_name, | ||
| 62 | + ewl.handle_opinion, | ||
| 63 | + ewl.attach_url, | ||
| 64 | + ewl.create_by, | ||
| 65 | + ewl.create_time | ||
| 66 | + FROM t_exception_workorder_log ewl | ||
| 67 | + WHERE ewl.workorder_id IN | ||
| 68 | + <foreach collection="workorderIds" item="workorderId" open="(" separator="," close=")"> | ||
| 69 | + #{workorderId} | ||
| 70 | + </foreach> | ||
| 71 | + AND ewl.del_flag = '0' | ||
| 72 | + ORDER BY ewl.workorder_id, ewl.handle_time DESC | ||
| 73 | + </select> | ||
| 74 | + | ||
| 75 | +</mapper> |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | +<mapper namespace="com.apple.erp.mapper.ExceptionWorkorderMapper"> | ||
| 4 | + | ||
| 5 | + <!-- 分页查询异常工单列表 --> | ||
| 6 | + <select id="selectExceptionWorkorderPage" resultType="com.apple.erp.dto.ExceptionWorkorderRes"> | ||
| 7 | + SELECT | ||
| 8 | + ew.workorder_id, | ||
| 9 | + ew.workorder_no, | ||
| 10 | + ew.order_no, | ||
| 11 | + ew.dealer_code, | ||
| 12 | + ew.dealer_name, | ||
| 13 | + ew.exception_type, | ||
| 14 | + CASE ew.exception_type | ||
| 15 | + WHEN 1 THEN '逻辑验证异常' | ||
| 16 | + WHEN 2 THEN '源头验证异常' | ||
| 17 | + WHEN 3 THEN '交叉验证异常' | ||
| 18 | + ELSE '未知类型' | ||
| 19 | + END AS exception_type_name, | ||
| 20 | + ew.severity_level, | ||
| 21 | + CASE ew.severity_level | ||
| 22 | + WHEN 1 THEN '高' | ||
| 23 | + WHEN 2 THEN '中' | ||
| 24 | + WHEN 3 THEN '低' | ||
| 25 | + ELSE '未知' | ||
| 26 | + END AS severity_level_name, | ||
| 27 | + ew.workorder_status, | ||
| 28 | + CASE ew.workorder_status | ||
| 29 | + WHEN 1 THEN '待处理' | ||
| 30 | + WHEN 2 THEN '处理中' | ||
| 31 | + WHEN 3 THEN '已解决' | ||
| 32 | + WHEN 4 THEN '已关闭' | ||
| 33 | + ELSE '未知状态' | ||
| 34 | + END AS workorder_status_name, | ||
| 35 | + ew.create_time, | ||
| 36 | + ew.expect_complete_time, | ||
| 37 | + ew.handler_user, | ||
| 38 | + ew.exception_desc, | ||
| 39 | + ew.handle_suggest, | ||
| 40 | + ew.data_source, | ||
| 41 | + ew.create_by, | ||
| 42 | + ew.update_by, | ||
| 43 | + ew.update_time | ||
| 44 | + FROM t_exception_workorder ew | ||
| 45 | + <where> | ||
| 46 | + ew.del_flag = '0' | ||
| 47 | + <if test="query.workorderNo != null and query.workorderNo != ''"> | ||
| 48 | + AND ew.workorder_no LIKE CONCAT('%', #{query.workorderNo}, '%') | ||
| 49 | + </if> | ||
| 50 | + <if test="query.orderNo != null and query.orderNo != ''"> | ||
| 51 | + AND ew.order_no LIKE CONCAT('%', #{query.orderNo}, '%') | ||
| 52 | + </if> | ||
| 53 | + <if test="query.dealerCode != null and query.dealerCode != ''"> | ||
| 54 | + AND ew.dealer_code = #{query.dealerCode} | ||
| 55 | + </if> | ||
| 56 | + <if test="query.dealerName != null and query.dealerName != ''"> | ||
| 57 | + AND ew.dealer_name LIKE CONCAT('%', #{query.dealerName}, '%') | ||
| 58 | + </if> | ||
| 59 | + <if test="query.workorderStatus != null"> | ||
| 60 | + AND ew.workorder_status = #{query.workorderStatus} | ||
| 61 | + </if> | ||
| 62 | + <if test="query.exceptionType != null"> | ||
| 63 | + AND ew.exception_type = #{query.exceptionType} | ||
| 64 | + </if> | ||
| 65 | + <if test="query.severityLevel != null"> | ||
| 66 | + AND ew.severity_level = #{query.severityLevel} | ||
| 67 | + </if> | ||
| 68 | + <if test="query.handlerUser != null and query.handlerUser != ''"> | ||
| 69 | + AND ew.handler_user LIKE CONCAT('%', #{query.handlerUser}, '%') | ||
| 70 | + </if> | ||
| 71 | + <if test="query.startTime != null"> | ||
| 72 | + AND ew.create_time >= #{query.startTime} | ||
| 73 | + </if> | ||
| 74 | + <if test="query.endTime != null"> | ||
| 75 | + AND ew.create_time <= #{query.endTime} | ||
| 76 | + </if> | ||
| 77 | + </where> | ||
| 78 | + ORDER BY ew.create_time DESC | ||
| 79 | + </select> | ||
| 80 | + | ||
| 81 | + <!-- 根据工单ID获取异常工单详情 --> | ||
| 82 | + <select id="selectExceptionWorkorderDetail" resultType="com.apple.erp.dto.ExceptionWorkorderRes"> | ||
| 83 | + SELECT | ||
| 84 | + ew.workorder_id, | ||
| 85 | + ew.workorder_no, | ||
| 86 | + ew.order_no, | ||
| 87 | + ew.dealer_code, | ||
| 88 | + ew.dealer_name, | ||
| 89 | + ew.exception_type, | ||
| 90 | + CASE ew.exception_type | ||
| 91 | + WHEN 1 THEN '逻辑验证异常' | ||
| 92 | + WHEN 2 THEN '源头验证异常' | ||
| 93 | + WHEN 3 THEN '交叉验证异常' | ||
| 94 | + ELSE '未知类型' | ||
| 95 | + END AS exception_type_name, | ||
| 96 | + ew.severity_level, | ||
| 97 | + CASE ew.severity_level | ||
| 98 | + WHEN 1 THEN '高' | ||
| 99 | + WHEN 2 THEN '中' | ||
| 100 | + WHEN 3 THEN '低' | ||
| 101 | + ELSE '未知' | ||
| 102 | + END AS severity_level_name, | ||
| 103 | + ew.workorder_status, | ||
| 104 | + CASE ew.workorder_status | ||
| 105 | + WHEN 1 THEN '待处理' | ||
| 106 | + WHEN 2 THEN '处理中' | ||
| 107 | + WHEN 3 THEN '已解决' | ||
| 108 | + WHEN 4 THEN '已关闭' | ||
| 109 | + ELSE '未知状态' | ||
| 110 | + END AS workorder_status_name, | ||
| 111 | + ew.create_time, | ||
| 112 | + ew.expect_complete_time, | ||
| 113 | + ew.handler_user, | ||
| 114 | + ew.exception_desc, | ||
| 115 | + ew.handle_suggest, | ||
| 116 | + ew.data_source, | ||
| 117 | + ew.create_by, | ||
| 118 | + ew.update_by, | ||
| 119 | + ew.update_time | ||
| 120 | + FROM t_exception_workorder ew | ||
| 121 | + WHERE ew.workorder_id = #{workorderId} AND ew.del_flag = '0' | ||
| 122 | + </select> | ||
| 123 | + | ||
| 124 | + <!-- 获取异常工单统计信息 --> | ||
| 125 | + <select id="selectExceptionWorkorderStats" resultType="com.apple.erp.dto.ExceptionWorkorderRes"> | ||
| 126 | + SELECT | ||
| 127 | + 'total' AS workorder_no, | ||
| 128 | + COUNT(*) AS workorder_id, | ||
| 129 | + SUM(CASE WHEN workorder_status = 1 THEN 1 ELSE 0 END) AS exception_type, | ||
| 130 | + SUM(CASE WHEN workorder_status = 2 THEN 1 ELSE 0 END) AS severity_level, | ||
| 131 | + SUM(CASE WHEN workorder_status = 3 THEN 1 ELSE 0 END) AS workorder_status, | ||
| 132 | + SUM(CASE WHEN workorder_status = 4 THEN 1 ELSE 0 END) AS handler_user, | ||
| 133 | + SUM(CASE WHEN severity_level = 1 THEN 1 ELSE 0 END) AS exception_desc, | ||
| 134 | + SUM(CASE WHEN severity_level = 2 THEN 1 ELSE 0 END) AS handle_suggest, | ||
| 135 | + SUM(CASE WHEN severity_level = 3 THEN 1 ELSE 0 END) AS data_source | ||
| 136 | + FROM t_exception_workorder | ||
| 137 | + WHERE del_flag = '0' | ||
| 138 | + </select> | ||
| 139 | + | ||
| 140 | + <!-- 批量更新工单状态 --> | ||
| 141 | + <update id="batchUpdateWorkorderStatus"> | ||
| 142 | + UPDATE t_exception_workorder | ||
| 143 | + SET workorder_status = #{workorderStatus}, | ||
| 144 | + handler_user = #{handlerUser}, | ||
| 145 | + update_time = NOW() | ||
| 146 | + WHERE workorder_id IN | ||
| 147 | + <foreach collection="workorderIds" item="workorderId" open="(" separator="," close=")"> | ||
| 148 | + #{workorderId} | ||
| 149 | + </foreach> | ||
| 150 | + AND del_flag = '0' | ||
| 151 | + </update> | ||
| 152 | + | ||
| 153 | +</mapper> |
| 1 | +-- 异常工单模块完整初始化脚本 | ||
| 2 | +-- 包含表结构创建、权限配置、测试数据插入 | ||
| 3 | + | ||
| 4 | +-- 1. 创建异常工单表 | ||
| 5 | +CREATE TABLE IF NOT EXISTS t_exception_workorder ( | ||
| 6 | + workorder_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '工单ID', | ||
| 7 | + workorder_no VARCHAR(30) NOT NULL COMMENT '工单编号', | ||
| 8 | + order_no VARCHAR(30) COMMENT '关联订单编号', | ||
| 9 | + dealer_code VARCHAR(20) COMMENT '经销商编码', | ||
| 10 | + dealer_name VARCHAR(100) COMMENT '经销商名称', | ||
| 11 | + exception_type TINYINT NOT NULL COMMENT '异常类型(1-逻辑验证异常/2-源头验证异常/3-交叉验证异常)', | ||
| 12 | + severity_level TINYINT NOT NULL COMMENT '严重程度(1-高/2-中/3-低)', | ||
| 13 | + workorder_status TINYINT DEFAULT 1 COMMENT '工单状态(1-待处理/2-处理中/3-已解决/4-已关闭)', | ||
| 14 | + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '工单创建时间', | ||
| 15 | + expect_complete_time DATETIME COMMENT '预计处理完成时间', | ||
| 16 | + handler_user VARCHAR(20) COMMENT '处理人', | ||
| 17 | + exception_desc VARCHAR(500) COMMENT '异常描述', | ||
| 18 | + handle_suggest VARCHAR(500) COMMENT '处理建议', | ||
| 19 | + data_source VARCHAR(20) COMMENT '数据来源', | ||
| 20 | + create_by VARCHAR(64) DEFAULT '' COMMENT '创建者', | ||
| 21 | + update_by VARCHAR(64) DEFAULT '' COMMENT '更新者', | ||
| 22 | + update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | ||
| 23 | + del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)' | ||
| 24 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='异常工单表'; | ||
| 25 | + | ||
| 26 | +-- 2. 创建异常工单处理日志表 | ||
| 27 | +CREATE TABLE IF NOT EXISTS t_exception_workorder_log ( | ||
| 28 | + log_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '日志ID', | ||
| 29 | + workorder_id BIGINT NOT NULL COMMENT '关联工单ID', | ||
| 30 | + workorder_no VARCHAR(30) NOT NULL COMMENT '关联工单编号', | ||
| 31 | + handle_user VARCHAR(20) NOT NULL COMMENT '处理人', | ||
| 32 | + handle_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '处理时间', | ||
| 33 | + before_status TINYINT NOT NULL COMMENT '处理前状态', | ||
| 34 | + after_status TINYINT NOT NULL COMMENT '处理后状态', | ||
| 35 | + handle_opinion VARCHAR(500) COMMENT '处理意见', | ||
| 36 | + attach_url VARCHAR(200) COMMENT '附件URL', | ||
| 37 | + create_by VARCHAR(64) DEFAULT '' COMMENT '创建者', | ||
| 38 | + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | ||
| 39 | + update_by VARCHAR(64) DEFAULT '' COMMENT '更新者', | ||
| 40 | + update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | ||
| 41 | + del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)' | ||
| 42 | +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='异常工单处理日志表'; | ||
| 43 | + | ||
| 44 | +-- 3. 创建索引 | ||
| 45 | +-- 异常工单表索引 | ||
| 46 | +CREATE UNIQUE INDEX IF NOT EXISTS uk_workorder_no ON t_exception_workorder(workorder_no); | ||
| 47 | +CREATE INDEX IF NOT EXISTS idx_workorder_dealer_code ON t_exception_workorder(dealer_code); | ||
| 48 | +CREATE INDEX IF NOT EXISTS idx_workorder_order_no ON t_exception_workorder(order_no); | ||
| 49 | +CREATE INDEX IF NOT EXISTS idx_workorder_status ON t_exception_workorder(workorder_status); | ||
| 50 | +CREATE INDEX IF NOT EXISTS idx_workorder_exception_type ON t_exception_workorder(exception_type); | ||
| 51 | +CREATE INDEX IF NOT EXISTS idx_workorder_severity_level ON t_exception_workorder(severity_level); | ||
| 52 | +CREATE INDEX IF NOT EXISTS idx_workorder_create_time ON t_exception_workorder(create_time); | ||
| 53 | +CREATE INDEX IF NOT EXISTS idx_workorder_handler_user ON t_exception_workorder(handler_user); | ||
| 54 | + | ||
| 55 | +-- 异常工单处理日志表索引 | ||
| 56 | +CREATE INDEX IF NOT EXISTS idx_log_workorder_id ON t_exception_workorder_log(workorder_id); | ||
| 57 | +CREATE INDEX IF NOT EXISTS idx_log_workorder_no ON t_exception_workorder_log(workorder_no); | ||
| 58 | +CREATE INDEX IF NOT EXISTS idx_log_handle_user ON t_exception_workorder_log(handle_user); | ||
| 59 | +CREATE INDEX IF NOT EXISTS idx_log_handle_time ON t_exception_workorder_log(handle_time); | ||
| 60 | + | ||
| 61 | +-- 4. 创建外键约束 | ||
| 62 | +ALTER TABLE t_exception_workorder_log | ||
| 63 | +ADD CONSTRAINT IF NOT EXISTS fk_workorder_log_workorder_id | ||
| 64 | +FOREIGN KEY (workorder_id) REFERENCES t_exception_workorder(workorder_id) | ||
| 65 | +ON DELETE CASCADE ON UPDATE CASCADE; | ||
| 66 | + | ||
| 67 | +-- 5. 插入异常工单菜单 | ||
| 68 | +INSERT IGNORE INTO t_sys_menu (parent_id, menu_name, menu_type, path, icon, sort, status, perms, create_by, create_time) VALUES | ||
| 69 | +(0, '异常工单', 1, '/main/exception-workorder', '⚠️', 7, 1, 'exception:workorder:view', 'admin', NOW()); | ||
| 70 | + | ||
| 71 | +-- 获取异常工单菜单ID | ||
| 72 | +SET @exception_menu_id = LAST_INSERT_ID(); | ||
| 73 | + | ||
| 74 | +-- 6. 插入异常工单子菜单 | ||
| 75 | +INSERT IGNORE INTO t_sys_menu (parent_id, menu_name, menu_type, path, icon, sort, status, perms, create_by, create_time) VALUES | ||
| 76 | +(@exception_menu_id, '工单查询', 2, '', '', 1, 1, 'exception:workorder:list', 'admin', NOW()), | ||
| 77 | +(@exception_menu_id, '工单详情', 2, '', '', 2, 1, 'exception:workorder:detail', 'admin', NOW()), | ||
| 78 | +(@exception_menu_id, '工单新增', 2, '', '', 3, 1, 'exception:workorder:add', 'admin', NOW()), | ||
| 79 | +(@exception_menu_id, '工单编辑', 2, '', '', 4, 1, 'exception:workorder:edit', 'admin', NOW()), | ||
| 80 | +(@exception_menu_id, '工单删除', 2, '', '', 5, 1, 'exception:workorder:delete', 'admin', NOW()), | ||
| 81 | +(@exception_menu_id, '状态更新', 2, '', '', 6, 1, 'exception:workorder:status', 'admin', NOW()), | ||
| 82 | +(@exception_menu_id, '批量处理', 2, '', '', 7, 1, 'exception:workorder:batch', 'admin', NOW()), | ||
| 83 | +(@exception_menu_id, '统计查看', 2, '', '', 8, 1, 'exception:workorder:stats', 'admin', NOW()); | ||
| 84 | + | ||
| 85 | + | ||
| 86 | +-- 12. 为管理员角色分配异常工单权限 | ||
| 87 | +INSERT IGNORE INTO t_sys_role_menu (role_id, menu_id, create_by, create_time) | ||
| 88 | +SELECT r.role_id, @exception_menu_id, 'admin', NOW() | ||
| 89 | +FROM t_sys_role r | ||
| 90 | +WHERE r.role_code = 'ADMIN'; | ||
| 91 | + | ||
| 92 | +-- 13. 为管理员角色分配异常工单子菜单权限 | ||
| 93 | +INSERT IGNORE INTO t_sys_role_menu (role_id, menu_id, create_by, create_time) | ||
| 94 | +SELECT r.role_id, m.menu_id, 'admin', NOW() | ||
| 95 | +FROM t_sys_role r, t_sys_menu m | ||
| 96 | +WHERE r.role_code = 'ADMIN' | ||
| 97 | +AND m.parent_id = @exception_menu_id; | ||
| 98 | + | ||
| 99 | + | ||
| 100 | +-- 完成初始化 | ||
| 101 | +SELECT '异常工单模块初始化完成' AS message; |
| ... | @@ -9,7 +9,9 @@ declare module 'vue' { | ... | @@ -9,7 +9,9 @@ declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | ElButton: typeof import('element-plus/es')['ElButton'] | 10 | ElButton: typeof import('element-plus/es')['ElButton'] |
| 11 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] | 11 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] |
| 12 | + ElCard: typeof import('element-plus/es')['ElCard'] | ||
| 12 | ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] | 13 | ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] |
| 14 | + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] | ||
| 13 | ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] | 15 | ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] |
| 14 | ElDialog: typeof import('element-plus/es')['ElDialog'] | 16 | ElDialog: typeof import('element-plus/es')['ElDialog'] |
| 15 | ElForm: typeof import('element-plus/es')['ElForm'] | 17 | ElForm: typeof import('element-plus/es')['ElForm'] |
| ... | @@ -23,7 +25,9 @@ declare module 'vue' { | ... | @@ -23,7 +25,9 @@ declare module 'vue' { |
| 23 | ElSelect: typeof import('element-plus/es')['ElSelect'] | 25 | ElSelect: typeof import('element-plus/es')['ElSelect'] |
| 24 | ElTable: typeof import('element-plus/es')['ElTable'] | 26 | ElTable: typeof import('element-plus/es')['ElTable'] |
| 25 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | 27 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] |
| 28 | + ElSelect: typeof import('element-plus/es')['ElSelect'] | ||
| 26 | ElTag: typeof import('element-plus/es')['ElTag'] | 29 | ElTag: typeof import('element-plus/es')['ElTag'] |
| 30 | + ElText: typeof import('element-plus/es')['ElText'] | ||
| 27 | Header: typeof import('./src/components/layout/Header.vue')['default'] | 31 | Header: typeof import('./src/components/layout/Header.vue')['default'] |
| 28 | RouterLink: typeof import('vue-router')['RouterLink'] | 32 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 29 | RouterView: typeof import('vue-router')['RouterView'] | 33 | RouterView: typeof import('vue-router')['RouterView'] | ... | ... |
| ... | @@ -120,8 +120,11 @@ export const deliveryApi = { | ... | @@ -120,8 +120,11 @@ export const deliveryApi = { |
| 120 | 120 | ||
| 121 | // 修改出库状态 | 121 | // 修改出库状态 |
| 122 | updateDeliveryStatus: (deliveryId: number, deliveryStatus: number) => { | 122 | updateDeliveryStatus: (deliveryId: number, deliveryStatus: number) => { |
| 123 | - return request.post(`/api/delivery/${deliveryId}/deliveryStatus`, null, { | 123 | + return request.post(`/api/delivery/${deliveryId}/deliveryStatus`, { deliveryStatus }) |
| 124 | - params: { deliveryStatus } | 124 | + }, |
| 125 | - }) | 125 | + |
| 126 | + // 导出出库数据 | ||
| 127 | + exportDeliveries: (params: DeliveryQueryReq) => { | ||
| 128 | + return request.post('/api/delivery/export', params, { responseType: 'blob' }) | ||
| 126 | } | 129 | } |
| 127 | } | 130 | } | ... | ... |
| 1 | -import axios from 'axios' | 1 | +import request from '@/utils/request' |
| 2 | 2 | ||
| 3 | -const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8083' | 3 | +/** |
| 4 | + * 字典管理API | ||
| 5 | + */ | ||
| 4 | 6 | ||
| 5 | -const api = axios.create({ | 7 | +// 获取字典项 |
| 6 | - baseURL: API_BASE_URL, | 8 | +export const getDictItems = (dictType: string) => { |
| 7 | - timeout: 10000, | 9 | + return request.get(`/api/dict/${dictType}`) |
| 8 | - headers: { | ||
| 9 | - 'Content-Type': 'application/json' | ||
| 10 | - } | ||
| 11 | -}) | ||
| 12 | - | ||
| 13 | -api.interceptors.request.use( | ||
| 14 | - (config) => { | ||
| 15 | - const token = localStorage.getItem('token') | ||
| 16 | - if (token) { | ||
| 17 | - config.headers.Authorization = `Bearer ${token}` | ||
| 18 | - } | ||
| 19 | - return config | ||
| 20 | - }, | ||
| 21 | - (error) => { | ||
| 22 | - return Promise.reject(error) | ||
| 23 | - } | ||
| 24 | -) | ||
| 25 | - | ||
| 26 | -api.interceptors.response.use( | ||
| 27 | - (response) => { | ||
| 28 | - return response.data | ||
| 29 | - }, | ||
| 30 | - (error) => { | ||
| 31 | - console.error('API请求错误:', error) | ||
| 32 | - return Promise.reject(error) | ||
| 33 | - } | ||
| 34 | -) | ||
| 35 | - | ||
| 36 | -export interface DictType { | ||
| 37 | - dictTypeId: number | ||
| 38 | - dictType: string | ||
| 39 | - dictName: string | ||
| 40 | - status: number | ||
| 41 | - statusText: string | ||
| 42 | - remark?: string | ||
| 43 | - createBy?: string | ||
| 44 | - createTime: string | ||
| 45 | - updateBy?: string | ||
| 46 | - updateTime: string | ||
| 47 | -} | ||
| 48 | - | ||
| 49 | -export interface DictItem { | ||
| 50 | - dictItemId: number | ||
| 51 | - dictTypeId: number | ||
| 52 | - dictType: string | ||
| 53 | - dictLabel: string | ||
| 54 | - dictValue: string | ||
| 55 | - sort: number | ||
| 56 | - remark?: string | ||
| 57 | - createBy?: string | ||
| 58 | - createTime: string | ||
| 59 | - updateBy?: string | ||
| 60 | - updateTime: string | ||
| 61 | -} | ||
| 62 | - | ||
| 63 | -export interface DictTypeSearchParams { | ||
| 64 | - dictType?: string | ||
| 65 | - dictName?: string | ||
| 66 | - status?: number | ||
| 67 | - pageNum?: number | ||
| 68 | - pageSize?: number | ||
| 69 | -} | ||
| 70 | - | ||
| 71 | -export interface DictItemSearchParams { | ||
| 72 | - dictTypeId?: number | ||
| 73 | - dictLabel?: string | ||
| 74 | - dictValue?: string | ||
| 75 | - pageNum?: number | ||
| 76 | - pageSize?: number | ||
| 77 | -} | ||
| 78 | - | ||
| 79 | -export interface DictTypeAddReq { | ||
| 80 | - dictType: string | ||
| 81 | - dictName: string | ||
| 82 | - status: number | ||
| 83 | - remark?: string | ||
| 84 | -} | ||
| 85 | - | ||
| 86 | -export interface DictTypeUpdateReq extends DictTypeAddReq { | ||
| 87 | - dictTypeId: number | ||
| 88 | -} | ||
| 89 | - | ||
| 90 | -export interface DictItemAddReq { | ||
| 91 | - dictTypeId: number | ||
| 92 | - dictLabel: string | ||
| 93 | - dictValue: string | ||
| 94 | - sort?: number | ||
| 95 | - remark?: string | ||
| 96 | } | 10 | } |
| 97 | 11 | ||
| 98 | -export interface DictItemUpdateReq extends DictItemAddReq { | 12 | +// 获取所有字典项 |
| 99 | - dictItemId: number | 13 | +export const getAllDictItems = () => { |
| 14 | + return request.get('/api/dict/all') | ||
| 100 | } | 15 | } |
| 101 | 16 | ||
| 102 | -export interface ApiResponse<T = any> { | 17 | +// 刷新字典缓存 |
| 103 | - code: number | 18 | +export const refreshDictCache = () => { |
| 104 | - message: string | 19 | + return request.post('/api/dict/refresh') |
| 105 | - data: T | ||
| 106 | -} | ||
| 107 | - | ||
| 108 | -export interface PageResponse<T> { | ||
| 109 | - records: T[] | ||
| 110 | - total: number | ||
| 111 | - size: number | ||
| 112 | - current: number | ||
| 113 | - orders: any[] | ||
| 114 | - optimizeCountSql: boolean | ||
| 115 | - searchCount: boolean | ||
| 116 | - maxLimit: any | ||
| 117 | - countId: any | ||
| 118 | - pages: number | ||
| 119 | -} | ||
| 120 | - | ||
| 121 | -export const dictApi = { | ||
| 122 | - // 字典类型管理 | ||
| 123 | - // 获取字典类型列表 | ||
| 124 | - getDictTypes: (params: DictTypeSearchParams): Promise<ApiResponse<PageResponse<DictType>>> => { | ||
| 125 | - return api.get('/api/system/dict/type/list', { params }) | ||
| 126 | - }, | ||
| 127 | - | ||
| 128 | - // 获取字典类型详情 | ||
| 129 | - getDictTypeById: (dictTypeId: number): Promise<ApiResponse<DictType>> => { | ||
| 130 | - return api.get(`/api/system/dict/type/${dictTypeId}`) | ||
| 131 | - }, | ||
| 132 | - | ||
| 133 | - // 新增字典类型 | ||
| 134 | - createDictType: (dictTypeData: DictTypeAddReq): Promise<ApiResponse<any>> => { | ||
| 135 | - return api.post('/api/system/dict/type', dictTypeData) | ||
| 136 | - }, | ||
| 137 | - | ||
| 138 | - // 修改字典类型 | ||
| 139 | - updateDictType: (dictTypeData: DictTypeUpdateReq): Promise<ApiResponse<any>> => { | ||
| 140 | - return api.put('/api/system/dict/type', dictTypeData) | ||
| 141 | - }, | ||
| 142 | - | ||
| 143 | - // 删除字典类型 | ||
| 144 | - deleteDictTypes: (dictTypeIds: number[]): Promise<ApiResponse<any>> => { | ||
| 145 | - return api.delete(`/api/system/dict/type/${dictTypeIds.join(',')}`) | ||
| 146 | - }, | ||
| 147 | - | ||
| 148 | - // 获取字典类型选择框列表 | ||
| 149 | - getDictTypeOptions: (): Promise<ApiResponse<DictType[]>> => { | ||
| 150 | - return api.get('/api/system/dict/type/optionselect') | ||
| 151 | - }, | ||
| 152 | - | ||
| 153 | - // 刷新字典缓存 | ||
| 154 | - refreshDictCache: (): Promise<ApiResponse<any>> => { | ||
| 155 | - return api.delete('/api/system/dict/type/refreshCache') | ||
| 156 | - }, | ||
| 157 | - | ||
| 158 | - // 字典项管理 | ||
| 159 | - // 获取字典项列表 | ||
| 160 | - getDictItems: (params: DictItemSearchParams): Promise<ApiResponse<PageResponse<DictItem>>> => { | ||
| 161 | - return api.get('/api/system/dict/item/list', { params }) | ||
| 162 | - }, | ||
| 163 | - | ||
| 164 | - // 根据字典类型获取字典项列表 | ||
| 165 | - getDictItemsByType: (dictType: string): Promise<ApiResponse<DictItem[]>> => { | ||
| 166 | - return api.get(`/api/system/dict/item/type/${dictType}`) | ||
| 167 | - }, | ||
| 168 | - | ||
| 169 | - // 获取字典项详情 | ||
| 170 | - getDictItemById: (dictItemId: number): Promise<ApiResponse<DictItem>> => { | ||
| 171 | - return api.get(`/api/system/dict/item/${dictItemId}`) | ||
| 172 | - }, | ||
| 173 | - | ||
| 174 | - // 新增字典项 | ||
| 175 | - createDictItem: (dictItemData: DictItemAddReq): Promise<ApiResponse<any>> => { | ||
| 176 | - return api.post('/api/system/dict/item', dictItemData) | ||
| 177 | - }, | ||
| 178 | - | ||
| 179 | - // 修改字典项 | ||
| 180 | - updateDictItem: (dictItemData: DictItemUpdateReq): Promise<ApiResponse<any>> => { | ||
| 181 | - return api.put('/api/system/dict/item', dictItemData) | ||
| 182 | - }, | ||
| 183 | - | ||
| 184 | - // 删除字典项 | ||
| 185 | - deleteDictItems: (dictItemIds: number[]): Promise<ApiResponse<any>> => { | ||
| 186 | - return api.delete(`/api/system/dict/item/${dictItemIds.join(',')}`) | ||
| 187 | - }, | ||
| 188 | } | 20 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
frontend/src/api/exceptionWorkorder.ts
0 → 100644
| 1 | +import { request } from '../utils/request' | ||
| 2 | + | ||
| 3 | +// 异常工单相关类型定义 | ||
| 4 | +export interface ExceptionWorkorderInfo { | ||
| 5 | + workorderId: number | ||
| 6 | + workorderNo: string | ||
| 7 | + orderNo: string | ||
| 8 | + dealerCode: string | ||
| 9 | + dealerName: string | ||
| 10 | + exceptionType: number | ||
| 11 | + exceptionTypeName: string | ||
| 12 | + severityLevel: number | ||
| 13 | + severityLevelName: string | ||
| 14 | + workorderStatus: number | ||
| 15 | + workorderStatusName: string | ||
| 16 | + createTime: string | ||
| 17 | + expectCompleteTime?: string | ||
| 18 | + handlerUser?: string | ||
| 19 | + exceptionDesc?: string | ||
| 20 | + handleSuggest?: string | ||
| 21 | + dataSource?: string | ||
| 22 | + createBy?: string | ||
| 23 | + updateBy?: string | ||
| 24 | + updateTime?: string | ||
| 25 | + workorderLogs?: ExceptionWorkorderLogInfo[] | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +export interface ExceptionWorkorderLogInfo { | ||
| 29 | + logId: number | ||
| 30 | + workorderId: number | ||
| 31 | + workorderNo: string | ||
| 32 | + handleUser: string | ||
| 33 | + handleTime: string | ||
| 34 | + beforeStatus: number | ||
| 35 | + beforeStatusName: string | ||
| 36 | + afterStatus: number | ||
| 37 | + afterStatusName: string | ||
| 38 | + handleOpinion?: string | ||
| 39 | + attachUrl?: string | ||
| 40 | + createBy?: string | ||
| 41 | + createTime: string | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +export interface ExceptionWorkorderQueryReq { | ||
| 45 | + workorderNo?: string | ||
| 46 | + orderNo?: string | ||
| 47 | + dealerCode?: string | ||
| 48 | + dealerName?: string | ||
| 49 | + workorderStatus?: number | ||
| 50 | + exceptionType?: number | ||
| 51 | + severityLevel?: number | ||
| 52 | + handlerUser?: string | ||
| 53 | + startTime?: string | ||
| 54 | + endTime?: string | ||
| 55 | + pageNum?: number | ||
| 56 | + pageSize?: number | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +export interface ExceptionWorkorderAddReq { | ||
| 60 | + workorderNo: string | ||
| 61 | + orderNo?: string | ||
| 62 | + dealerCode?: string | ||
| 63 | + dealerName?: string | ||
| 64 | + exceptionType: number | ||
| 65 | + severityLevel: number | ||
| 66 | + workorderStatus?: number | ||
| 67 | + expectCompleteTime?: string | ||
| 68 | + handlerUser?: string | ||
| 69 | + exceptionDesc?: string | ||
| 70 | + handleSuggest?: string | ||
| 71 | + dataSource?: string | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +export interface ExceptionWorkorderUpdateReq { | ||
| 75 | + workorderId: number | ||
| 76 | + workorderNo?: string | ||
| 77 | + orderNo?: string | ||
| 78 | + dealerCode?: string | ||
| 79 | + dealerName?: string | ||
| 80 | + exceptionType?: number | ||
| 81 | + severityLevel?: number | ||
| 82 | + workorderStatus?: number | ||
| 83 | + expectCompleteTime?: string | ||
| 84 | + handlerUser?: string | ||
| 85 | + exceptionDesc?: string | ||
| 86 | + handleSuggest?: string | ||
| 87 | + dataSource?: string | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +export interface ExceptionWorkorderStatusUpdateReq { | ||
| 91 | + workorderId: number | ||
| 92 | + workorderStatus: number | ||
| 93 | + handlerUser?: string | ||
| 94 | + handleOpinion?: string | ||
| 95 | + attachUrl?: string | ||
| 96 | +} | ||
| 97 | + | ||
| 98 | +// 异常工单API接口 | ||
| 99 | +export const exceptionWorkorderApi = { | ||
| 100 | + // 分页查询异常工单列表 | ||
| 101 | + getExceptionWorkorderList: (params: ExceptionWorkorderQueryReq) => { | ||
| 102 | + return request.get('/api/exception-workorder/list', params) | ||
| 103 | + }, | ||
| 104 | + | ||
| 105 | + // 获取异常工单详情 | ||
| 106 | + getExceptionWorkorderDetail: (workorderId: number) => { | ||
| 107 | + return request.get(`/api/exception-workorder/${workorderId}`) | ||
| 108 | + }, | ||
| 109 | + | ||
| 110 | + // 新增异常工单 | ||
| 111 | + addExceptionWorkorder: (data: ExceptionWorkorderAddReq) => { | ||
| 112 | + return request.post('/api/exception-workorder', data) | ||
| 113 | + }, | ||
| 114 | + | ||
| 115 | + // 更新异常工单 | ||
| 116 | + updateExceptionWorkorder: (data: ExceptionWorkorderUpdateReq) => { | ||
| 117 | + return request.put('/api/exception-workorder', data) | ||
| 118 | + }, | ||
| 119 | + | ||
| 120 | + // 更新工单状态 | ||
| 121 | + updateWorkorderStatus: (data: ExceptionWorkorderStatusUpdateReq) => { | ||
| 122 | + return request.post('/api/exception-workorder/status', data) | ||
| 123 | + }, | ||
| 124 | + | ||
| 125 | + // 删除异常工单 | ||
| 126 | + deleteExceptionWorkorder: (workorderId: number) => { | ||
| 127 | + return request.delete(`/api/exception-workorder/${workorderId}`) | ||
| 128 | + }, | ||
| 129 | + | ||
| 130 | + // 批量删除异常工单 | ||
| 131 | + batchDeleteExceptionWorkorders: (workorderIds: number[]) => { | ||
| 132 | + return request.delete('/api/exception-workorder/batch', workorderIds) | ||
| 133 | + }, | ||
| 134 | + | ||
| 135 | + // 批量更新工单状态 | ||
| 136 | + batchUpdateWorkorderStatus: (workorderIds: number[], workorderStatus: number, handlerUser: string) => { | ||
| 137 | + return request.post('/api/exception-workorder/batch-status', null, { | ||
| 138 | + params: { | ||
| 139 | + workorderIds: workorderIds.join(','), | ||
| 140 | + workorderStatus, | ||
| 141 | + handlerUser | ||
| 142 | + } | ||
| 143 | + }) | ||
| 144 | + }, | ||
| 145 | + | ||
| 146 | + // 获取异常工单统计信息 | ||
| 147 | + getExceptionWorkorderStats: () => { | ||
| 148 | + return request.get('/api/exception-workorder/stats') | ||
| 149 | + } | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +// 异常类型枚举 | ||
| 153 | +export const EXCEPTION_TYPE = { | ||
| 154 | + 1: '逻辑验证异常', | ||
| 155 | + 2: '源头验证异常', | ||
| 156 | + 3: '交叉验证异常' | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +// 严重程度枚举 | ||
| 160 | +export const SEVERITY_LEVEL = { | ||
| 161 | + 1: '高', | ||
| 162 | + 2: '中', | ||
| 163 | + 3: '低' | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +// 工单状态枚举 | ||
| 167 | +export const WORKORDER_STATUS = { | ||
| 168 | + 1: '待处理', | ||
| 169 | + 2: '处理中', | ||
| 170 | + 3: '已解决', | ||
| 171 | + 4: '已关闭' | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +// 获取异常类型名称 | ||
| 175 | +export const getExceptionTypeName = (type: number): string => { | ||
| 176 | + return EXCEPTION_TYPE[type as keyof typeof EXCEPTION_TYPE] || '未知类型' | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +// 获取严重程度名称 | ||
| 180 | +export const getSeverityLevelName = (level: number): string => { | ||
| 181 | + return SEVERITY_LEVEL[level as keyof typeof SEVERITY_LEVEL] || '未知' | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +// 获取工单状态名称 | ||
| 185 | +export const getWorkorderStatusName = (status: number): string => { | ||
| 186 | + return WORKORDER_STATUS[status as keyof typeof WORKORDER_STATUS] || '未知状态' | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +// 获取严重程度颜色 | ||
| 190 | +export const getSeverityLevelColor = (level: number): string => { | ||
| 191 | + const colors = { | ||
| 192 | + 1: '#f56c6c', // 高 - 红色 | ||
| 193 | + 2: '#e6a23c', // 中 - 橙色 | ||
| 194 | + 3: '#409eff' // 低 - 蓝色 | ||
| 195 | + } | ||
| 196 | + return colors[level as keyof typeof colors] || '#909399' | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +// 获取工单状态颜色 | ||
| 200 | +export const getWorkorderStatusColor = (status: number): string => { | ||
| 201 | + const colors = { | ||
| 202 | + 1: '#909399', // 待处理 - 灰色 | ||
| 203 | + 2: '#e6a23c', // 处理中 - 橙色 | ||
| 204 | + 3: '#67c23a', // 已解决 - 绿色 | ||
| 205 | + 4: '#f56c6c' // 已关闭 - 红色 | ||
| 206 | + } | ||
| 207 | + return colors[status as keyof typeof colors] || '#909399' | ||
| 208 | +} |
| ... | @@ -121,8 +121,11 @@ export const invoiceApi = { | ... | @@ -121,8 +121,11 @@ export const invoiceApi = { |
| 121 | return request.post('/api/invoice/batchDelete', invoiceIds) | 121 | return request.post('/api/invoice/batchDelete', invoiceIds) |
| 122 | }, | 122 | }, |
| 123 | updateInvoiceStatus: (invoiceId: number, invoiceStatus: number) => { | 123 | updateInvoiceStatus: (invoiceId: number, invoiceStatus: number) => { |
| 124 | - return request.post(`/api/invoice/${invoiceId}/invoiceStatus`, null, { | 124 | + return request.post(`/api/invoice/${invoiceId}/invoiceStatus`, { invoiceStatus }) |
| 125 | - params: { invoiceStatus } | 125 | + }, |
| 126 | - }) | 126 | + |
| 127 | + // 导出发票数据 | ||
| 128 | + exportInvoices: (params: InvoiceQueryReq) => { | ||
| 129 | + return request.post('/api/invoice/export', params, { responseType: 'blob' }) | ||
| 127 | } | 130 | } |
| 128 | } | 131 | } | ... | ... |
| ... | @@ -150,5 +150,10 @@ export const orderApi = { | ... | @@ -150,5 +150,10 @@ export const orderApi = { |
| 150 | return request.post(`/order/${orderId}/rebateCalcFlag`, null, { | 150 | return request.post(`/order/${orderId}/rebateCalcFlag`, null, { |
| 151 | params: { rebateCalcFlag } | 151 | params: { rebateCalcFlag } |
| 152 | }) | 152 | }) |
| 153 | + }, | ||
| 154 | + | ||
| 155 | + // 导出订单数据 | ||
| 156 | + exportOrders: (params: OrderQueryReq) => { | ||
| 157 | + return request.post('/order/export', params, { responseType: 'blob' }) | ||
| 153 | } | 158 | } |
| 154 | } | 159 | } | ... | ... |
| ... | @@ -209,6 +209,11 @@ export const getRebateTrendStats = (startDate?: string, endDate?: string) => { | ... | @@ -209,6 +209,11 @@ export const getRebateTrendStats = (startDate?: string, endDate?: string) => { |
| 209 | }) | 209 | }) |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | +// 导出返利数据 | ||
| 213 | +export const exportRebates = (params: RebateSearchParams) => { | ||
| 214 | + return request.post('/api/rebate/export', params, { responseType: 'blob' }) | ||
| 215 | +} | ||
| 216 | + | ||
| 212 | export default { | 217 | export default { |
| 213 | getRebatePage, | 218 | getRebatePage, |
| 214 | getRebateById, | 219 | getRebateById, |
| ... | @@ -227,5 +232,6 @@ export default { | ... | @@ -227,5 +232,6 @@ export default { |
| 227 | exportRebate, | 232 | exportRebate, |
| 228 | getRebateMonthlyStats, | 233 | getRebateMonthlyStats, |
| 229 | getRebateStatusStats, | 234 | getRebateStatusStats, |
| 230 | - getRebateTrendStats | 235 | + getRebateTrendStats, |
| 236 | + exportRebates | ||
| 231 | } | 237 | } | ... | ... |
| ... | @@ -72,7 +72,8 @@ | ... | @@ -72,7 +72,8 @@ |
| 72 | 72 | ||
| 73 | <div class="header-right"> | 73 | <div class="header-right"> |
| 74 | <div class="user-info"> | 74 | <div class="user-info"> |
| 75 | - <span class="welcome-text">欢迎,{{ userInfo?.username || '用户' }}</span> | 75 | + <span class="welcome-text" v-if="userInfoLoading">加载中...</span> |
| 76 | + <span class="welcome-text" v-else>欢迎,{{ userInfo?.username || '未知' }}</span> | ||
| 76 | <div class="user-actions"> | 77 | <div class="user-actions"> |
| 77 | <button class="logout-btn" @click="handleLogout">退出登录</button> | 78 | <button class="logout-btn" @click="handleLogout">退出登录</button> |
| 78 | </div> | 79 | </div> |
| ... | @@ -125,6 +126,7 @@ | ... | @@ -125,6 +126,7 @@ |
| 125 | import { ref, computed, onMounted, watch, nextTick } from 'vue' | 126 | import { ref, computed, onMounted, watch, nextTick } from 'vue' |
| 126 | import { useRouter, useRoute } from 'vue-router' | 127 | import { useRouter, useRoute } from 'vue-router' |
| 127 | import { logoutApi } from '../api/auth' | 128 | import { logoutApi } from '../api/auth' |
| 129 | +import { request } from '../utils/request' | ||
| 128 | 130 | ||
| 129 | const router = useRouter() | 131 | const router = useRouter() |
| 130 | const route = useRoute() | 132 | const route = useRoute() |
| ... | @@ -134,6 +136,26 @@ const sidebarCollapsed = ref(false) | ... | @@ -134,6 +136,26 @@ const sidebarCollapsed = ref(false) |
| 134 | 136 | ||
| 135 | // 用户信息 | 137 | // 用户信息 |
| 136 | const userInfo = ref<any>(null) | 138 | const userInfo = ref<any>(null) |
| 139 | +const userInfoLoading = ref(false) | ||
| 140 | + | ||
| 141 | +// 获取用户信息 | ||
| 142 | +const fetchUserInfo = async () => { | ||
| 143 | + try { | ||
| 144 | + userInfoLoading.value = true | ||
| 145 | + const response = await request.get('/api/auth/userinfo') | ||
| 146 | + userInfo.value = response | ||
| 147 | + console.log('顶部栏用户信息:', response) | ||
| 148 | + } catch (error) { | ||
| 149 | + console.error('获取用户信息失败:', error) | ||
| 150 | + // 如果获取失败,尝试从本地存储获取 | ||
| 151 | + const storedUserInfo = localStorage.getItem('userInfo') | ||
| 152 | + if (storedUserInfo) { | ||
| 153 | + userInfo.value = JSON.parse(storedUserInfo) | ||
| 154 | + } | ||
| 155 | + } finally { | ||
| 156 | + userInfoLoading.value = false | ||
| 157 | + } | ||
| 158 | +} | ||
| 137 | 159 | ||
| 138 | // 标签页容器引用 | 160 | // 标签页容器引用 |
| 139 | const tabContainer = ref<HTMLElement>() | 161 | const tabContainer = ref<HTMLElement>() |
| ... | @@ -147,6 +169,7 @@ const menuItems = ref([ | ... | @@ -147,6 +169,7 @@ const menuItems = ref([ |
| 147 | { name: '产品管理', path: '/main/product', icon: '📦' }, | 169 | { name: '产品管理', path: '/main/product', icon: '📦' }, |
| 148 | { name: '经销商管理', path: '/main/dealer', icon: '🏢' }, | 170 | { name: '经销商管理', path: '/main/dealer', icon: '🏢' }, |
| 149 | { name: '返利管理', path: '/main/rebate', icon: '💰' }, | 171 | { name: '返利管理', path: '/main/rebate', icon: '💰' }, |
| 172 | + { name: '异常工单', path: '/main/exception-workorder', icon: '⚠️' }, | ||
| 150 | { | 173 | { |
| 151 | name: '系统设置', | 174 | name: '系统设置', |
| 152 | icon: '⚙️', | 175 | icon: '⚙️', |
| ... | @@ -370,9 +393,17 @@ watch(() => route.path, (newPath) => { | ... | @@ -370,9 +393,17 @@ watch(() => route.path, (newPath) => { |
| 370 | 393 | ||
| 371 | // 组件挂载时获取用户信息 | 394 | // 组件挂载时获取用户信息 |
| 372 | onMounted(() => { | 395 | onMounted(() => { |
| 373 | - const storedUserInfo = localStorage.getItem('userInfo') | 396 | + // 检查是否已登录 |
| 374 | - if (storedUserInfo) { | 397 | + const token = localStorage.getItem('token') |
| 375 | - userInfo.value = JSON.parse(storedUserInfo) | 398 | + if (token) { |
| 399 | + // 调用API获取用户信息 | ||
| 400 | + fetchUserInfo() | ||
| 401 | + } else { | ||
| 402 | + // 如果没有token,尝试从本地存储获取 | ||
| 403 | + const storedUserInfo = localStorage.getItem('userInfo') | ||
| 404 | + if (storedUserInfo) { | ||
| 405 | + userInfo.value = JSON.parse(storedUserInfo) | ||
| 406 | + } | ||
| 376 | } | 407 | } |
| 377 | }) | 408 | }) |
| 378 | </script> | 409 | </script> | ... | ... |
| 1 | import { createApp } from 'vue' | 1 | import { createApp } from 'vue' |
| 2 | import { createPinia } from 'pinia' | 2 | import { createPinia } from 'pinia' |
| 3 | import App from './App.vue' | 3 | import App from './App.vue' |
| 4 | +import ElementPlus from 'element-plus' | ||
| 5 | +import 'element-plus/dist/index.css' | ||
| 4 | 6 | ||
| 5 | import router from './router' | 7 | import router from './router' |
| 6 | 8 | ||
| ... | @@ -10,5 +12,6 @@ const pinia = createPinia() | ... | @@ -10,5 +12,6 @@ const pinia = createPinia() |
| 10 | 12 | ||
| 11 | app.use(pinia) | 13 | app.use(pinia) |
| 12 | app.use(router) | 14 | app.use(router) |
| 15 | +app.use(ElementPlus) | ||
| 13 | // 挂载应用 | 16 | // 挂载应用 |
| 14 | app.mount('#app') | 17 | app.mount('#app') | ... | ... |
| ... | @@ -153,6 +153,24 @@ const staticRoutes: RouteRecordRaw[] = [ | ... | @@ -153,6 +153,24 @@ const staticRoutes: RouteRecordRaw[] = [ |
| 153 | } | 153 | } |
| 154 | }, | 154 | }, |
| 155 | { | 155 | { |
| 156 | + path: 'exception-workorder', | ||
| 157 | + name: 'ExceptionWorkorder', | ||
| 158 | + component: () => import('@/views/exceptionWorkorder/index.vue'), | ||
| 159 | + meta: { | ||
| 160 | + title: '异常工单', | ||
| 161 | + requiresAuth: true | ||
| 162 | + } | ||
| 163 | + }, | ||
| 164 | + { | ||
| 165 | + path: 'test-menu', | ||
| 166 | + name: 'TestMenu', | ||
| 167 | + component: () => import('@/views/test-menu.vue'), | ||
| 168 | + meta: { | ||
| 169 | + title: '菜单测试', | ||
| 170 | + requiresAuth: true | ||
| 171 | + } | ||
| 172 | + }, | ||
| 173 | + { | ||
| 156 | path: 'settings', | 174 | path: 'settings', |
| 157 | name: 'Settings', | 175 | name: 'Settings', |
| 158 | component: () => import('@/views/settings/index.vue'), | 176 | component: () => import('@/views/settings/index.vue'), | ... | ... |
| ... | @@ -46,6 +46,11 @@ service.interceptors.request.use( | ... | @@ -46,6 +46,11 @@ service.interceptors.request.use( |
| 46 | // 响应拦截器 | 46 | // 响应拦截器 |
| 47 | service.interceptors.response.use( | 47 | service.interceptors.response.use( |
| 48 | (response: AxiosResponse) => { | 48 | (response: AxiosResponse) => { |
| 49 | + // 如果是blob响应(文件下载),直接返回 | ||
| 50 | + if (response.config.responseType === 'blob') { | ||
| 51 | + return response.data | ||
| 52 | + } | ||
| 53 | + | ||
| 49 | const { code, message, data } = response.data | 54 | const { code, message, data } = response.data |
| 50 | 55 | ||
| 51 | // 请求成功 | 56 | // 请求成功 |
| ... | @@ -121,8 +126,8 @@ export const request = { | ... | @@ -121,8 +126,8 @@ export const request = { |
| 121 | return service.get(url, { params }) | 126 | return service.get(url, { params }) |
| 122 | }, | 127 | }, |
| 123 | 128 | ||
| 124 | - post<T = any>(url: string, data?: any): Promise<T> { | 129 | + post<T = any>(url: string, data?: any, config?: any): Promise<T> { |
| 125 | - return service.post(url, data) | 130 | + return service.post(url, data, config) |
| 126 | }, | 131 | }, |
| 127 | 132 | ||
| 128 | put<T = any>(url: string, data?: any): Promise<T> { | 133 | put<T = any>(url: string, data?: any): Promise<T> { | ... | ... |
| ... | @@ -2,7 +2,8 @@ | ... | @@ -2,7 +2,8 @@ |
| 2 | <div class="dashboard-container"> | 2 | <div class="dashboard-container"> |
| 3 | <div class="dashboard-header"> | 3 | <div class="dashboard-header"> |
| 4 | <h2>系统概览</h2> | 4 | <h2>系统概览</h2> |
| 5 | - <p>欢迎回来,{{ userInfo?.username || '用户' }}!</p> | 5 | + <p v-if="loading">正在加载用户信息...</p> |
| 6 | + <p v-else>欢迎回来,{{ userInfo?.username || '未知' }}!</p> | ||
| 6 | </div> | 7 | </div> |
| 7 | 8 | ||
| 8 | <div class="dashboard-stats"> | 9 | <div class="dashboard-stats"> |
| ... | @@ -43,32 +44,34 @@ | ... | @@ -43,32 +44,34 @@ |
| 43 | <div class="dashboard-card"> | 44 | <div class="dashboard-card"> |
| 44 | <h3>系统信息</h3> | 45 | <h3>系统信息</h3> |
| 45 | <div class="info-grid"> | 46 | <div class="info-grid"> |
| 46 | - <div class="info-item"> | 47 | + <div class="info-item"> |
| 47 | <label>用户名:</label> | 48 | <label>用户名:</label> |
| 48 | - <span>{{ userInfo?.username || '未知' }}</span> | 49 | + <span v-if="loading">加载中...</span> |
| 49 | - </div> | 50 | + <span v-else>{{ userInfo?.username || '未知' }}</span> |
| 50 | - <div class="info-item"> | 51 | + </div> |
| 52 | + <div class="info-item"> | ||
| 51 | <label>角色:</label> | 53 | <label>角色:</label> |
| 52 | - <span>{{ userInfo?.roles?.[0]?.roleName || '普通用户' }}</span> | 54 | + <span v-if="loading">加载中...</span> |
| 53 | - </div> | 55 | + <span v-else>{{ getRoleName(userInfo) || '普通用户' }}</span> |
| 54 | - <div class="info-item"> | 56 | + </div> |
| 57 | + <div class="info-item"> | ||
| 55 | <label>登录时间:</label> | 58 | <label>登录时间:</label> |
| 56 | <span>{{ currentTime }}</span> | 59 | <span>{{ currentTime }}</span> |
| 57 | - </div> | 60 | + </div> |
| 58 | - <div class="info-item"> | 61 | + <div class="info-item"> |
| 59 | <label>系统版本:</label> | 62 | <label>系统版本:</label> |
| 60 | <span>v1.0.0</span> | 63 | <span>v1.0.0</span> |
| 61 | </div> | 64 | </div> |
| 62 | - </div> | 65 | + </div> |
| 63 | </div> | 66 | </div> |
| 64 | 67 | ||
| 65 | <div class="dashboard-card"> | 68 | <div class="dashboard-card"> |
| 66 | <h3>快速操作</h3> | 69 | <h3>快速操作</h3> |
| 67 | <div class="quick-actions"> | 70 | <div class="quick-actions"> |
| 68 | - <button class="action-btn">👤 用户管理</button> | 71 | + <button class="action-btn" @click="navigateTo('/main/users')">👤 用户管理</button> |
| 69 | - <button class="action-btn">🛡️ 角色管理</button> | 72 | + <button class="action-btn" @click="navigateTo('/main/sys/role')">🛡️ 角色管理</button> |
| 70 | - <button class="action-btn">⚙️ 系统设置</button> | 73 | + <button class="action-btn" @click="navigateTo('/main/settings')">⚙️ 系统设置</button> |
| 71 | - <button class="action-btn">📊 查看日志</button> | 74 | + <button class="action-btn" @click="navigateTo('/main/sys/log')">📊 查看日志</button> |
| 72 | </div> | 75 | </div> |
| 73 | </div> | 76 | </div> |
| 74 | </div> | 77 | </div> |
| ... | @@ -78,28 +81,85 @@ | ... | @@ -78,28 +81,85 @@ |
| 78 | <script setup lang="ts"> | 81 | <script setup lang="ts"> |
| 79 | import { ref, onMounted } from 'vue' | 82 | import { ref, onMounted } from 'vue' |
| 80 | import { useRouter } from 'vue-router' | 83 | import { useRouter } from 'vue-router' |
| 84 | +import { request } from '@/utils/request' | ||
| 81 | 85 | ||
| 82 | const router = useRouter() | 86 | const router = useRouter() |
| 83 | const currentTime = ref('') | 87 | const currentTime = ref('') |
| 84 | const userInfo = ref<any>(null) | 88 | const userInfo = ref<any>(null) |
| 89 | +const loading = ref(false) | ||
| 90 | + | ||
| 91 | +// 获取角色名称 | ||
| 92 | +const getRoleName = (userInfo: any) => { | ||
| 93 | + // 优先使用roles字段中的角色信息 | ||
| 94 | + if (userInfo?.roles && Array.isArray(userInfo.roles) && userInfo.roles.length > 0) { | ||
| 95 | + return userInfo.roles[0].roleName || '普通用户' | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + // 如果没有roles字段,回退到authorities | ||
| 99 | + const authorities = userInfo?.authorities | ||
| 100 | + if (authorities && Array.isArray(authorities)) { | ||
| 101 | + // 查找ROLE_开头的权限 | ||
| 102 | + const roleAuthority = authorities.find(auth => | ||
| 103 | + auth.authority && auth.authority.startsWith('ROLE_') | ||
| 104 | + ) | ||
| 105 | + | ||
| 106 | + if (roleAuthority) { | ||
| 107 | + // 移除ROLE_前缀并转换为中文 | ||
| 108 | + const roleName = roleAuthority.authority.replace('ROLE_', '') | ||
| 109 | + const roleMap: { [key: string]: string } = { | ||
| 110 | + 'ADMIN': '管理员', | ||
| 111 | + 'USER': '普通用户', | ||
| 112 | + 'MANAGER': '经理', | ||
| 113 | + 'OPERATOR': '操作员' | ||
| 114 | + } | ||
| 115 | + return roleMap[roleName] || roleName | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + return '普通用户' | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +// 获取用户信息 | ||
| 123 | +const fetchUserInfo = async () => { | ||
| 124 | + try { | ||
| 125 | + loading.value = true | ||
| 126 | + const response = await request.get('/api/auth/userinfo') | ||
| 127 | + userInfo.value = response | ||
| 128 | + console.log('用户信息:', response) | ||
| 129 | + } catch (error) { | ||
| 130 | + console.error('获取用户信息失败:', error) | ||
| 131 | + // 如果获取失败,尝试从本地存储获取 | ||
| 132 | + const storedUserInfo = localStorage.getItem('userInfo') | ||
| 133 | + if (storedUserInfo) { | ||
| 134 | + userInfo.value = JSON.parse(storedUserInfo) | ||
| 135 | + } | ||
| 136 | + } finally { | ||
| 137 | + loading.value = false | ||
| 138 | + } | ||
| 139 | +} | ||
| 85 | 140 | ||
| 86 | onMounted(() => { | 141 | onMounted(() => { |
| 87 | // 获取当前时间 | 142 | // 获取当前时间 |
| 88 | currentTime.value = new Date().toLocaleString() | 143 | currentTime.value = new Date().toLocaleString() |
| 89 | 144 | ||
| 90 | - // 获取用户信息 | ||
| 91 | - const storedUserInfo = localStorage.getItem('userInfo') | ||
| 92 | - if (storedUserInfo) { | ||
| 93 | - userInfo.value = JSON.parse(storedUserInfo) | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | // 检查是否已登录 | 145 | // 检查是否已登录 |
| 97 | const token = localStorage.getItem('token') | 146 | const token = localStorage.getItem('token') |
| 98 | if (!token) { | 147 | if (!token) { |
| 99 | router.push('/') | 148 | router.push('/') |
| 149 | + return | ||
| 100 | } | 150 | } |
| 151 | + | ||
| 152 | + // 获取用户信息 | ||
| 153 | + fetchUserInfo() | ||
| 101 | }) | 154 | }) |
| 102 | 155 | ||
| 156 | +// 页面跳转函数 | ||
| 157 | +const navigateTo = (path: string) => { | ||
| 158 | + router.push(path).catch(err => { | ||
| 159 | + console.error('页面跳转失败:', err) | ||
| 160 | + }) | ||
| 161 | +} | ||
| 162 | + | ||
| 103 | const logout = () => { | 163 | const logout = () => { |
| 104 | // 清除本地存储 | 164 | // 清除本地存储 |
| 105 | localStorage.removeItem('token') | 165 | localStorage.removeItem('token') | ... | ... |
| ... | @@ -244,8 +244,13 @@ | ... | @@ -244,8 +244,13 @@ |
| 244 | </tr> | 244 | </tr> |
| 245 | </thead> | 245 | </thead> |
| 246 | <tbody> | 246 | <tbody> |
| 247 | +<<<<<<< .mine | ||
| 247 | <tr v-for="item in deliveryDetail.deliveryItems" :key="item.deliveryItemId"> | 248 | <tr v-for="item in deliveryDetail.deliveryItems" :key="item.deliveryItemId"> |
| 248 | <td>{{ item.productName }}</td> | 249 | <td>{{ item.productName }}</td> |
| 250 | +======= | ||
| 251 | + <tr v-for="item in deliveryDetail.deliveryItems" :key="item.itemId || item.deliveryId"> | ||
| 252 | + | ||
| 253 | +>>>>>>> .theirs | ||
| 249 | <td>{{ item.productCode }}</td> | 254 | <td>{{ item.productCode }}</td> |
| 250 | <td>{{ item.deliveryQty }}</td> | 255 | <td>{{ item.deliveryQty }}</td> |
| 251 | <td>{{ formatCurrency(item.deliveryPrice) }}</td> | 256 | <td>{{ formatCurrency(item.deliveryPrice) }}</td> |
| ... | @@ -627,6 +632,7 @@ | ... | @@ -627,6 +632,7 @@ |
| 627 | 632 | ||
| 628 | <script setup lang="ts"> | 633 | <script setup lang="ts"> |
| 629 | import { ref, reactive, computed, onMounted } from 'vue' | 634 | import { ref, reactive, computed, onMounted } from 'vue' |
| 635 | +import { ElMessage, ElMessageBox } from 'element-plus' | ||
| 630 | import { deliveryApi, type DeliveryAddReq, type DeliveryInfo, type DeliveryQueryReq } from '../../api/delivery' | 636 | import { deliveryApi, type DeliveryAddReq, type DeliveryInfo, type DeliveryQueryReq } from '../../api/delivery' |
| 631 | import { dealerApi, type DealerInfo } from '../../api/dealer' | 637 | import { dealerApi, type DealerInfo } from '../../api/dealer' |
| 632 | import { productApi } from '../../api/product' | 638 | import { productApi } from '../../api/product' |
| ... | @@ -729,7 +735,12 @@ const formatCurrency = (amount: number) => { | ... | @@ -729,7 +735,12 @@ const formatCurrency = (amount: number) => { |
| 729 | // 消息提示 | 735 | // 消息提示 |
| 730 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { | 736 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { |
| 731 | console.log(`${type}: ${message}`) | 737 | console.log(`${type}: ${message}`) |
| 732 | - alert(message) | 738 | + ElMessage({ |
| 739 | + message, | ||
| 740 | + type, | ||
| 741 | + duration: 3000, | ||
| 742 | + showClose: true | ||
| 743 | + }) | ||
| 733 | } | 744 | } |
| 734 | 745 | ||
| 735 | // 获取页码数组 | 746 | // 获取页码数组 |
| ... | @@ -868,8 +879,78 @@ const handleDelete = async (delivery: DeliveryInfo) => { | ... | @@ -868,8 +879,78 @@ const handleDelete = async (delivery: DeliveryInfo) => { |
| 868 | } | 879 | } |
| 869 | 880 | ||
| 870 | 881 | ||
| 871 | -const handleExport = () => { | 882 | +const handleExport = async () => { |
| 872 | - showMessage('导出功能开发中...', 'warning') | 883 | + try { |
| 884 | + // 显示确认弹窗 | ||
| 885 | + await ElMessageBox.confirm( | ||
| 886 | + '确定要导出出库数据吗?导出将包含当前筛选条件下的所有数据。', | ||
| 887 | + '确认导出', | ||
| 888 | + { | ||
| 889 | + confirmButtonText: '确定导出', | ||
| 890 | + cancelButtonText: '取消', | ||
| 891 | + type: 'warning', | ||
| 892 | + center: true | ||
| 893 | + } | ||
| 894 | + ) | ||
| 895 | + | ||
| 896 | + // 用户确认后显示加载提示 | ||
| 897 | + const loadingMessage = ElMessage({ | ||
| 898 | + message: '正在导出数据,请稍候...', | ||
| 899 | + type: 'warning', | ||
| 900 | + duration: 0, // 不自动关闭 | ||
| 901 | + showClose: false | ||
| 902 | + }) | ||
| 903 | + | ||
| 904 | + try { | ||
| 905 | + // 准备导出参数 | ||
| 906 | + const exportParams = { | ||
| 907 | + deliveryNo: searchParams.deliveryNo, | ||
| 908 | + dealerCode: searchParams.dealerCode, | ||
| 909 | + dealerName: searchParams.dealerName, | ||
| 910 | + deliveryStatus: searchParams.deliveryStatus, | ||
| 911 | + warehouseCode: searchParams.warehouseCode, | ||
| 912 | + dataSource: searchParams.dataSource, | ||
| 913 | + deliveryStartDate: searchParams.deliveryStartDate, | ||
| 914 | + deliveryEndDate: searchParams.deliveryEndDate | ||
| 915 | + } | ||
| 916 | + | ||
| 917 | + // 调用导出接口 | ||
| 918 | + const response = await deliveryApi.exportDeliveries(exportParams) | ||
| 919 | + | ||
| 920 | + // 创建下载链接 | ||
| 921 | + const blob = new Blob([response], { | ||
| 922 | + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | ||
| 923 | + }) | ||
| 924 | + const url = window.URL.createObjectURL(blob) | ||
| 925 | + const link = document.createElement('a') | ||
| 926 | + link.href = url | ||
| 927 | + | ||
| 928 | + // 生成文件名 | ||
| 929 | + const timestamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, '').slice(0, 14) | ||
| 930 | + link.download = `出库数据_${timestamp}.xlsx` | ||
| 931 | + | ||
| 932 | + // 触发下载 | ||
| 933 | + document.body.appendChild(link) | ||
| 934 | + link.click() | ||
| 935 | + document.body.removeChild(link) | ||
| 936 | + window.URL.revokeObjectURL(url) | ||
| 937 | + | ||
| 938 | + // 关闭加载提示,显示成功消息 | ||
| 939 | + loadingMessage.close() | ||
| 940 | + ElMessage.success('导出成功!文件已开始下载') | ||
| 941 | + | ||
| 942 | + } catch (exportError) { | ||
| 943 | + // 关闭加载提示 | ||
| 944 | + loadingMessage.close() | ||
| 945 | + throw exportError | ||
| 946 | + } | ||
| 947 | + | ||
| 948 | + } catch (error) { | ||
| 949 | + if (error !== 'cancel') { | ||
| 950 | + console.error('导出失败:', error) | ||
| 951 | + ElMessage.error('导出失败,请重试') | ||
| 952 | + } | ||
| 953 | + } | ||
| 873 | } | 954 | } |
| 874 | 955 | ||
| 875 | // 新增出库相关函数 | 956 | // 新增出库相关函数 | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -517,6 +517,7 @@ | ... | @@ -517,6 +517,7 @@ |
| 517 | 517 | ||
| 518 | <script setup lang="ts"> | 518 | <script setup lang="ts"> |
| 519 | import { ref, reactive, computed, onMounted } from 'vue' | 519 | import { ref, reactive, computed, onMounted } from 'vue' |
| 520 | +import { ElMessage, ElMessageBox } from 'element-plus' | ||
| 520 | import { invoiceApi, type InvoiceInfo, type InvoiceQueryReq } from '../../api/invoice' | 521 | import { invoiceApi, type InvoiceInfo, type InvoiceQueryReq } from '../../api/invoice' |
| 521 | import { dealerApi, type DealerInfo } from '../../api/dealer' | 522 | import { dealerApi, type DealerInfo } from '../../api/dealer' |
| 522 | import { productApi } from '../../api/product' | 523 | import { productApi } from '../../api/product' |
| ... | @@ -609,7 +610,12 @@ const formatCurrency = (amount: number) => { | ... | @@ -609,7 +610,12 @@ const formatCurrency = (amount: number) => { |
| 609 | // 消息提示 | 610 | // 消息提示 |
| 610 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { | 611 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { |
| 611 | console.log(`${type}: ${message}`) | 612 | console.log(`${type}: ${message}`) |
| 612 | - alert(message) | 613 | + ElMessage({ |
| 614 | + message, | ||
| 615 | + type, | ||
| 616 | + duration: 3000, | ||
| 617 | + showClose: true | ||
| 618 | + }) | ||
| 613 | } | 619 | } |
| 614 | 620 | ||
| 615 | // 获取页码数组 | 621 | // 获取页码数组 |
| ... | @@ -840,8 +846,81 @@ const handleView = async (order: InvoiceInfo) => { | ... | @@ -840,8 +846,81 @@ const handleView = async (order: InvoiceInfo) => { |
| 840 | } | 846 | } |
| 841 | 847 | ||
| 842 | 848 | ||
| 843 | -const handleExport = () => { | 849 | +const handleExport = async () => { |
| 844 | - showMessage('导出功能开发中...', 'warning') | 850 | + try { |
| 851 | + // 显示确认弹窗 | ||
| 852 | + await ElMessageBox.confirm( | ||
| 853 | + '确定要导出发票数据吗?导出将包含当前筛选条件下的所有数据。', | ||
| 854 | + '确认导出', | ||
| 855 | + { | ||
| 856 | + confirmButtonText: '确定导出', | ||
| 857 | + cancelButtonText: '取消', | ||
| 858 | + type: 'warning', | ||
| 859 | + center: true | ||
| 860 | + } | ||
| 861 | + ) | ||
| 862 | + | ||
| 863 | + // 用户确认后显示加载提示 | ||
| 864 | + const loadingMessage = ElMessage({ | ||
| 865 | + message: '正在导出数据,请稍候...', | ||
| 866 | + type: 'warning', | ||
| 867 | + duration: 0, // 不自动关闭 | ||
| 868 | + showClose: false | ||
| 869 | + }) | ||
| 870 | + | ||
| 871 | + try { | ||
| 872 | + // 准备导出参数 | ||
| 873 | + const exportParams = { | ||
| 874 | + invoiceNo: searchParams.invoiceNo, | ||
| 875 | + orderNo: searchParams.orderNo, | ||
| 876 | + deliveryNo: searchParams.deliveryNo, | ||
| 877 | + dealerCode: searchParams.dealerCode, | ||
| 878 | + dealerName: searchParams.dealerName, | ||
| 879 | + invoiceStatus: searchParams.invoiceStatus, | ||
| 880 | + dataSource: searchParams.dataSource, | ||
| 881 | + invoiceStartDate: searchParams.invoiceStartDate, | ||
| 882 | + invoiceEndDate: searchParams.invoiceEndDate, | ||
| 883 | + minAmount: searchParams.minAmount, | ||
| 884 | + maxAmount: searchParams.maxAmount | ||
| 885 | + } | ||
| 886 | + | ||
| 887 | + // 调用导出接口 | ||
| 888 | + const response = await invoiceApi.exportInvoices(exportParams) | ||
| 889 | + | ||
| 890 | + // 创建下载链接 | ||
| 891 | + const blob = new Blob([response], { | ||
| 892 | + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | ||
| 893 | + }) | ||
| 894 | + const url = window.URL.createObjectURL(blob) | ||
| 895 | + const link = document.createElement('a') | ||
| 896 | + link.href = url | ||
| 897 | + | ||
| 898 | + // 生成文件名 | ||
| 899 | + const timestamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, '').slice(0, 14) | ||
| 900 | + link.download = `发票数据_${timestamp}.xlsx` | ||
| 901 | + | ||
| 902 | + // 触发下载 | ||
| 903 | + document.body.appendChild(link) | ||
| 904 | + link.click() | ||
| 905 | + document.body.removeChild(link) | ||
| 906 | + window.URL.revokeObjectURL(url) | ||
| 907 | + | ||
| 908 | + // 关闭加载提示,显示成功消息 | ||
| 909 | + loadingMessage.close() | ||
| 910 | + ElMessage.success('导出成功!文件已开始下载') | ||
| 911 | + | ||
| 912 | + } catch (exportError) { | ||
| 913 | + // 关闭加载提示 | ||
| 914 | + loadingMessage.close() | ||
| 915 | + throw exportError | ||
| 916 | + } | ||
| 917 | + | ||
| 918 | + } catch (error) { | ||
| 919 | + if (error !== 'cancel') { | ||
| 920 | + console.error('导出失败:', error) | ||
| 921 | + ElMessage.error('导出失败,请重试') | ||
| 922 | + } | ||
| 923 | + } | ||
| 845 | } | 924 | } |
| 846 | 925 | ||
| 847 | const handlePrintInvoice = (invoice: InvoiceInfo) => { | 926 | const handlePrintInvoice = (invoice: InvoiceInfo) => { | ... | ... |
| ... | @@ -462,6 +462,7 @@ | ... | @@ -462,6 +462,7 @@ |
| 462 | 462 | ||
| 463 | <script setup lang="ts"> | 463 | <script setup lang="ts"> |
| 464 | import { ref, reactive, computed, onMounted } from 'vue' | 464 | import { ref, reactive, computed, onMounted } from 'vue' |
| 465 | +import { ElMessage, ElMessageBox } from 'element-plus' | ||
| 465 | import { orderApi, type OrderInfo, type OrderQueryReq, type OrderAddReq, type OrderUpdateReq, type OrderItemAddReq } from '../../api/order' | 466 | import { orderApi, type OrderInfo, type OrderQueryReq, type OrderAddReq, type OrderUpdateReq, type OrderItemAddReq } from '../../api/order' |
| 466 | import { dealerApi, type DealerInfo } from '../../api/dealer' | 467 | import { dealerApi, type DealerInfo } from '../../api/dealer' |
| 467 | import { productApi } from '../../api/product' | 468 | import { productApi } from '../../api/product' |
| ... | @@ -606,9 +607,12 @@ const formatCurrency = (amount: number) => { | ... | @@ -606,9 +607,12 @@ const formatCurrency = (amount: number) => { |
| 606 | 607 | ||
| 607 | // 消息提示 | 608 | // 消息提示 |
| 608 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { | 609 | const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => { |
| 609 | - // 这里可以集成消息提示组件 | 610 | + ElMessage({ |
| 610 | - console.log(`${type}: ${message}`) | 611 | + message, |
| 611 | - alert(message) | 612 | + type, |
| 613 | + duration: 3000, | ||
| 614 | + showClose: true | ||
| 615 | + }) | ||
| 612 | } | 616 | } |
| 613 | 617 | ||
| 614 | // 方法 | 618 | // 方法 |
| ... | @@ -786,8 +790,82 @@ const handleBatchDelete = async () => { | ... | @@ -786,8 +790,82 @@ const handleBatchDelete = async () => { |
| 786 | } | 790 | } |
| 787 | 791 | ||
| 788 | 792 | ||
| 789 | -const handleExport = () => { | 793 | +const handleExport = async () => { |
| 790 | - showMessage('导出功能开发中...', 'warning') | 794 | + try { |
| 795 | + // 显示确认弹窗 | ||
| 796 | + await ElMessageBox.confirm( | ||
| 797 | + '确定要导出订单数据吗?导出将包含当前筛选条件下的所有数据。', | ||
| 798 | + '确认导出', | ||
| 799 | + { | ||
| 800 | + confirmButtonText: '确定导出', | ||
| 801 | + cancelButtonText: '取消', | ||
| 802 | + type: 'warning', | ||
| 803 | + center: true | ||
| 804 | + } | ||
| 805 | + ) | ||
| 806 | + | ||
| 807 | + // 用户确认后显示加载提示 | ||
| 808 | + const loadingMessage = ElMessage({ | ||
| 809 | + message: '正在导出数据,请稍候...', | ||
| 810 | + type: 'warning', | ||
| 811 | + duration: 0, // 不自动关闭 | ||
| 812 | + showClose: false | ||
| 813 | + }) | ||
| 814 | + | ||
| 815 | + try { | ||
| 816 | + // 准备导出参数 | ||
| 817 | + const exportParams = { | ||
| 818 | + orderNo: searchParams.orderNo, | ||
| 819 | + dealerCode: searchParams.dealerCode, | ||
| 820 | + dealerName: searchParams.dealerName, | ||
| 821 | + deliveryStatus: searchParams.deliveryStatus, | ||
| 822 | + invoiceStatus: searchParams.invoiceStatus, | ||
| 823 | + rebateCalcFlag: searchParams.rebateCalcFlag, | ||
| 824 | + dataSource: searchParams.dataSource, | ||
| 825 | + verifyStatus: searchParams.verifyStatus, | ||
| 826 | + orderStartDate: searchParams.orderStartDate, | ||
| 827 | + orderEndDate: searchParams.orderEndDate, | ||
| 828 | + minAmount: searchParams.minAmount, | ||
| 829 | + maxAmount: searchParams.maxAmount | ||
| 830 | + } | ||
| 831 | + | ||
| 832 | + // 调用导出接口 | ||
| 833 | + const response = await orderApi.exportOrders(exportParams) | ||
| 834 | + | ||
| 835 | + // 创建下载链接 | ||
| 836 | + const blob = new Blob([response], { | ||
| 837 | + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | ||
| 838 | + }) | ||
| 839 | + const url = window.URL.createObjectURL(blob) | ||
| 840 | + const link = document.createElement('a') | ||
| 841 | + link.href = url | ||
| 842 | + | ||
| 843 | + // 生成文件名 | ||
| 844 | + const timestamp = new Date().toISOString().slice(0, 19).replace(/[-:T]/g, '').slice(0, 14) | ||
| 845 | + link.download = `订单数据_${timestamp}.xlsx` | ||
| 846 | + | ||
| 847 | + // 触发下载 | ||
| 848 | + document.body.appendChild(link) | ||
| 849 | + link.click() | ||
| 850 | + document.body.removeChild(link) | ||
| 851 | + window.URL.revokeObjectURL(url) | ||
| 852 | + | ||
| 853 | + // 关闭加载提示,显示成功消息 | ||
| 854 | + loadingMessage.close() | ||
| 855 | + ElMessage.success('导出成功!文件已开始下载') | ||
| 856 | + | ||
| 857 | + } catch (exportError) { | ||
| 858 | + // 关闭加载提示 | ||
| 859 | + loadingMessage.close() | ||
| 860 | + throw exportError | ||
| 861 | + } | ||
| 862 | + | ||
| 863 | + } catch (error) { | ||
| 864 | + if (error !== 'cancel') { | ||
| 865 | + console.error('导出失败:', error) | ||
| 866 | + ElMessage.error('导出失败,请重试') | ||
| 867 | + } | ||
| 868 | + } | ||
| 791 | } | 869 | } |
| 792 | 870 | ||
| 793 | const handleSelectAll = () => { | 871 | const handleSelectAll = () => { | ... | ... |
This diff is collapsed. Click to expand it.
frontend/src/views/settings/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="settings-container"> | ||
| 3 | + <!-- 页面标题 --> | ||
| 4 | + <div class="page-header"> | ||
| 5 | + <h2>系统设置</h2> | ||
| 6 | + <p>管理系统配置和参数</p> | ||
| 7 | + </div> | ||
| 8 | + | ||
| 9 | + <!-- 设置内容 --> | ||
| 10 | + <div class="settings-content"> | ||
| 11 | + <div class="settings-card"> | ||
| 12 | + <h3>基本设置</h3> | ||
| 13 | + <div class="setting-item"> | ||
| 14 | + <label>系统名称:</label> | ||
| 15 | + <input v-model="settings.systemName" class="setting-input" placeholder="请输入系统名称" /> | ||
| 16 | + </div> | ||
| 17 | + <div class="setting-item"> | ||
| 18 | + <label>系统版本:</label> | ||
| 19 | + <input v-model="settings.systemVersion" class="setting-input" placeholder="请输入系统版本" /> | ||
| 20 | + </div> | ||
| 21 | + <div class="setting-item"> | ||
| 22 | + <label>系统描述:</label> | ||
| 23 | + <textarea v-model="settings.systemDescription" class="setting-textarea" placeholder="请输入系统描述"></textarea> | ||
| 24 | + </div> | ||
| 25 | + </div> | ||
| 26 | + | ||
| 27 | + <div class="settings-card"> | ||
| 28 | + <h3>业务设置</h3> | ||
| 29 | + <div class="setting-item"> | ||
| 30 | + <label>默认分页大小:</label> | ||
| 31 | + <select v-model="settings.defaultPageSize" class="setting-select"> | ||
| 32 | + <option value="10">10条/页</option> | ||
| 33 | + <option value="20">20条/页</option> | ||
| 34 | + <option value="50">50条/页</option> | ||
| 35 | + <option value="100">100条/页</option> | ||
| 36 | + </select> | ||
| 37 | + </div> | ||
| 38 | + <div class="setting-item"> | ||
| 39 | + <label>数据保留天数:</label> | ||
| 40 | + <input v-model="settings.dataRetentionDays" type="number" class="setting-input" placeholder="请输入数据保留天数" /> | ||
| 41 | + </div> | ||
| 42 | + <div class="setting-item"> | ||
| 43 | + <label>自动备份:</label> | ||
| 44 | + <label class="checkbox-label"> | ||
| 45 | + <input v-model="settings.autoBackup" type="checkbox" /> | ||
| 46 | + <span>启用自动备份</span> | ||
| 47 | + </label> | ||
| 48 | + </div> | ||
| 49 | + </div> | ||
| 50 | + | ||
| 51 | + <div class="settings-card"> | ||
| 52 | + <h3>安全设置</h3> | ||
| 53 | + <div class="setting-item"> | ||
| 54 | + <label>会话超时时间(分钟):</label> | ||
| 55 | + <input v-model="settings.sessionTimeout" type="number" class="setting-input" placeholder="请输入会话超时时间" /> | ||
| 56 | + </div> | ||
| 57 | + <div class="setting-item"> | ||
| 58 | + <label>密码复杂度:</label> | ||
| 59 | + <select v-model="settings.passwordComplexity" class="setting-select"> | ||
| 60 | + <option value="low">低</option> | ||
| 61 | + <option value="medium">中</option> | ||
| 62 | + <option value="high">高</option> | ||
| 63 | + </select> | ||
| 64 | + </div> | ||
| 65 | + <div class="setting-item"> | ||
| 66 | + <label>登录失败锁定:</label> | ||
| 67 | + <label class="checkbox-label"> | ||
| 68 | + <input v-model="settings.loginLock" type="checkbox" /> | ||
| 69 | + <span>启用登录失败锁定</span> | ||
| 70 | + </label> | ||
| 71 | + </div> | ||
| 72 | + </div> | ||
| 73 | + | ||
| 74 | + <div class="settings-card"> | ||
| 75 | + <h3>通知设置</h3> | ||
| 76 | + <div class="setting-item"> | ||
| 77 | + <label>邮件通知:</label> | ||
| 78 | + <label class="checkbox-label"> | ||
| 79 | + <input v-model="settings.emailNotification" type="checkbox" /> | ||
| 80 | + <span>启用邮件通知</span> | ||
| 81 | + </label> | ||
| 82 | + </div> | ||
| 83 | + <div class="setting-item"> | ||
| 84 | + <label>短信通知:</label> | ||
| 85 | + <label class="checkbox-label"> | ||
| 86 | + <input v-model="settings.smsNotification" type="checkbox" /> | ||
| 87 | + <span>启用短信通知</span> | ||
| 88 | + </label> | ||
| 89 | + </div> | ||
| 90 | + <div class="setting-item"> | ||
| 91 | + <label>系统消息:</label> | ||
| 92 | + <label class="checkbox-label"> | ||
| 93 | + <input v-model="settings.systemMessage" type="checkbox" /> | ||
| 94 | + <span>启用系统消息</span> | ||
| 95 | + </label> | ||
| 96 | + </div> | ||
| 97 | + </div> | ||
| 98 | + | ||
| 99 | + <!-- 操作按钮 --> | ||
| 100 | + <div class="settings-actions"> | ||
| 101 | + <button @click="handleSave" class="action-btn primary">💾 保存设置</button> | ||
| 102 | + <button @click="handleReset" class="action-btn secondary">🔄 重置</button> | ||
| 103 | + <button @click="handleTest" class="action-btn info">🧪 测试连接</button> | ||
| 104 | + </div> | ||
| 105 | + </div> | ||
| 106 | + </div> | ||
| 107 | +</template> | ||
| 108 | + | ||
| 109 | +<script setup lang="ts"> | ||
| 110 | +import { ref, reactive, onMounted } from 'vue' | ||
| 111 | + | ||
| 112 | +// 设置数据 | ||
| 113 | +const settings = reactive({ | ||
| 114 | + systemName: 'Apple ERP系统', | ||
| 115 | + systemVersion: '1.0.0', | ||
| 116 | + systemDescription: '企业资源规划管理系统', | ||
| 117 | + defaultPageSize: 20, | ||
| 118 | + dataRetentionDays: 365, | ||
| 119 | + autoBackup: true, | ||
| 120 | + sessionTimeout: 30, | ||
| 121 | + passwordComplexity: 'medium', | ||
| 122 | + loginLock: true, | ||
| 123 | + emailNotification: true, | ||
| 124 | + smsNotification: false, | ||
| 125 | + systemMessage: true | ||
| 126 | +}) | ||
| 127 | + | ||
| 128 | +// 原始设置(用于重置) | ||
| 129 | +const originalSettings = ref({}) | ||
| 130 | + | ||
| 131 | +// 保存设置 | ||
| 132 | +const handleSave = () => { | ||
| 133 | + // 这里可以调用后端API保存设置 | ||
| 134 | + console.log('保存设置:', settings) | ||
| 135 | + showMessage('设置保存成功', 'success') | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +// 重置设置 | ||
| 139 | +const handleReset = () => { | ||
| 140 | + Object.assign(settings, originalSettings.value) | ||
| 141 | + showMessage('设置已重置', 'warning') | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +// 测试连接 | ||
| 145 | +const handleTest = () => { | ||
| 146 | + showMessage('连接测试成功', 'success') | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +// 显示消息 | ||
| 150 | +const showMessage = (message: string, type: 'success' | 'warning' | 'error') => { | ||
| 151 | + // 这里可以集成Element Plus的消息组件 | ||
| 152 | + console.log(`${type}: ${message}`) | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +// 组件挂载时加载设置 | ||
| 156 | +onMounted(() => { | ||
| 157 | + // 这里可以调用后端API加载设置 | ||
| 158 | + originalSettings.value = { ...settings } | ||
| 159 | +}) | ||
| 160 | +</script> | ||
| 161 | + | ||
| 162 | +<style scoped> | ||
| 163 | +.settings-container { | ||
| 164 | + padding: 20px; | ||
| 165 | + background-color: #f5f5f5; | ||
| 166 | + min-height: 100vh; | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +.page-header { | ||
| 170 | + margin-bottom: 30px; | ||
| 171 | + text-align: center; | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +.page-header h2 { | ||
| 175 | + color: #333; | ||
| 176 | + margin-bottom: 10px; | ||
| 177 | + font-size: 28px; | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +.page-header p { | ||
| 181 | + color: #666; | ||
| 182 | + font-size: 16px; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +.settings-content { | ||
| 186 | + max-width: 1200px; | ||
| 187 | + margin: 0 auto; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +.settings-card { | ||
| 191 | + background: white; | ||
| 192 | + border-radius: 8px; | ||
| 193 | + padding: 24px; | ||
| 194 | + margin-bottom: 24px; | ||
| 195 | + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +.settings-card h3 { | ||
| 199 | + color: #333; | ||
| 200 | + margin-bottom: 20px; | ||
| 201 | + font-size: 18px; | ||
| 202 | + border-bottom: 2px solid #e9ecef; | ||
| 203 | + padding-bottom: 10px; | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +.setting-item { | ||
| 207 | + display: flex; | ||
| 208 | + align-items: center; | ||
| 209 | + margin-bottom: 20px; | ||
| 210 | + gap: 16px; | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +.setting-item label { | ||
| 214 | + min-width: 150px; | ||
| 215 | + color: #333; | ||
| 216 | + font-weight: 500; | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +.setting-input, | ||
| 220 | +.setting-select, | ||
| 221 | +.setting-textarea { | ||
| 222 | + flex: 1; | ||
| 223 | + padding: 8px 12px; | ||
| 224 | + border: 1px solid #ddd; | ||
| 225 | + border-radius: 4px; | ||
| 226 | + font-size: 14px; | ||
| 227 | + transition: border-color 0.3s; | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | +.setting-input:focus, | ||
| 231 | +.setting-select:focus, | ||
| 232 | +.setting-textarea:focus { | ||
| 233 | + outline: none; | ||
| 234 | + border-color: #007bff; | ||
| 235 | + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); | ||
| 236 | +} | ||
| 237 | + | ||
| 238 | +.setting-textarea { | ||
| 239 | + min-height: 80px; | ||
| 240 | + resize: vertical; | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +.checkbox-label { | ||
| 244 | + display: flex; | ||
| 245 | + align-items: center; | ||
| 246 | + gap: 8px; | ||
| 247 | + cursor: pointer; | ||
| 248 | +} | ||
| 249 | + | ||
| 250 | +.checkbox-label input[type="checkbox"] { | ||
| 251 | + width: 16px; | ||
| 252 | + height: 16px; | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +.settings-actions { | ||
| 256 | + display: flex; | ||
| 257 | + gap: 16px; | ||
| 258 | + justify-content: center; | ||
| 259 | + margin-top: 30px; | ||
| 260 | +} | ||
| 261 | + | ||
| 262 | +.action-btn { | ||
| 263 | + padding: 12px 24px; | ||
| 264 | + border: none; | ||
| 265 | + border-radius: 6px; | ||
| 266 | + font-size: 14px; | ||
| 267 | + font-weight: 500; | ||
| 268 | + cursor: pointer; | ||
| 269 | + transition: all 0.3s; | ||
| 270 | + min-width: 120px; | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +.action-btn.primary { | ||
| 274 | + background-color: #007bff; | ||
| 275 | + color: white; | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +.action-btn.primary:hover { | ||
| 279 | + background-color: #0056b3; | ||
| 280 | +} | ||
| 281 | + | ||
| 282 | +.action-btn.secondary { | ||
| 283 | + background-color: #6c757d; | ||
| 284 | + color: white; | ||
| 285 | +} | ||
| 286 | + | ||
| 287 | +.action-btn.secondary:hover { | ||
| 288 | + background-color: #545b62; | ||
| 289 | +} | ||
| 290 | + | ||
| 291 | +.action-btn.info { | ||
| 292 | + background-color: #17a2b8; | ||
| 293 | + color: white; | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +.action-btn.info:hover { | ||
| 297 | + background-color: #138496; | ||
| 298 | +} | ||
| 299 | + | ||
| 300 | +@media (max-width: 768px) { | ||
| 301 | + .setting-item { | ||
| 302 | + flex-direction: column; | ||
| 303 | + align-items: flex-start; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + .setting-item label { | ||
| 307 | + min-width: auto; | ||
| 308 | + margin-bottom: 8px; | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + .settings-actions { | ||
| 312 | + flex-direction: column; | ||
| 313 | + align-items: center; | ||
| 314 | + } | ||
| 315 | +} | ||
| 316 | +</style> |
| ... | @@ -7,7 +7,7 @@ | ... | @@ -7,7 +7,7 @@ |
| 7 | "auto-imports.d.ts", | 7 | "auto-imports.d.ts", |
| 8 | "components.d.ts" | 8 | "components.d.ts" |
| 9 | ], | 9 | ], |
| 10 | - "exclude": ["src/**/__tests__/*"], | 10 | + "exclude": ["src/**/__tests__/*", "src/views/test-menu.vue"], |
| 11 | "compilerOptions": { | 11 | "compilerOptions": { |
| 12 | "composite": true, | 12 | "composite": true, |
| 13 | "baseUrl": ".", | 13 | "baseUrl": ".", | ... | ... |
-
Please register or login to post a comment