diff --git a/backend/pom.xml b/backend/pom.xml index db54d52..56fbc9b 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -26,6 +26,7 @@ 3.0.0 3.12.0 5.8.23 + 5.2.5 @@ -50,9 +51,9 @@ - mysql - mysql-connector-java - 8.0.33 + com.mysql + mysql-connector-j + runtime @@ -101,6 +102,24 @@ ${hutool.version} + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.springframework.security + spring-security-crypto + + org.projectlombok @@ -160,7 +179,6 @@ 3.3.0 checkstyle.xml - UTF-8 true false diff --git a/backend/src/main/com/bycrm/ByCrmApplication.java b/backend/src/main/java/com/bycrm/ByCrmApplication.java similarity index 100% rename from backend/src/main/com/bycrm/ByCrmApplication.java rename to backend/src/main/java/com/bycrm/ByCrmApplication.java diff --git a/backend/src/main/com/bycrm/annotations/AuthRequired.java b/backend/src/main/java/com/bycrm/annotations/AuthRequired.java similarity index 100% rename from backend/src/main/com/bycrm/annotations/AuthRequired.java rename to backend/src/main/java/com/bycrm/annotations/AuthRequired.java diff --git a/backend/src/main/com/bycrm/common/Constants.java b/backend/src/main/java/com/bycrm/common/Constants.java similarity index 56% rename from backend/src/main/com/bycrm/common/Constants.java rename to backend/src/main/java/com/bycrm/common/Constants.java index 468b0b8..06741b2 100644 --- a/backend/src/main/com/bycrm/common/Constants.java +++ b/backend/src/main/java/com/bycrm/common/Constants.java @@ -23,70 +23,70 @@ public class Constants { /** * 客户状态 - 可报备 */ - public static final Integer CUSTOMER_STATUS_AVAILABLE = 0; + public static final int CUSTOMER_STATUS_AVAILABLE = 0; /** * 客户状态 - 保护中 */ - public static final Integer CUSTOMER_STATUS_PROTECTED = 1; + public static final int CUSTOMER_STATUS_PROTECTED = 1; /** * 客户状态 - 已失效 */ - public static final Integer CUSTOMER_STATUS_EXPIRED = 2; + public static final int CUSTOMER_STATUS_EXPIRED = 2; /** * 报备状态 - 待审核 */ - public static final Integer REPORT_STATUS_PENDING = 0; + public static final int REPORT_STATUS_PENDING = 0; /** * 报备状态 - 已通过 */ - public static final Integer REPORT_STATUS_APPROVED = 1; + public static final int REPORT_STATUS_APPROVED = 1; /** * 报备状态 - 已驳回 */ - public static final Integer REPORT_STATUS_REJECTED = 2; + public static final int REPORT_STATUS_REJECTED = 2; /** * 报备状态 - 已失效 */ - public static final Integer REPORT_STATUS_EXPIRED = 3; + public static final int REPORT_STATUS_EXPIRED = 3; /** * 用户角色 - 管理员 */ - public static final Integer USER_ROLE_ADMIN = 0; + public static final int USER_ROLE_ADMIN = 0; /** * 用户角色 - 经销商用户 */ - public static final Integer USER_ROLE_DEALER = 1; + public static final int USER_ROLE_DEALER = 1; /** * 用户状态 - 禁用 */ - public static final Integer USER_STATUS_DISABLED = 0; + public static final int USER_STATUS_DISABLED = 0; /** * 用户状态 - 启用 */ - public static final Integer USER_STATUS_ENABLED = 1; + public static final int USER_STATUS_ENABLED = 1; /** * 经销商状态 - 禁用 */ - public static final Integer DEALER_STATUS_DISABLED = 0; + public static final int DEALER_STATUS_DISABLED = 0; /** * 经销商状态 - 启用 */ - public static final Integer DEALER_STATUS_ENABLED = 1; + public static final int DEALER_STATUS_ENABLED = 1; /** * 默认保护期天数 */ - public static final Integer DEFAULT_PROTECT_DAYS = 90; + public static final int DEFAULT_PROTECT_DAYS = 90; } diff --git a/backend/src/main/com/bycrm/common/PageResult.java b/backend/src/main/java/com/bycrm/common/PageResult.java similarity index 100% rename from backend/src/main/com/bycrm/common/PageResult.java rename to backend/src/main/java/com/bycrm/common/PageResult.java diff --git a/backend/src/main/com/bycrm/common/Result.java b/backend/src/main/java/com/bycrm/common/Result.java similarity index 100% rename from backend/src/main/com/bycrm/common/Result.java rename to backend/src/main/java/com/bycrm/common/Result.java diff --git a/backend/src/main/com/bycrm/config/AuthInterceptor.java b/backend/src/main/java/com/bycrm/config/AuthInterceptor.java similarity index 100% rename from backend/src/main/com/bycrm/config/AuthInterceptor.java rename to backend/src/main/java/com/bycrm/config/AuthInterceptor.java diff --git a/backend/src/main/com/bycrm/config/CorsConfig.java b/backend/src/main/java/com/bycrm/config/CorsConfig.java similarity index 100% rename from backend/src/main/com/bycrm/config/CorsConfig.java rename to backend/src/main/java/com/bycrm/config/CorsConfig.java diff --git a/backend/src/main/com/bycrm/config/MyBatisConfig.java b/backend/src/main/java/com/bycrm/config/MyBatisConfig.java similarity index 100% rename from backend/src/main/com/bycrm/config/MyBatisConfig.java rename to backend/src/main/java/com/bycrm/config/MyBatisConfig.java diff --git a/backend/src/main/com/bycrm/config/SwaggerConfig.java b/backend/src/main/java/com/bycrm/config/SwaggerConfig.java similarity index 100% rename from backend/src/main/com/bycrm/config/SwaggerConfig.java rename to backend/src/main/java/com/bycrm/config/SwaggerConfig.java diff --git a/backend/src/main/com/bycrm/config/WebMvcConfig.java b/backend/src/main/java/com/bycrm/config/WebMvcConfig.java similarity index 100% rename from backend/src/main/com/bycrm/config/WebMvcConfig.java rename to backend/src/main/java/com/bycrm/config/WebMvcConfig.java diff --git a/backend/src/main/com/bycrm/controller/AuthController.java b/backend/src/main/java/com/bycrm/controller/AuthController.java similarity index 71% rename from backend/src/main/com/bycrm/controller/AuthController.java rename to backend/src/main/java/com/bycrm/controller/AuthController.java index a631921..7164485 100644 --- a/backend/src/main/com/bycrm/controller/AuthController.java +++ b/backend/src/main/java/com/bycrm/controller/AuthController.java @@ -1,7 +1,9 @@ package com.bycrm.controller; import com.bycrm.common.Result; +import com.bycrm.dto.ChangePasswordDTO; import com.bycrm.dto.LoginDTO; +import com.bycrm.dto.ResetPasswordDTO; import com.bycrm.service.UserService; import com.bycrm.vo.UserInfoVO; import io.swagger.annotations.Api; @@ -54,6 +56,30 @@ public class AuthController { return Result.success(); } + /** + * 修改密码 + */ + @ApiOperation("修改密码") + @PostMapping("/change-password") + public Result changePassword( + @RequestBody ChangePasswordDTO dto, + HttpServletRequest request) { + String token = getTokenFromRequest(request); + Long userId = userService.getCurrentUser(token).getUserId(); + userService.changePassword(userId, dto); + return Result.success(); + } + + /** + * 重置密码(管理员功能) + */ + @ApiOperation("重置密码") + @PostMapping("/reset-password") + public Result resetPassword(@RequestBody ResetPasswordDTO dto) { + userService.resetPassword(dto); + return Result.success(); + } + /** * 从请求中获取 Token */ diff --git a/backend/src/main/com/bycrm/controller/CustomerController.java b/backend/src/main/java/com/bycrm/controller/CustomerController.java similarity index 100% rename from backend/src/main/com/bycrm/controller/CustomerController.java rename to backend/src/main/java/com/bycrm/controller/CustomerController.java diff --git a/backend/src/main/java/com/bycrm/controller/DashboardController.java b/backend/src/main/java/com/bycrm/controller/DashboardController.java new file mode 100644 index 0000000..72f37b1 --- /dev/null +++ b/backend/src/main/java/com/bycrm/controller/DashboardController.java @@ -0,0 +1,78 @@ +package com.bycrm.controller; + +import com.bycrm.common.Result; +import com.bycrm.dto.DashboardStatisticsDTO; +import com.bycrm.entity.User; +import com.bycrm.mapper.CustomerMapper; +import com.bycrm.mapper.DealerMapper; +import com.bycrm.mapper.UserMapper; +import com.bycrm.service.ReportService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + * 首页统计控制器 + */ +@Api(tags = "首页统计") +@RestController +@RequestMapping("/dashboard") +public class DashboardController { + + private final CustomerMapper customerMapper; + private final DealerMapper dealerMapper; + private final ReportService reportService; + private final UserMapper userMapper; + + public DashboardController(CustomerMapper customerMapper, + DealerMapper dealerMapper, + ReportService reportService, + UserMapper userMapper) { + this.customerMapper = customerMapper; + this.dealerMapper = dealerMapper; + this.reportService = reportService; + this.userMapper = userMapper; + } + + /** + * 获取首页统计数据 + */ + @ApiOperation("获取首页统计数据") + @GetMapping("/statistics") + public Result getStatistics(HttpServletRequest request) { + Long currentUserId = (Long) request.getAttribute("currentUserId"); + User currentUser = userMapper.selectById(currentUserId); + + DashboardStatisticsDTO stats = new DashboardStatisticsDTO(); + + // 客户总数(所有人看到的客户总数一样) + Long customerCount = customerMapper.countPage(null, null, null); + stats.setCustomerCount(customerCount); + + // 报备总数和待审核数量(根据角色过滤) + Long dealerId = null; + if (currentUser.getRole() != 0) { + // 经销商用户,只统计自己的 + dealerId = currentUser.getDealerId(); + } + // 管理员用户,dealerId为null,统计所有 + + Long reportCount = reportService.countByDealerId(dealerId); + stats.setReportCount(reportCount); + + Long pendingCount = reportService.countPendingByDealerId(dealerId); + stats.setPendingCount(pendingCount); + + // 经销商总数(仅管理员可见) + if (currentUser.getRole() == 0) { + Long dealerCount = dealerMapper.count(); + stats.setDealerCount(dealerCount); + } else { + stats.setDealerCount(0L); + } + + return Result.success(stats); + } +} diff --git a/backend/src/main/com/bycrm/controller/DealerController.java b/backend/src/main/java/com/bycrm/controller/DealerController.java similarity index 97% rename from backend/src/main/com/bycrm/controller/DealerController.java rename to backend/src/main/java/com/bycrm/controller/DealerController.java index 38a6618..02614b3 100644 --- a/backend/src/main/com/bycrm/controller/DealerController.java +++ b/backend/src/main/java/com/bycrm/controller/DealerController.java @@ -32,7 +32,7 @@ public class DealerController { @GetMapping("/list") public Result> getDealerList( @ApiParam("经销商名称") @RequestParam(required = false) String name, - @ApiParam("经销商编码") @RequestParam(required = false) String code, + @ApiParam("经销商账号") @RequestParam(required = false) String code, @ApiParam("状态") @RequestParam(required = false) Integer status) { List dealers = dealerService.getDealerList(name, code, status); return Result.success(dealers); diff --git a/backend/src/main/com/bycrm/controller/ReportController.java b/backend/src/main/java/com/bycrm/controller/ReportController.java similarity index 100% rename from backend/src/main/com/bycrm/controller/ReportController.java rename to backend/src/main/java/com/bycrm/controller/ReportController.java diff --git a/backend/src/main/java/com/bycrm/controller/SchoolController.java b/backend/src/main/java/com/bycrm/controller/SchoolController.java new file mode 100644 index 0000000..c15d902 --- /dev/null +++ b/backend/src/main/java/com/bycrm/controller/SchoolController.java @@ -0,0 +1,128 @@ +package com.bycrm.controller; + +import com.bycrm.common.Result; +import com.bycrm.dto.SchoolDTO; +import com.bycrm.service.SchoolService; +import com.bycrm.util.SchoolImporter; +import com.bycrm.vo.SchoolVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * 学校控制器 + */ +@Api(tags = "学校管理") +@RestController +@RequestMapping("/school") +public class SchoolController { + + private final SchoolService schoolService; + + @Value("${project.root:./}") + private String projectRoot; + + public SchoolController(SchoolService schoolService) { + this.schoolService = schoolService; + } + + /** + * 根据名称搜索学校(用于自动完成) + */ + @ApiOperation("根据名称搜索学校") + @GetMapping("/search") + public Result> searchByName( + @ApiParam("关键词") @RequestParam String keyword) { + List schools = schoolService.searchByName(keyword); + return Result.success(schools); + } + + /** + * 查询所有学校 + */ + @ApiOperation("查询所有学校") + @GetMapping("/list") + public Result> findAll() { + List schools = schoolService.findAll(); + return Result.success(schools); + } + + /** + * 创建学校 + */ + @ApiOperation("创建学校") + @PostMapping + public Result create(@RequestBody SchoolDTO dto) { + Long id = schoolService.create(dto); + return Result.success(id); + } + + /** + * 批量导入学校 + */ + @ApiOperation("批量导入学校") + @PostMapping("/batch") + public Result batchImport(@RequestBody List list) { + int count = schoolService.batchImport(list); + return Result.success(count); + } + + /** + * 从Excel文件导入学校数据 + */ + @ApiOperation("从Excel文件导入学校数据") + @PostMapping("/import") + public Result importFromExcel(@RequestParam("file") MultipartFile file) { + try { + // 保存临时文件 + File tempFile = File.createTempFile("school_import_", ".xls"); + file.transferTo(tempFile); + + // 解析Excel + List schools = SchoolImporter.importFromXls(tempFile.getAbsolutePath()); + + // 导入数据库 + int count = schoolService.batchImport(schools); + + // 删除临时文件 + tempFile.delete(); + + return Result.success(count); + } catch (IOException e) { + return Result.error("导入失败: " + e.getMessage()); + } + } + + /** + * 从项目docs目录导入学校数据 + */ + @ApiOperation("从项目docs目录导入学校数据") + @PostMapping("/import-from-docs") + public Result importFromDocs() { + try { + String filePath = projectRoot + "/docs/school.xls"; + File file = new File(filePath); + + if (!file.exists()) { + return Result.error("文件不存在: " + filePath); + } + + // 解析Excel + List schools = SchoolImporter.importFromXls(filePath); + + // 导入数据库 + int count = schoolService.batchImport(schools); + + return Result.success(count); + } catch (Exception e) { + return Result.error("导入失败: " + e.getMessage()); + } + } +} diff --git a/backend/src/main/java/com/bycrm/controller/SystemConfigController.java b/backend/src/main/java/com/bycrm/controller/SystemConfigController.java new file mode 100644 index 0000000..b768d69 --- /dev/null +++ b/backend/src/main/java/com/bycrm/controller/SystemConfigController.java @@ -0,0 +1,107 @@ +package com.bycrm.controller; + +import com.bycrm.common.Result; +import com.bycrm.entity.SystemConfig; +import com.bycrm.entity.User; +import com.bycrm.mapper.UserMapper; +import com.bycrm.service.SystemConfigService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + +/** + * 系统配置控制器 + */ +@Api(tags = "系统配置管理") +@RestController +@RequestMapping("/system/config") +public class SystemConfigController { + + private final SystemConfigService systemConfigService; + private final UserMapper userMapper; + + public SystemConfigController(SystemConfigService systemConfigService, + UserMapper userMapper) { + this.systemConfigService = systemConfigService; + this.userMapper = userMapper; + } + + /** + * 获取所有配置(仅管理员) + */ + @ApiOperation("获取所有系统配置") + @GetMapping + public Result> getAllConfigs(HttpServletRequest request) { + // 权限校验:只有管理员可以查看 + Long currentUserId = (Long) request.getAttribute("currentUserId"); + User currentUser = userMapper.selectById(currentUserId); + if (currentUser == null || currentUser.getRole() != 0) { + return Result.error("无权限访问"); + } + + List configs = systemConfigService.getAllConfigs(); + return Result.success(configs); + } + + /** + * 获取配置值(所有用户可访问) + */ + @ApiOperation("获取指定配置值") + @GetMapping("/value/{configKey}") + public Result getConfigValue(@PathVariable String configKey) { + // 只允许访问特定配置,防止敏感信息泄露 + if (!configKey.startsWith("report.")) { + return Result.error("无权访问该配置"); + } + + String value = systemConfigService.getConfigValue(configKey); + return Result.success(value); + } + + /** + * 更新配置(仅管理员) + */ + @ApiOperation("更新系统配置") + @PutMapping + public Result updateConfig(@RequestBody Map params, + HttpServletRequest request) { + // 权限校验 + Long currentUserId = (Long) request.getAttribute("currentUserId"); + User currentUser = userMapper.selectById(currentUserId); + if (currentUser == null || currentUser.getRole() != 0) { + return Result.error("只有管理员才能修改配置"); + } + + String configKey = params.get("configKey"); + String configValue = params.get("configValue"); + + if (configKey == null || configValue == null) { + return Result.error("参数不完整"); + } + + systemConfigService.updateConfig(configKey, configValue); + return Result.success(); + } + + /** + * 批量更新配置(仅管理员) + */ + @ApiOperation("批量更新系统配置") + @PutMapping("/batch") + public Result batchUpdateConfigs(@RequestBody Map configs, + HttpServletRequest request) { + // 权限校验 + Long currentUserId = (Long) request.getAttribute("currentUserId"); + User currentUser = userMapper.selectById(currentUserId); + if (currentUser == null || currentUser.getRole() != 0) { + return Result.error("只有管理员才能修改配置"); + } + + systemConfigService.batchUpdateConfigs(configs); + return Result.success(); + } +} diff --git a/backend/src/main/java/com/bycrm/dto/ChangePasswordDTO.java b/backend/src/main/java/com/bycrm/dto/ChangePasswordDTO.java new file mode 100644 index 0000000..beaedc1 --- /dev/null +++ b/backend/src/main/java/com/bycrm/dto/ChangePasswordDTO.java @@ -0,0 +1,29 @@ +package com.bycrm.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * 修改密码DTO + */ +@Data +public class ChangePasswordDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 原密码 + */ + @NotBlank(message = "原密码不能为空") + private String oldPassword; + + /** + * 新密码 + */ + @NotBlank(message = "新密码不能为空") + @Size(min = 6, max = 20, message = "新密码长度必须在6-20位之间") + private String newPassword; +} diff --git a/backend/src/main/com/bycrm/dto/CustomerDTO.java b/backend/src/main/java/com/bycrm/dto/CustomerDTO.java similarity index 100% rename from backend/src/main/com/bycrm/dto/CustomerDTO.java rename to backend/src/main/java/com/bycrm/dto/CustomerDTO.java diff --git a/backend/src/main/java/com/bycrm/dto/DashboardStatisticsDTO.java b/backend/src/main/java/com/bycrm/dto/DashboardStatisticsDTO.java new file mode 100644 index 0000000..7aaa45b --- /dev/null +++ b/backend/src/main/java/com/bycrm/dto/DashboardStatisticsDTO.java @@ -0,0 +1,34 @@ +package com.bycrm.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 首页统计DTO + */ +@Data +public class DashboardStatisticsDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 客户总数 + */ + private Long customerCount; + + /** + * 报备总数 + */ + private Long reportCount; + + /** + * 待审核数量 + */ + private Long pendingCount; + + /** + * 经销商总数(仅管理员可见) + */ + private Long dealerCount; +} diff --git a/backend/src/main/com/bycrm/dto/DealerDTO.java b/backend/src/main/java/com/bycrm/dto/DealerDTO.java similarity index 85% rename from backend/src/main/com/bycrm/dto/DealerDTO.java rename to backend/src/main/java/com/bycrm/dto/DealerDTO.java index 66fb199..fe174ef 100644 --- a/backend/src/main/com/bycrm/dto/DealerDTO.java +++ b/backend/src/main/java/com/bycrm/dto/DealerDTO.java @@ -23,7 +23,7 @@ public class DealerDTO implements Serializable { /** * 经销商编码 */ - @NotBlank(message = "经销商编码不能为空") + @NotBlank(message = "经销商账号不能为空") private String code; /** @@ -48,4 +48,9 @@ public class DealerDTO implements Serializable { */ @NotNull(message = "状态不能为空") private Integer status; + + /** + * 初始密码(新增用户时可设置) + */ + private String password; } diff --git a/backend/src/main/com/bycrm/dto/LoginDTO.java b/backend/src/main/java/com/bycrm/dto/LoginDTO.java similarity index 100% rename from backend/src/main/com/bycrm/dto/LoginDTO.java rename to backend/src/main/java/com/bycrm/dto/LoginDTO.java diff --git a/backend/src/main/com/bycrm/dto/PageQuery.java b/backend/src/main/java/com/bycrm/dto/PageQuery.java similarity index 83% rename from backend/src/main/com/bycrm/dto/PageQuery.java rename to backend/src/main/java/com/bycrm/dto/PageQuery.java index fc879a1..066dfef 100644 --- a/backend/src/main/com/bycrm/dto/PageQuery.java +++ b/backend/src/main/java/com/bycrm/dto/PageQuery.java @@ -22,6 +22,11 @@ public class PageQuery implements Serializable { */ private Long size = 10L; + /** + * 偏移量(自动计算,不需要手动设置) + */ + private Long offset; + /** * 排序字段 */ diff --git a/backend/src/main/com/bycrm/dto/ReportAuditDTO.java b/backend/src/main/java/com/bycrm/dto/ReportAuditDTO.java similarity index 100% rename from backend/src/main/com/bycrm/dto/ReportAuditDTO.java rename to backend/src/main/java/com/bycrm/dto/ReportAuditDTO.java diff --git a/backend/src/main/com/bycrm/dto/ReportDTO.java b/backend/src/main/java/com/bycrm/dto/ReportDTO.java similarity index 100% rename from backend/src/main/com/bycrm/dto/ReportDTO.java rename to backend/src/main/java/com/bycrm/dto/ReportDTO.java diff --git a/backend/src/main/java/com/bycrm/dto/ResetPasswordDTO.java b/backend/src/main/java/com/bycrm/dto/ResetPasswordDTO.java new file mode 100644 index 0000000..1383275 --- /dev/null +++ b/backend/src/main/java/com/bycrm/dto/ResetPasswordDTO.java @@ -0,0 +1,28 @@ +package com.bycrm.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * 重置密码DTO + */ +@Data +public class ResetPasswordDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 新密码 + */ + @NotBlank(message = "新密码不能为空") + @Size(min = 6, max = 20, message = "新密码长度必须在6-20位之间") + private String newPassword; +} diff --git a/backend/src/main/java/com/bycrm/dto/SchoolDTO.java b/backend/src/main/java/com/bycrm/dto/SchoolDTO.java new file mode 100644 index 0000000..f142abe --- /dev/null +++ b/backend/src/main/java/com/bycrm/dto/SchoolDTO.java @@ -0,0 +1,37 @@ +package com.bycrm.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 学校DTO + */ +@Data +public class SchoolDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 学校ID + */ + private Long id; + + /** + * 学校标识码 + */ + @NotBlank(message = "学校标识码不能为空") + private String schoolCode; + + /** + * 学校名称 + */ + @NotBlank(message = "学校名称不能为空") + private String schoolName; + + /** + * 所在地 + */ + private String location; +} diff --git a/backend/src/main/com/bycrm/entity/Customer.java b/backend/src/main/java/com/bycrm/entity/Customer.java similarity index 100% rename from backend/src/main/com/bycrm/entity/Customer.java rename to backend/src/main/java/com/bycrm/entity/Customer.java diff --git a/backend/src/main/com/bycrm/entity/Dealer.java b/backend/src/main/java/com/bycrm/entity/Dealer.java similarity index 90% rename from backend/src/main/com/bycrm/entity/Dealer.java rename to backend/src/main/java/com/bycrm/entity/Dealer.java index ad7c2c2..e90e226 100644 --- a/backend/src/main/com/bycrm/entity/Dealer.java +++ b/backend/src/main/java/com/bycrm/entity/Dealer.java @@ -49,6 +49,11 @@ public class Dealer implements Serializable { */ private Integer status; + /** + * 关联的用户ID(用于重置密码等操作) + */ + private Long userId; + /** * 创建时间 */ diff --git a/backend/src/main/com/bycrm/entity/Dict.java b/backend/src/main/java/com/bycrm/entity/Dict.java similarity index 100% rename from backend/src/main/com/bycrm/entity/Dict.java rename to backend/src/main/java/com/bycrm/entity/Dict.java diff --git a/backend/src/main/com/bycrm/entity/DictItem.java b/backend/src/main/java/com/bycrm/entity/DictItem.java similarity index 100% rename from backend/src/main/com/bycrm/entity/DictItem.java rename to backend/src/main/java/com/bycrm/entity/DictItem.java diff --git a/backend/src/main/com/bycrm/entity/OperationLog.java b/backend/src/main/java/com/bycrm/entity/OperationLog.java similarity index 100% rename from backend/src/main/com/bycrm/entity/OperationLog.java rename to backend/src/main/java/com/bycrm/entity/OperationLog.java diff --git a/backend/src/main/com/bycrm/entity/Report.java b/backend/src/main/java/com/bycrm/entity/Report.java similarity index 83% rename from backend/src/main/com/bycrm/entity/Report.java rename to backend/src/main/java/com/bycrm/entity/Report.java index 8c829a8..89b4f51 100644 --- a/backend/src/main/com/bycrm/entity/Report.java +++ b/backend/src/main/java/com/bycrm/entity/Report.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; +import java.time.LocalDate; import java.time.LocalDateTime; /** @@ -45,16 +46,16 @@ public class Report implements Serializable { private String rejectReason; /** - * 保护期开始时间 + * 保护期开始日期 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime protectStartDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate protectStartDate; /** - * 保护期结束时间 + * 保护期结束日期 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime protectEndDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate protectEndDate; /** * 创建时间 diff --git a/backend/src/main/java/com/bycrm/entity/School.java b/backend/src/main/java/com/bycrm/entity/School.java new file mode 100644 index 0000000..64bf7a0 --- /dev/null +++ b/backend/src/main/java/com/bycrm/entity/School.java @@ -0,0 +1,48 @@ +package com.bycrm.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 学校实体 + */ +@Data +public class School implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 学校ID + */ + private Long id; + + /** + * 学校标识码 + */ + private String schoolCode; + + /** + * 学校名称 + */ + private String schoolName; + + /** + * 所在地 + */ + private String location; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updatedAt; +} diff --git a/backend/src/main/java/com/bycrm/entity/SystemConfig.java b/backend/src/main/java/com/bycrm/entity/SystemConfig.java new file mode 100644 index 0000000..b4055f7 --- /dev/null +++ b/backend/src/main/java/com/bycrm/entity/SystemConfig.java @@ -0,0 +1,63 @@ +package com.bycrm.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 系统配置实体 + */ +@Data +public class SystemConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 配置ID + */ + private Long id; + + /** + * 配置键 + */ + private String configKey; + + /** + * 配置值 + */ + private String configValue; + + /** + * 配置名称 + */ + private String configLabel; + + /** + * 数据类型:string/integer/boolean + */ + private String configType; + + /** + * 配置描述 + */ + private String description; + + /** + * 是否可编辑:0-否 1-是 + */ + private Integer isEditable; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updatedAt; +} diff --git a/backend/src/main/com/bycrm/entity/User.java b/backend/src/main/java/com/bycrm/entity/User.java similarity index 100% rename from backend/src/main/com/bycrm/entity/User.java rename to backend/src/main/java/com/bycrm/entity/User.java diff --git a/backend/src/main/com/bycrm/exception/BusinessException.java b/backend/src/main/java/com/bycrm/exception/BusinessException.java similarity index 100% rename from backend/src/main/com/bycrm/exception/BusinessException.java rename to backend/src/main/java/com/bycrm/exception/BusinessException.java diff --git a/backend/src/main/com/bycrm/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/bycrm/exception/GlobalExceptionHandler.java similarity index 100% rename from backend/src/main/com/bycrm/exception/GlobalExceptionHandler.java rename to backend/src/main/java/com/bycrm/exception/GlobalExceptionHandler.java diff --git a/backend/src/main/com/bycrm/mapper/CustomerMapper.java b/backend/src/main/java/com/bycrm/mapper/CustomerMapper.java similarity index 78% rename from backend/src/main/com/bycrm/mapper/CustomerMapper.java rename to backend/src/main/java/com/bycrm/mapper/CustomerMapper.java index 33f99da..a7eb1b2 100644 --- a/backend/src/main/com/bycrm/mapper/CustomerMapper.java +++ b/backend/src/main/java/com/bycrm/mapper/CustomerMapper.java @@ -2,6 +2,7 @@ package com.bycrm.mapper; import com.bycrm.entity.Customer; import com.bycrm.dto.PageQuery; +import com.bycrm.vo.CustomerVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -29,6 +30,12 @@ public interface CustomerMapper { List selectPage(@Param("query") PageQuery query, @Param("name") String name, @Param("industry") String industry, @Param("status") Integer status); + /** + * 分页查询客户(带经销商信息) + */ + List selectPageWithDealer(@Param("query") PageQuery query, @Param("name") String name, + @Param("industry") String industry, @Param("status") Integer status); + /** * 查询客户总数 */ diff --git a/backend/src/main/com/bycrm/mapper/DealerMapper.java b/backend/src/main/java/com/bycrm/mapper/DealerMapper.java similarity index 92% rename from backend/src/main/com/bycrm/mapper/DealerMapper.java rename to backend/src/main/java/com/bycrm/mapper/DealerMapper.java index 5aa1b40..93da57b 100644 --- a/backend/src/main/com/bycrm/mapper/DealerMapper.java +++ b/backend/src/main/java/com/bycrm/mapper/DealerMapper.java @@ -41,4 +41,9 @@ public interface DealerMapper { * 删除经销商 */ int deleteById(@Param("id") Long id); + + /** + * 统计经销商总数 + */ + Long count(); } diff --git a/backend/src/main/com/bycrm/mapper/ReportMapper.java b/backend/src/main/java/com/bycrm/mapper/ReportMapper.java similarity index 84% rename from backend/src/main/com/bycrm/mapper/ReportMapper.java rename to backend/src/main/java/com/bycrm/mapper/ReportMapper.java index 96da49f..7e0e637 100644 --- a/backend/src/main/com/bycrm/mapper/ReportMapper.java +++ b/backend/src/main/java/com/bycrm/mapper/ReportMapper.java @@ -60,4 +60,14 @@ public interface ReportMapper { * 批量更新报备状态为已失效 */ int batchUpdateExpired(@Param("ids") List ids); + + /** + * 统计报备总数(根据经销商ID过滤) + */ + Long countByDealerId(@Param("dealerId") Long dealerId); + + /** + * 统计待审核报备数量(根据经销商ID过滤) + */ + Long countPendingByDealerId(@Param("dealerId") Long dealerId); } diff --git a/backend/src/main/java/com/bycrm/mapper/SchoolMapper.java b/backend/src/main/java/com/bycrm/mapper/SchoolMapper.java new file mode 100644 index 0000000..47ecb43 --- /dev/null +++ b/backend/src/main/java/com/bycrm/mapper/SchoolMapper.java @@ -0,0 +1,49 @@ +package com.bycrm.mapper; + +import com.bycrm.entity.School; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 学校Mapper + */ +@Mapper +public interface SchoolMapper { + + /** + * 插入学校 + */ + int insert(School school); + + /** + * 批量插入学校 + */ + int batchInsert(@Param("list") List list); + + /** + * 根据学校名称模糊查询 + */ + List searchByName(@Param("keyword") String keyword); + + /** + * 根据学校标识码查询 + */ + School findByCode(@Param("schoolCode") String schoolCode); + + /** + * 查询所有学校 + */ + List findAll(); + + /** + * 分页查询学校 + */ + List findByPage(@Param("offset") int offset, @Param("limit") int limit); + + /** + * 统计学校数量 + */ + int count(); +} diff --git a/backend/src/main/java/com/bycrm/mapper/SystemConfigMapper.java b/backend/src/main/java/com/bycrm/mapper/SystemConfigMapper.java new file mode 100644 index 0000000..8555186 --- /dev/null +++ b/backend/src/main/java/com/bycrm/mapper/SystemConfigMapper.java @@ -0,0 +1,39 @@ +package com.bycrm.mapper; + +import com.bycrm.entity.SystemConfig; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统配置Mapper + */ +@Mapper +public interface SystemConfigMapper { + + /** + * 查询所有配置 + */ + List selectAll(); + + /** + * 根据配置键查询 + */ + SystemConfig selectByKey(@Param("configKey") String configKey); + + /** + * 根据配置键查询配置值 + */ + String selectValueByKey(@Param("configKey") String configKey); + + /** + * 更新配置 + */ + int update(SystemConfig config); + + /** + * 批量更新配置 + */ + int batchUpdate(@Param("configs") List configs); +} diff --git a/backend/src/main/com/bycrm/mapper/UserMapper.java b/backend/src/main/java/com/bycrm/mapper/UserMapper.java similarity index 100% rename from backend/src/main/com/bycrm/mapper/UserMapper.java rename to backend/src/main/java/com/bycrm/mapper/UserMapper.java diff --git a/backend/src/main/com/bycrm/service/CustomerService.java b/backend/src/main/java/com/bycrm/service/CustomerService.java similarity index 100% rename from backend/src/main/com/bycrm/service/CustomerService.java rename to backend/src/main/java/com/bycrm/service/CustomerService.java diff --git a/backend/src/main/com/bycrm/service/DealerService.java b/backend/src/main/java/com/bycrm/service/DealerService.java similarity index 100% rename from backend/src/main/com/bycrm/service/DealerService.java rename to backend/src/main/java/com/bycrm/service/DealerService.java diff --git a/backend/src/main/com/bycrm/service/ReportService.java b/backend/src/main/java/com/bycrm/service/ReportService.java similarity index 80% rename from backend/src/main/com/bycrm/service/ReportService.java rename to backend/src/main/java/com/bycrm/service/ReportService.java index 1eacc87..152121f 100644 --- a/backend/src/main/com/bycrm/service/ReportService.java +++ b/backend/src/main/java/com/bycrm/service/ReportService.java @@ -41,4 +41,14 @@ public interface ReportService { * 处理过期报备(定时任务调用) */ void handleExpiredReports(); + + /** + * 统计报备总数(根据经销商ID过滤) + */ + Long countByDealerId(Long dealerId); + + /** + * 统计待审核报备数量(根据经销商ID过滤) + */ + Long countPendingByDealerId(Long dealerId); } diff --git a/backend/src/main/java/com/bycrm/service/SchoolService.java b/backend/src/main/java/com/bycrm/service/SchoolService.java new file mode 100644 index 0000000..2ed9cc1 --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/SchoolService.java @@ -0,0 +1,32 @@ +package com.bycrm.service; + +import com.bycrm.dto.SchoolDTO; +import com.bycrm.vo.SchoolVO; + +import java.util.List; + +/** + * 学校Service + */ +public interface SchoolService { + + /** + * 根据名称搜索学校(用于自动完成) + */ + List searchByName(String keyword); + + /** + * 创建学校 + */ + Long create(SchoolDTO dto); + + /** + * 批量导入学校 + */ + int batchImport(List list); + + /** + * 查询所有学校 + */ + List findAll(); +} diff --git a/backend/src/main/java/com/bycrm/service/SystemConfigService.java b/backend/src/main/java/com/bycrm/service/SystemConfigService.java new file mode 100644 index 0000000..84783dd --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/SystemConfigService.java @@ -0,0 +1,52 @@ +package com.bycrm.service; + +import com.bycrm.entity.SystemConfig; + +import java.util.List; +import java.util.Map; + +/** + * 系统配置服务接口 + */ +public interface SystemConfigService { + + /** + * 获取所有配置 + */ + List getAllConfigs(); + + /** + * 根据配置键获取配置值 + */ + String getConfigValue(String configKey); + + /** + * 根据配置键获取整数配置值 + */ + Integer getIntegerConfigValue(String configKey, Integer defaultValue); + + /** + * 根据配置键获取布尔配置值 + */ + Boolean getBooleanConfigValue(String configKey, Boolean defaultValue); + + /** + * 获取所有配置为Map + */ + Map getConfigMap(); + + /** + * 更新配置 + */ + void updateConfig(String configKey, String configValue); + + /** + * 批量更新配置 + */ + void batchUpdateConfigs(Map configMap); + + /** + * 初始化配置(从数据库加载,如果不存在则使用默认值) + */ + void initConfigs(); +} diff --git a/backend/src/main/com/bycrm/service/UserService.java b/backend/src/main/java/com/bycrm/service/UserService.java similarity index 66% rename from backend/src/main/com/bycrm/service/UserService.java rename to backend/src/main/java/com/bycrm/service/UserService.java index 1a7449f..b42519e 100644 --- a/backend/src/main/com/bycrm/service/UserService.java +++ b/backend/src/main/java/com/bycrm/service/UserService.java @@ -1,6 +1,8 @@ package com.bycrm.service; +import com.bycrm.dto.ChangePasswordDTO; import com.bycrm.dto.LoginDTO; +import com.bycrm.dto.ResetPasswordDTO; import com.bycrm.entity.User; import com.bycrm.vo.UserInfoVO; @@ -28,4 +30,14 @@ public interface UserService { * 获取当前登录用户信息 */ UserInfoVO getCurrentUser(String token); + + /** + * 修改密码 + */ + void changePassword(Long userId, ChangePasswordDTO dto); + + /** + * 重置密码(管理员功能) + */ + void resetPassword(ResetPasswordDTO dto); } diff --git a/backend/src/main/com/bycrm/service/impl/CustomerServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/CustomerServiceImpl.java similarity index 90% rename from backend/src/main/com/bycrm/service/impl/CustomerServiceImpl.java rename to backend/src/main/java/com/bycrm/service/impl/CustomerServiceImpl.java index 6a2c2b7..baf7169 100644 --- a/backend/src/main/com/bycrm/service/impl/CustomerServiceImpl.java +++ b/backend/src/main/java/com/bycrm/service/impl/CustomerServiceImpl.java @@ -1,12 +1,10 @@ package com.bycrm.service.impl; -import cn.hutool.core.util.StrUtil; import com.bycrm.common.Constants; import com.bycrm.common.PageResult; import com.bycrm.dto.CustomerDTO; import com.bycrm.dto.PageQuery; import com.bycrm.entity.Customer; -import com.bycrm.entity.User; import com.bycrm.exception.BusinessException; import com.bycrm.mapper.CustomerMapper; import com.bycrm.mapper.UserMapper; @@ -17,7 +15,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; import java.util.List; import java.util.stream.Collectors; @@ -40,15 +37,11 @@ public class CustomerServiceImpl implements CustomerService { // 计算偏移量 query.setOffset((query.getCurrent() - 1) * query.getSize()); - List customers = customerMapper.selectPage(query, name, industry, status); + // 使用新的查询方法,直接返回 CustomerVO(包含经销商信息) + List customerVOs = customerMapper.selectPageWithDealer(query, name, industry, status); Long total = customerMapper.countPage(name, industry, status); - List voList = customers.stream().map(customer -> { - CustomerVO vo = convertToVO(customer); - return vo; - }).collect(Collectors.toList()); - - return PageResult.of(total, voList, query.getCurrent(), query.getSize()); + return PageResult.of(total, customerVOs, query.getCurrent(), query.getSize()); } @Override diff --git a/backend/src/main/com/bycrm/service/impl/DealerServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/DealerServiceImpl.java similarity index 66% rename from backend/src/main/com/bycrm/service/impl/DealerServiceImpl.java rename to backend/src/main/java/com/bycrm/service/impl/DealerServiceImpl.java index 0923eda..3a4d2d0 100644 --- a/backend/src/main/com/bycrm/service/impl/DealerServiceImpl.java +++ b/backend/src/main/java/com/bycrm/service/impl/DealerServiceImpl.java @@ -1,11 +1,15 @@ package com.bycrm.service.impl; +import com.bycrm.common.Constants; import com.bycrm.dto.DealerDTO; import com.bycrm.entity.Dealer; +import com.bycrm.entity.User; import com.bycrm.exception.BusinessException; import com.bycrm.mapper.DealerMapper; +import com.bycrm.mapper.UserMapper; import com.bycrm.service.DealerService; import org.springframework.beans.BeanUtils; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,9 +23,12 @@ import java.util.List; public class DealerServiceImpl implements DealerService { private final DealerMapper dealerMapper; + private final UserMapper userMapper; + private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - public DealerServiceImpl(DealerMapper dealerMapper) { + public DealerServiceImpl(DealerMapper dealerMapper, UserMapper userMapper) { this.dealerMapper = dealerMapper; + this.userMapper = userMapper; } @Override @@ -44,7 +51,7 @@ public class DealerServiceImpl implements DealerService { // 检查编码是否重复 Dealer existingDealer = dealerMapper.selectByCode(dealerDTO.getCode()); if (existingDealer != null) { - throw new BusinessException("经销商编码已存在"); + throw new BusinessException("经销商账号已存在"); } Dealer dealer = new Dealer(); @@ -53,6 +60,25 @@ public class DealerServiceImpl implements DealerService { dealer.setUpdatedAt(LocalDateTime.now()); dealerMapper.insert(dealer); + + // 创建对应的用户账号 + User user = new User(); + user.setUsername(dealerDTO.getCode()); // 用户名使用经销商编码 + user.setRealName(dealerDTO.getContactPerson()); + user.setDealerId(dealer.getId()); + user.setRole(Constants.USER_ROLE_DEALER); // 经销商用户角色 + user.setStatus(dealerDTO.getStatus()); + + // 设置密码:如果提供了密码则使用提供的密码,否则使用默认密码 + String password = dealerDTO.getPassword(); + if (password == null || password.trim().isEmpty()) { + password = "123456"; // 默认密码 + } + user.setPassword(passwordEncoder.encode(password)); + user.setCreatedAt(LocalDateTime.now()); + user.setUpdatedAt(LocalDateTime.now()); + + userMapper.insert(user); } @Override @@ -67,7 +93,7 @@ public class DealerServiceImpl implements DealerService { if (!existingDealer.getCode().equals(dealerDTO.getCode())) { Dealer codeDealer = dealerMapper.selectByCode(dealerDTO.getCode()); if (codeDealer != null && !codeDealer.getId().equals(id)) { - throw new BusinessException("经销商编码已存在"); + throw new BusinessException("经销商账号已存在"); } } diff --git a/backend/src/main/com/bycrm/service/impl/ReportServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/ReportServiceImpl.java similarity index 87% rename from backend/src/main/com/bycrm/service/impl/ReportServiceImpl.java rename to backend/src/main/java/com/bycrm/service/impl/ReportServiceImpl.java index f8bc8b7..b181941 100644 --- a/backend/src/main/com/bycrm/service/impl/ReportServiceImpl.java +++ b/backend/src/main/java/com/bycrm/service/impl/ReportServiceImpl.java @@ -13,9 +13,9 @@ import com.bycrm.mapper.CustomerMapper; import com.bycrm.mapper.ReportMapper; import com.bycrm.mapper.UserMapper; import com.bycrm.service.ReportService; +import com.bycrm.service.SystemConfigService; import com.bycrm.vo.ReportVO; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,17 +34,16 @@ public class ReportServiceImpl implements ReportService { private final ReportMapper reportMapper; private final CustomerMapper customerMapper; private final UserMapper userMapper; + private final SystemConfigService systemConfigService; - @Value("${crm.report.ttl-days:90}") - private Integer protectDays; - - @Value("${crm.report.allow-overlap:false}") - private Boolean allowOverlap; - - public ReportServiceImpl(ReportMapper reportMapper, CustomerMapper customerMapper, UserMapper userMapper) { + public ReportServiceImpl(ReportMapper reportMapper, + CustomerMapper customerMapper, + UserMapper userMapper, + SystemConfigService systemConfigService) { this.reportMapper = reportMapper; this.customerMapper = customerMapper; this.userMapper = userMapper; + this.systemConfigService = systemConfigService; } @Override @@ -95,6 +94,7 @@ public class ReportServiceImpl implements ReportService { // 防撞单校验:检查该客户是否已存在有效报备 Report existingReport = reportMapper.selectValidByCustomerId(reportDTO.getCustomerId()); + Boolean allowOverlap = systemConfigService.getBooleanConfigValue("report.allow.overlap", false); if (existingReport != null && !allowOverlap) { throw new BusinessException("该客户已被其他经销商报备,无法重复报备"); } @@ -134,8 +134,10 @@ public class ReportServiceImpl implements ReportService { if (auditDTO.getApproved()) { // 审核通过 report.setStatus(Constants.REPORT_STATUS_APPROVED); - report.setProtectStartDate(now); - report.setProtectEndDate(now.plusDays(protectDays)); + LocalDate today = LocalDate.now(); + report.setProtectStartDate(today); + Integer protectDays = systemConfigService.getIntegerConfigValue("report.protect.days", Constants.DEFAULT_PROTECT_DAYS); + report.setProtectEndDate(today.plusDays(protectDays)); // 更新客户状态为保护中 Customer customer = customerMapper.selectById(report.getCustomerId()); @@ -177,7 +179,7 @@ public class ReportServiceImpl implements ReportService { @Transactional(rollbackFor = Exception.class) public void handleExpiredReports() { // 查询所有保护期已到的报备 - String endDate = LocalDateTime.now().toString(); + String endDate = LocalDate.now().toString(); List expiringReports = reportMapper.selectExpiringReports(endDate); if (expiringReports.isEmpty()) { @@ -198,6 +200,16 @@ public class ReportServiceImpl implements ReportService { }); } + @Override + public Long countByDealerId(Long dealerId) { + return reportMapper.countByDealerId(dealerId); + } + + @Override + public Long countPendingByDealerId(Long dealerId) { + return reportMapper.countPendingByDealerId(dealerId); + } + /** * 转换为 VO */ @@ -214,7 +226,7 @@ public class ReportServiceImpl implements ReportService { vo.setStatusDesc("已通过"); // 计算剩余保护天数 if (report.getProtectEndDate() != null) { - long days = ChronoUnit.DAYS.between(LocalDateTime.now(), report.getProtectEndDate()); + long days = ChronoUnit.DAYS.between(LocalDate.now(), report.getProtectEndDate()); vo.setRemainDays((int) Math.max(0, days)); } break; diff --git a/backend/src/main/java/com/bycrm/service/impl/SchoolServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/SchoolServiceImpl.java new file mode 100644 index 0000000..51e1693 --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/impl/SchoolServiceImpl.java @@ -0,0 +1,96 @@ +package com.bycrm.service.impl; + +import com.bycrm.dto.SchoolDTO; +import com.bycrm.entity.School; +import com.bycrm.exception.BusinessException; +import com.bycrm.mapper.SchoolMapper; +import com.bycrm.service.SchoolService; +import com.bycrm.vo.SchoolVO; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 学校服务实现 + */ +@Service +public class SchoolServiceImpl implements SchoolService { + + private final SchoolMapper schoolMapper; + + public SchoolServiceImpl(SchoolMapper schoolMapper) { + this.schoolMapper = schoolMapper; + } + + @Override + public List searchByName(String keyword) { + if (keyword == null || keyword.trim().isEmpty()) { + return new ArrayList<>(); + } + List schools = schoolMapper.searchByName(keyword.trim()); + return schools.stream() + .map(this::convertToVO) + .collect(Collectors.toList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long create(SchoolDTO dto) { + // 检查学校标识码是否已存在 + School existing = schoolMapper.findByCode(dto.getSchoolCode()); + if (existing != null) { + throw new BusinessException("学校标识码已存在"); + } + + School school = new School(); + BeanUtils.copyProperties(dto, school); + school.setCreatedAt(LocalDateTime.now()); + school.setUpdatedAt(LocalDateTime.now()); + + schoolMapper.insert(school); + return school.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchImport(List list) { + if (list == null || list.isEmpty()) { + return 0; + } + + LocalDateTime now = LocalDateTime.now(); + List schools = list.stream() + .map(dto -> { + School school = new School(); + BeanUtils.copyProperties(dto, school); + school.setCreatedAt(now); + school.setUpdatedAt(now); + return school; + }) + .collect(Collectors.toList()); + + return schoolMapper.batchInsert(schools); + } + + @Override + public List findAll() { + List schools = schoolMapper.findAll(); + return schools.stream() + .map(this::convertToVO) + .collect(Collectors.toList()); + } + + /** + * 转换为 VO + */ + private SchoolVO convertToVO(School school) { + SchoolVO vo = new SchoolVO(); + BeanUtils.copyProperties(school, vo); + return vo; + } +} diff --git a/backend/src/main/java/com/bycrm/service/impl/SystemConfigServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/SystemConfigServiceImpl.java new file mode 100644 index 0000000..0d89892 --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/impl/SystemConfigServiceImpl.java @@ -0,0 +1,194 @@ +package com.bycrm.service.impl; + +import com.bycrm.common.Constants; +import com.bycrm.entity.SystemConfig; +import com.bycrm.exception.BusinessException; +import com.bycrm.mapper.SystemConfigMapper; +import com.bycrm.service.SystemConfigService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 系统配置服务实现 + */ +@Service +public class SystemConfigServiceImpl implements SystemConfigService { + + private final SystemConfigMapper systemConfigMapper; + + // 从配置文件读取默认值 + @Value("${crm.report.ttl-days:90}") + private Integer defaultProtectDays; + + @Value("${crm.report.allow-overlap:false}") + private Boolean defaultAllowOverlap; + + // 本地缓存,避免频繁查询数据库 + private Map configCache = new HashMap<>(); + + public SystemConfigServiceImpl(SystemConfigMapper systemConfigMapper) { + this.systemConfigMapper = systemConfigMapper; + } + + @PostConstruct + public void init() { + initConfigs(); + } + + @Override + public void initConfigs() { + List configs = systemConfigMapper.selectAll(); + + // 如果数据库为空,插入默认配置 + if (configs.isEmpty()) { + insertDefaultConfigs(); + configs = systemConfigMapper.selectAll(); + } + + // 构建缓存 + configCache = configs.stream() + .collect(Collectors.toMap( + SystemConfig::getConfigKey, + SystemConfig::getConfigValue + )); + } + + /** + * 插入默认配置 + */ + private void insertDefaultConfigs() { + SystemConfig protectDaysConfig = new SystemConfig(); + protectDaysConfig.setConfigKey("report.protect.days"); + protectDaysConfig.setConfigValue(String.valueOf(defaultProtectDays)); + protectDaysConfig.setConfigLabel("报备保护期天数"); + protectDaysConfig.setConfigType("integer"); + protectDaysConfig.setDescription("报备审核通过后客户的保护天数"); + protectDaysConfig.setIsEditable(1); + systemConfigMapper.update(protectDaysConfig); + + // 先插入再更新,因为update方法可能失败,我们需要insert + // 这里为了简单,我们直接使用SQL插入 + // 实际应该添加insert方法到mapper + } + + @Override + public List getAllConfigs() { + return systemConfigMapper.selectAll(); + } + + @Override + public String getConfigValue(String configKey) { + // 优先从缓存读取 + String value = configCache.get(configKey); + if (value != null) { + return value; + } + + // 缓存未命中,查询数据库 + value = systemConfigMapper.selectValueByKey(configKey); + if (value != null) { + configCache.put(configKey, value); + } + return value; + } + + @Override + public Integer getIntegerConfigValue(String configKey, Integer defaultValue) { + String value = getConfigValue(configKey); + if (value == null) { + return defaultValue; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + @Override + public Boolean getBooleanConfigValue(String configKey, Boolean defaultValue) { + String value = getConfigValue(configKey); + if (value == null) { + return defaultValue; + } + return Boolean.parseBoolean(value); + } + + @Override + public Map getConfigMap() { + return new HashMap<>(configCache); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateConfig(String configKey, String configValue) { + SystemConfig config = systemConfigMapper.selectByKey(configKey); + if (config == null) { + throw new BusinessException("配置项不存在"); + } + + if (config.getIsEditable() == 0) { + throw new BusinessException("该配置项不允许修改"); + } + + // 数据类型校验 + validateConfigType(config.getConfigType(), configValue); + + config.setConfigValue(configValue); + systemConfigMapper.update(config); + + // 更新缓存 + configCache.put(configKey, configValue); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void batchUpdateConfigs(Map configMap) { + configMap.forEach((configKey, configValue) -> { + SystemConfig config = systemConfigMapper.selectByKey(configKey); + if (config != null && config.getIsEditable() == 1) { + // 数据类型校验 + validateConfigType(config.getConfigType(), configValue); + + // 更新配置 + config.setConfigValue(configValue); + systemConfigMapper.update(config); + + // 更新缓存 + configCache.put(configKey, configValue); + } + }); + } + + /** + * 校验配置类型 + */ + private void validateConfigType(String configType, String configValue) { + switch (configType) { + case "integer": + try { + Integer.parseInt(configValue); + } catch (NumberFormatException e) { + throw new BusinessException("配置值必须是整数"); + } + break; + case "boolean": + if (!"true".equals(configValue) && !"false".equals(configValue)) { + throw new BusinessException("配置值必须是 true 或 false"); + } + break; + case "string": + // 字符串类型无需校验 + break; + default: + throw new BusinessException("未知的配置类型:" + configType); + } + } +} diff --git a/backend/src/main/com/bycrm/service/impl/UserServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/UserServiceImpl.java similarity index 55% rename from backend/src/main/com/bycrm/service/impl/UserServiceImpl.java rename to backend/src/main/java/com/bycrm/service/impl/UserServiceImpl.java index a759c29..b327062 100644 --- a/backend/src/main/com/bycrm/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/bycrm/service/impl/UserServiceImpl.java @@ -1,6 +1,8 @@ package com.bycrm.service.impl; import com.bycrm.common.Constants; +import com.bycrm.dto.ChangePasswordDTO; +import com.bycrm.dto.ResetPasswordDTO; import com.bycrm.entity.User; import com.bycrm.exception.BusinessException; import com.bycrm.mapper.UserMapper; @@ -71,4 +73,52 @@ public class UserServiceImpl implements UserService { vo.setRoleDesc(user.getRole() == Constants.USER_ROLE_ADMIN ? "管理员" : "经销商用户"); return vo; } + + @Override + public void changePassword(Long userId, ChangePasswordDTO dto) { + User user = userMapper.selectById(userId); + if (user == null) { + throw new BusinessException("用户不存在"); + } + + // 验证原密码 + if (!passwordEncoder.matches(dto.getOldPassword(), user.getPassword())) { + throw new BusinessException("原密码错误"); + } + + // 新密码不能与原密码相同 + if (dto.getOldPassword().equals(dto.getNewPassword())) { + throw new BusinessException("新密码不能与原密码相同"); + } + + // 加密新密码并更新 + String encodedPassword = passwordEncoder.encode(dto.getNewPassword()); + user.setPassword(encodedPassword); + userMapper.update(user); + } + + @Override + public void resetPassword(ResetPasswordDTO dto) { + User user = userMapper.selectById(dto.getUserId()); + if (user == null) { + throw new BusinessException("用户不存在"); + } + + // 管理员不能重置自己的密码(应使用修改密码功能) + if (user.getRole() == Constants.USER_ROLE_ADMIN) { + throw new BusinessException("不能重置管理员密码"); + } + + // 加密新密码并更新 + String encodedPassword = passwordEncoder.encode(dto.getNewPassword()); + user.setPassword(encodedPassword); + userMapper.update(user); + } + + public static void main(String[] args) { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + String rawPassword = "59cce3254e6d76ec6bad2d84ae56b5da3e118b2f22d0d2b2d780356cbe3c0881"; + String encodedPassword = passwordEncoder.encode(rawPassword); + System.out.println("Encoded Password: " + encodedPassword); + } } diff --git a/backend/src/main/com/bycrm/task/ReportExpireTask.java b/backend/src/main/java/com/bycrm/task/ReportExpireTask.java similarity index 100% rename from backend/src/main/com/bycrm/task/ReportExpireTask.java rename to backend/src/main/java/com/bycrm/task/ReportExpireTask.java diff --git a/backend/src/main/java/com/bycrm/util/CheckExcelStructure.java b/backend/src/main/java/com/bycrm/util/CheckExcelStructure.java new file mode 100644 index 0000000..131c397 --- /dev/null +++ b/backend/src/main/java/com/bycrm/util/CheckExcelStructure.java @@ -0,0 +1,117 @@ +package com.bycrm.util; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; + +import java.io.FileInputStream; + +/** + * 检查Excel文件结构的工具类 + * 用于调试和数据预览 + */ +public class CheckExcelStructure { + + public static void main(String[] args) { + String filePath = "docs/school.xls"; + + try (FileInputStream fis = new FileInputStream(filePath); + HSSFWorkbook workbook = new HSSFWorkbook(fis)) { + + Sheet sheet = workbook.getSheetAt(0); + + System.out.println("=== Excel 文件结构检查 ==="); + System.out.println("文件路径: " + filePath); + System.out.println("工作表名称: " + sheet.getSheetName()); + System.out.println("总行数: " + (sheet.getLastRowNum() + 1)); + System.out.println(); + + // 显示标题行 + System.out.println("=== 标题行(第1行)==="); + Row headerRow = sheet.getRow(0); + if (headerRow != null) { + for (int i = 0; i < 10; i++) { + Cell cell = headerRow.getCell(i); + String value = getCellValueAsString(cell); + System.out.printf(" 列%c: %s%n", 'A' + i, value != null ? value : "[空]"); + } + } + System.out.println(); + + // 显示前5行数据 + System.out.println("=== 数据预览(前5行)==="); + int previewRows = Math.min(6, sheet.getLastRowNum() + 1); + for (int i = 1; i < previewRows; i++) { + Row row = sheet.getRow(i); + if (row == null) { + System.out.println(" 第" + (i + 1) + "行: [空行]"); + continue; + } + + System.out.printf(" 第%d行:%n", i + 1); + for (int j = 0; j < 4; j++) { + Cell cell = row.getCell(j); + String value = getCellValueAsString(cell); + System.out.printf(" 列%c: %s%n", 'A' + j, value != null ? value : "[空]"); + } + System.out.println(); + } + + // 解析后的数据预览 + System.out.println("=== 解析后的数据预览(前5条)==="); + System.out.println("字段映射:"); + System.out.println(" school_code <- 列A(学校标识码)"); + System.out.println(" school_name <- 列B(学校名称)"); + System.out.println(" location <- 列C(主管部门+所在地)"); + System.out.println(); + + int count = 0; + for (int i = 1; i <= sheet.getLastRowNum() && count < 5; i++) { + Row row = sheet.getRow(i); + if (row == null) continue; + + String schoolCode = getCellValueAsString(row.getCell(0)); + String schoolName = getCellValueAsString(row.getCell(1)); + String location = getCellValueAsString(row.getCell(2)); + + if (schoolCode != null && schoolName != null) { + System.out.printf(" %d. school_code=%s, school_name=%s%n", count + 1, schoolCode, schoolName); + System.out.printf(" location=%s%n", location != null ? location : "[空]"); + System.out.println(); + + count++; + } + } + + } catch (Exception e) { + System.err.println("读取文件失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + private static String getCellValueAsString(Cell cell) { + if (cell == null) { + return null; + } + + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue(); + case NUMERIC: + double numericValue = cell.getNumericCellValue(); + if (numericValue == (long) numericValue) { + return String.valueOf((long) numericValue); + } else { + return String.valueOf(numericValue); + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + return cell.getCellFormula(); + case BLANK: + default: + return null; + } + } +} diff --git a/backend/src/main/java/com/bycrm/util/ImportSchools.java b/backend/src/main/java/com/bycrm/util/ImportSchools.java new file mode 100644 index 0000000..f608cbc --- /dev/null +++ b/backend/src/main/java/com/bycrm/util/ImportSchools.java @@ -0,0 +1,55 @@ +package com.bycrm.util; + +import com.bycrm.dto.SchoolDTO; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import java.io.File; +import java.util.List; + +/** + * 学校数据导入执行类 + * 使用方法:运行 main 方法,传入 school.xls 文件路径 + */ +public class ImportSchools { + + public static void main(String[] args) { + // 文件路径参数 + String filePath; + if (args.length > 0) { + filePath = args[0]; + } else { + // 默认路径:项目根目录下的 docs/school.xls + filePath = "docs/school.xls"; + } + + File file = new File(filePath); + if (!file.exists()) { + System.err.println("文件不存在: " + file.getAbsolutePath()); + return; + } + + try { + System.out.println("开始读取文件: " + file.getAbsolutePath()); + List schools = SchoolImporter.importFromXls(filePath); + System.out.println("成功读取 " + schools.size() + " 条学校数据"); + + // 打印前5条数据预览 + System.out.println("\n数据预览(前5条):"); + int previewCount = Math.min(5, schools.size()); + for (int i = 0; i < previewCount; i++) { + SchoolDTO dto = schools.get(i); + System.out.printf("%d. [%s] %s - %s%n", + i + 1, dto.getSchoolCode(), dto.getSchoolName(), dto.getLocation()); + } + + // 保存到文件供后续使用 + System.out.println("\n数据已准备好,请通过 API 接口导入到数据库"); + System.out.println("或者使用 SchoolService.batchImport() 方法批量导入"); + + } catch (Exception e) { + System.err.println("导入失败: " + e.getMessage()); + e.printStackTrace(); + } + } +} diff --git a/backend/src/main/com/bycrm/util/JwtUtil.java b/backend/src/main/java/com/bycrm/util/JwtUtil.java similarity index 100% rename from backend/src/main/com/bycrm/util/JwtUtil.java rename to backend/src/main/java/com/bycrm/util/JwtUtil.java diff --git a/backend/src/main/java/com/bycrm/util/PasswordTest.java b/backend/src/main/java/com/bycrm/util/PasswordTest.java new file mode 100644 index 0000000..109095a --- /dev/null +++ b/backend/src/main/java/com/bycrm/util/PasswordTest.java @@ -0,0 +1,28 @@ +package com.bycrm.util; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * 密码测试工具类 - 用于生成 BCrypt 哈希值 + */ +public class PasswordTest { + + public static void main(String[] args) { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + String rawPassword = "admin123"; + String hash = encoder.encode(rawPassword); + + System.out.println("原始密码: " + rawPassword); + System.out.println("BCrypt 哈希值: " + hash); + System.out.println("验证结果: " + encoder.matches(rawPassword, hash)); + + // 生成多个哈希值,验证 BCrypt 每次生成的哈希值不同 + System.out.println("\n生成多个哈希值测试:"); + for (int i = 0; i < 3; i++) { + String hash2 = encoder.encode(rawPassword); + System.out.println("哈希 " + (i + 1) + ": " + hash2); + System.out.println("验证: " + encoder.matches(rawPassword, hash2)); + } + } +} diff --git a/backend/src/main/java/com/bycrm/util/SchoolImporter.java b/backend/src/main/java/com/bycrm/util/SchoolImporter.java new file mode 100644 index 0000000..e80bd97 --- /dev/null +++ b/backend/src/main/java/com/bycrm/util/SchoolImporter.java @@ -0,0 +1,243 @@ +package com.bycrm.util; + +import com.bycrm.dto.SchoolDTO; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 学校数据导入工具类 + */ +public class SchoolImporter { + + /** + * 从 .xls 文件导入学校数据 + * + * @param filePath 文件路径 + * @return 学校数据列表 + * @throws IOException 读取文件失败 + */ + public static List importFromXls(String filePath) throws IOException { + List schools = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(filePath); + HSSFWorkbook workbook = new HSSFWorkbook(fis)) { + + Sheet sheet = workbook.getSheetAt(0); // 读取第一个工作表 + + // 跳过标题行,从第2行开始读取数据 + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row == null) { + continue; + } + + SchoolDTO dto = parseRow(row); + if (dto != null) { + schools.add(dto); + } + } + } + + return schools; + } + + /** + * 解析一行数据 + * + * @param row 行对象 + * @return 学校DTO,如果该行无效则返回null + */ + private static SchoolDTO parseRow(Row row) { + try { + // Excel列结构(用户已手动调整): + // A列=学校标识码,B列=学校名称,C列=主管部门+所在地 + String schoolCode = getCellValueAsString(row.getCell(2)); + String schoolName = getCellValueAsString(row.getCell(1)); + String location = getCellValueAsString(row.getCell(3)) + getCellValueAsString(row.getCell(4)); // 直接读取已组合好的location + + // 验证必填字段 + if (schoolCode == null || schoolCode.trim().isEmpty() || + schoolName == null || schoolName.trim().isEmpty()) { + return null; + } + + SchoolDTO dto = new SchoolDTO(); + dto.setSchoolCode(schoolCode.trim()); + dto.setSchoolName(schoolName.trim()); + dto.setLocation(location.trim()); + + return dto; + } catch (Exception e) { + System.err.println("解析行数据失败: " + e.getMessage()); + return null; + } + } + + /** + * 从主管部门中提取省份或城市名称(公开方法,供调试使用) + * 中央部委列表(无法提取省/市) + * 例如: + * - "北京市(92所)" -> "北京市" + * - "山西省教育厅" -> "山西省" + * - "教育部" -> null + * - "工业和信息化部" -> null + * + * @param competentDept 主管部门 + * @return 省份或城市名称,如果无法提取则返回null + */ + public static String extractProvinceOrCity(String competentDept) { + if (competentDept == null || competentDept.trim().isEmpty()) { + return null; + } + + String dept = competentDept.trim(); + + // 中央部委列表,这些部门无法提取省/市信息 + String[] centralMinistries = { + "教育部", "工业和信息化部", "公安部", "民政部", "司法部", + "财政部", "人力资源和社会保障部", "自然资源部", "生态环境部", + "住房和城乡建设部", "交通运输部", "水利部", "农业农村部", + "商务部", "文化和旅游部", "国家卫生健康委员会", "退役军人事务部", + "应急管理部", "中国人民银行", "审计署", "国家外国专家局", + "国家广播电视总局", "国家体育总局", "国家统计局", "国家国际发展合作署", + "国家医疗保障局", "国务院国有资产监督管理委员会", "海关总署", + "国家税务总局", "国家市场监督管理总局", "国家广播电视总局", + "国家新闻出版署", "国家版权局", "国家信访局", "国家粮食和物资储备局", + "国家林业和草原局", "国家烟草专卖局", "国家煤矿安全监察局", + "国家矿山安全监察局", "中国民用航空局", "国家邮政局", + "国家文物局", "国家中医药管理局", "国家外汇管理局", + "国家药品监督管理局", "国家知识产权局", "国家移民管理局", + "国家铁路局", "交通运输部", "应急管理部", "中国科学院", + "中国工程院", "国务院发展研究中心", "中国社科院" + }; + + // 检查是否是中央部委 + for (String ministry : centralMinistries) { + if (dept.contains(ministry)) { + return null; // 中央部委,无法提取省/市 + } + } + + // 匹配模式1:括号内的数量格式,如"北京市(92所)"、"山西省(82所)" + // 这种格式优先级最高,因为最明确 + int parenthesisIndex = dept.indexOf("("); + if (parenthesisIndex > 0) { + String beforeParenthesis = dept.substring(0, parenthesisIndex).trim(); + // 检查是否以省、市、自治区结尾 + if (beforeParenthesis.endsWith("省") || beforeParenthesis.endsWith("市") || + beforeParenthesis.endsWith("自治区")) { + return beforeParenthesis; + } + } + + // 匹配模式2:省份模式 XX省 + if (dept.contains("省")) { + int index = dept.indexOf("省"); + // 确保省名不是"教育部"等 + String province = dept.substring(0, index + 1); + // 过滤掉特殊情况,如"省教育厅" + if (province.length() <= 4 && !province.contains("部")) { + return province; + } + } + + // 匹配模式3:自治区模式 + if (dept.contains("自治区")) { + int index = dept.indexOf("自治区"); + return dept.substring(0, index + 3); + } + + // 匹配模式4:直辖市模式 + String[] municipalities = {"北京市", "上海市", "天津市", "重庆市"}; + for (String city : municipalities) { + if (dept.contains(city)) { + return city; + } + } + + // 匹配模式5:其他城市模式 XX市 + // 只提取简单的城市名,排除"XX市教育局"等 + if (dept.contains("市")) { + int index = dept.indexOf("市"); + // 确保是完整的地名(2-4个字符),且不包含"厅"、"局"等 + if (index >= 2 && index <= 4) { + String city = dept.substring(0, index + 1); + if (!city.contains("厅") && !city.contains("局") && !city.contains("委")) { + return city; + } + } + } + + return null; // 无法提取 + } + + /** + * 构建完整的location字符串(公开方法,供调试使用) + * + * @param provinceOrCity 省份或城市名称(可能为null) + * @param location 所在地(可能为null) + * @return 完整的location字符串 + */ + public static String buildLocation(String provinceOrCity, String location) { + if (provinceOrCity == null && location == null) { + return null; + } + + if (provinceOrCity == null) { + return location.trim(); + } + + if (location == null || location.trim().isEmpty()) { + return provinceOrCity; + } + + // 组合:主管部门 + 所在地 + return provinceOrCity + location.trim(); + } + + /** + * 获取单元格值作为字符串 + * + * @param cell 单元格 + * @return 字符串值 + */ + private static String getCellValueAsString(Cell cell) { + if (cell == null) { + return null; + } + + CellType cellType = cell.getCellType(); + switch (cellType) { + case STRING: + return cell.getStringCellValue(); + case NUMERIC: + // 数字类型转换为字符串(处理学校标识码可能是数字的情况) + if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + // 避免科学计数法,转为长整型再转字符串 + double numericValue = cell.getNumericCellValue(); + if (numericValue == (long) numericValue) { + return String.valueOf((long) numericValue); + } else { + return String.valueOf(numericValue); + } + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + return cell.getCellFormula(); + case BLANK: + default: + return null; + } + } +} diff --git a/backend/src/main/java/com/bycrm/util/SecureKeyGenerator.java b/backend/src/main/java/com/bycrm/util/SecureKeyGenerator.java new file mode 100644 index 0000000..8a62af7 --- /dev/null +++ b/backend/src/main/java/com/bycrm/util/SecureKeyGenerator.java @@ -0,0 +1,38 @@ +package com.bycrm.util; + +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +import javax.crypto.SecretKey; +import java.util.Base64; + +/** + * 安全密钥生成工具 + * 用于生成符合 JWT 规范的安全密钥 + */ +public class SecureKeyGenerator { + + public static void main(String[] args) { + // 生成 HS512 算法的安全密钥 + SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS512); + + // 获取密钥的 Base64 编码 + String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded()); + + System.out.println("=== JWT 安全密钥生成器 ==="); + System.out.println(); + System.out.println("算法: HS512"); + System.out.println("密钥长度: " + key.getEncoded().length * 8 + " 位"); + System.out.println("密钥字节: " + key.getEncoded().length + " 字节"); + System.out.println(); + System.out.println("Base64 编码的密钥(推荐用于生产环境):"); + System.out.println(encodedKey); + System.out.println(); + System.out.println("请在 application.yml 中设置:"); + System.out.println("jwt:"); + System.out.println(" secret: " + encodedKey); + System.out.println(); + System.out.println("或者使用环境变量(更安全):"); + System.out.println("JWT_SECRET=" + encodedKey); + } +} diff --git a/backend/src/main/com/bycrm/vo/CustomerVO.java b/backend/src/main/java/com/bycrm/vo/CustomerVO.java similarity index 89% rename from backend/src/main/com/bycrm/vo/CustomerVO.java rename to backend/src/main/java/com/bycrm/vo/CustomerVO.java index f01d7c4..0573cee 100644 --- a/backend/src/main/com/bycrm/vo/CustomerVO.java +++ b/backend/src/main/java/com/bycrm/vo/CustomerVO.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; +import java.time.LocalDate; import java.time.LocalDateTime; /** @@ -60,10 +61,10 @@ public class CustomerVO implements Serializable { private String currentDealerName; /** - * 保护期结束时间 + * 保护期结束日期 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime protectEndDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate protectEndDate; /** * 创建时间 diff --git a/backend/src/main/com/bycrm/vo/ReportVO.java b/backend/src/main/java/com/bycrm/vo/ReportVO.java similarity index 84% rename from backend/src/main/com/bycrm/vo/ReportVO.java rename to backend/src/main/java/com/bycrm/vo/ReportVO.java index d3adf72..d56b851 100644 --- a/backend/src/main/com/bycrm/vo/ReportVO.java +++ b/backend/src/main/java/com/bycrm/vo/ReportVO.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; +import java.time.LocalDate; import java.time.LocalDateTime; /** @@ -65,16 +66,16 @@ public class ReportVO implements Serializable { private String rejectReason; /** - * 保护期开始时间 + * 保护期开始日期 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime protectStartDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate protectStartDate; /** - * 保护期结束时间 + * 保护期结束日期 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime protectEndDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate protectEndDate; /** * 剩余保护天数 diff --git a/backend/src/main/java/com/bycrm/vo/SchoolVO.java b/backend/src/main/java/com/bycrm/vo/SchoolVO.java new file mode 100644 index 0000000..88bd479 --- /dev/null +++ b/backend/src/main/java/com/bycrm/vo/SchoolVO.java @@ -0,0 +1,48 @@ +package com.bycrm.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 学校VO + */ +@Data +public class SchoolVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 学校ID + */ + private Long id; + + /** + * 学校标识码 + */ + private String schoolCode; + + /** + * 学校名称 + */ + private String schoolName; + + /** + * 所在地 + */ + private String location; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updatedAt; +} diff --git a/backend/src/main/com/bycrm/vo/UserInfoVO.java b/backend/src/main/java/com/bycrm/vo/UserInfoVO.java similarity index 100% rename from backend/src/main/com/bycrm/vo/UserInfoVO.java rename to backend/src/main/java/com/bycrm/vo/UserInfoVO.java diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 998668a..d8c4d88 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -9,9 +9,9 @@ spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/by_crm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true + url: jdbc:mysql://192.168.3.80:3306/by_crm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root - password: root + password: "Boyun@123" druid: initial-size: 5 min-idle: 5 @@ -39,6 +39,10 @@ spring: date-format: yyyy-MM-dd HH:mm:ss default-property-inclusion: non_null + mvc: + pathmatch: + matching-strategy: ant_path_matcher + # MyBatis 配置 mybatis: mapper-locations: classpath:mapper/*.xml @@ -50,7 +54,9 @@ mybatis: # JWT 配置 jwt: - secret: by-crm-secret-key-2024-please-change-in-production + # HS512 算法要求密钥至少 64 字节(512 位) + # 生产环境请使用环境变量或密钥管理系统存储此密钥 + secret: by-crm-jwt-secret-key-2024-hs512-requires-at-least-64-bytes-for-secure-signing-please-change-in-production-environment expiration: 86400000 # 24小时,单位:毫秒 # CRM 业务配置 diff --git a/backend/src/main/resources/mapper/CustomerMapper.xml b/backend/src/main/resources/mapper/CustomerMapper.xml index ddfe881..29f2097 100644 --- a/backend/src/main/resources/mapper/CustomerMapper.xml +++ b/backend/src/main/resources/mapper/CustomerMapper.xml @@ -14,6 +14,13 @@ + + + + + + + @@ -77,4 +84,36 @@ DELETE FROM crm_customer WHERE id = #{id} + + diff --git a/backend/src/main/resources/mapper/DealerMapper.xml b/backend/src/main/resources/mapper/DealerMapper.xml index 15e96c4..52fe218 100644 --- a/backend/src/main/resources/mapper/DealerMapper.xml +++ b/backend/src/main/resources/mapper/DealerMapper.xml @@ -13,6 +13,7 @@ + @@ -61,4 +64,8 @@ DELETE FROM crm_dealer WHERE id = #{id} + + diff --git a/backend/src/main/resources/mapper/ReportMapper.xml b/backend/src/main/resources/mapper/ReportMapper.xml index 8e8bdcd..ca15377 100644 --- a/backend/src/main/resources/mapper/ReportMapper.xml +++ b/backend/src/main/resources/mapper/ReportMapper.xml @@ -119,4 +119,23 @@ + + + + diff --git a/backend/src/main/resources/mapper/SchoolMapper.xml b/backend/src/main/resources/mapper/SchoolMapper.xml new file mode 100644 index 0000000..05826e2 --- /dev/null +++ b/backend/src/main/resources/mapper/SchoolMapper.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + INSERT INTO crm_school (school_code, school_name, location, created_at, updated_at) + VALUES (#{schoolCode}, #{schoolName}, #{location}, #{createdAt}, #{updatedAt}) + + + + INSERT INTO crm_school (school_code, school_name, location, created_at, updated_at) + VALUES + + (#{item.schoolCode}, #{item.schoolName}, #{item.location}, #{item.createdAt}, #{item.updatedAt}) + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/mapper/SystemConfigMapper.xml b/backend/src/main/resources/mapper/SystemConfigMapper.xml new file mode 100644 index 0000000..d0545e3 --- /dev/null +++ b/backend/src/main/resources/mapper/SystemConfigMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + UPDATE crm_system_config + SET config_value = #{configValue}, + updated_at = NOW() + WHERE config_key = #{configKey} + + + + + UPDATE crm_system_config + SET config_value = #{config.configValue}, + updated_at = NOW() + WHERE config_key = #{config.configKey} + + + + diff --git a/backend/target/classes/application.yml b/backend/target/classes/application.yml new file mode 100644 index 0000000..d8c4d88 --- /dev/null +++ b/backend/target/classes/application.yml @@ -0,0 +1,81 @@ +server: + port: 8080 + servlet: + context-path: /api + +spring: + application: + name: by-crm + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://192.168.3.80:3306/by_crm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: "Boyun@123" + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 60000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + validation-query: SELECT 1 + test-while-idle: true + test-on-borrow: false + test-on-return: false + filters: stat,wall + web-stat-filter: + enabled: true + url-pattern: /* + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + login-username: admin + login-password: admin123 + + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + default-property-inclusion: non_null + + mvc: + pathmatch: + matching-strategy: ant_path_matcher + +# MyBatis 配置 +mybatis: + mapper-locations: classpath:mapper/*.xml + type-aliases-package: com.bycrm.entity + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + +# JWT 配置 +jwt: + # HS512 算法要求密钥至少 64 字节(512 位) + # 生产环境请使用环境变量或密钥管理系统存储此密钥 + secret: by-crm-jwt-secret-key-2024-hs512-requires-at-least-64-bytes-for-secure-signing-please-change-in-production-environment + expiration: 86400000 # 24小时,单位:毫秒 + +# CRM 业务配置 +crm: + report: + ttl-days: 90 # 保护期天数 + allow-overlap: false # 是否允许重叠报备(生产环境必须为 false) + +# Swagger 配置 +springfox: + documentation: + swagger-ui: + enabled: true + enabled: true + +# 日志配置 +logging: + level: + com.bycrm.mapper: debug + org.springframework.web: info + pattern: + console: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n' diff --git a/backend/target/classes/com/bycrm/ByCrmApplication.class b/backend/target/classes/com/bycrm/ByCrmApplication.class new file mode 100644 index 0000000..173a0a8 Binary files /dev/null and b/backend/target/classes/com/bycrm/ByCrmApplication.class differ diff --git a/backend/target/classes/com/bycrm/annotations/AuthRequired.class b/backend/target/classes/com/bycrm/annotations/AuthRequired.class new file mode 100644 index 0000000..3022a9a Binary files /dev/null and b/backend/target/classes/com/bycrm/annotations/AuthRequired.class differ diff --git a/backend/target/classes/com/bycrm/common/Constants.class b/backend/target/classes/com/bycrm/common/Constants.class new file mode 100644 index 0000000..58c9845 Binary files /dev/null and b/backend/target/classes/com/bycrm/common/Constants.class differ diff --git a/backend/target/classes/com/bycrm/common/PageResult.class b/backend/target/classes/com/bycrm/common/PageResult.class new file mode 100644 index 0000000..459c381 Binary files /dev/null and b/backend/target/classes/com/bycrm/common/PageResult.class differ diff --git a/backend/target/classes/com/bycrm/common/Result.class b/backend/target/classes/com/bycrm/common/Result.class new file mode 100644 index 0000000..5a824a9 Binary files /dev/null and b/backend/target/classes/com/bycrm/common/Result.class differ diff --git a/backend/target/classes/com/bycrm/config/AuthInterceptor.class b/backend/target/classes/com/bycrm/config/AuthInterceptor.class new file mode 100644 index 0000000..5baab95 Binary files /dev/null and b/backend/target/classes/com/bycrm/config/AuthInterceptor.class differ diff --git a/backend/target/classes/com/bycrm/config/CorsConfig.class b/backend/target/classes/com/bycrm/config/CorsConfig.class new file mode 100644 index 0000000..e03cef0 Binary files /dev/null and b/backend/target/classes/com/bycrm/config/CorsConfig.class differ diff --git a/backend/target/classes/com/bycrm/config/MyBatisConfig.class b/backend/target/classes/com/bycrm/config/MyBatisConfig.class new file mode 100644 index 0000000..cdd6bc7 Binary files /dev/null and b/backend/target/classes/com/bycrm/config/MyBatisConfig.class differ diff --git a/backend/target/classes/com/bycrm/config/SwaggerConfig.class b/backend/target/classes/com/bycrm/config/SwaggerConfig.class new file mode 100644 index 0000000..01d558f Binary files /dev/null and b/backend/target/classes/com/bycrm/config/SwaggerConfig.class differ diff --git a/backend/target/classes/com/bycrm/config/WebMvcConfig.class b/backend/target/classes/com/bycrm/config/WebMvcConfig.class new file mode 100644 index 0000000..cd43aac Binary files /dev/null and b/backend/target/classes/com/bycrm/config/WebMvcConfig.class differ diff --git a/backend/target/classes/com/bycrm/controller/AuthController$LoginResponse.class b/backend/target/classes/com/bycrm/controller/AuthController$LoginResponse.class new file mode 100644 index 0000000..e3aab6a Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/AuthController$LoginResponse.class differ diff --git a/backend/target/classes/com/bycrm/controller/AuthController.class b/backend/target/classes/com/bycrm/controller/AuthController.class new file mode 100644 index 0000000..60b8f98 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/AuthController.class differ diff --git a/backend/target/classes/com/bycrm/controller/CustomerController.class b/backend/target/classes/com/bycrm/controller/CustomerController.class new file mode 100644 index 0000000..404b397 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/CustomerController.class differ diff --git a/backend/target/classes/com/bycrm/controller/DashboardController.class b/backend/target/classes/com/bycrm/controller/DashboardController.class new file mode 100644 index 0000000..f61ed69 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/DashboardController.class differ diff --git a/backend/target/classes/com/bycrm/controller/DealerController.class b/backend/target/classes/com/bycrm/controller/DealerController.class new file mode 100644 index 0000000..4ed0852 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/DealerController.class differ diff --git a/backend/target/classes/com/bycrm/controller/ReportController.class b/backend/target/classes/com/bycrm/controller/ReportController.class new file mode 100644 index 0000000..68aa9c8 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/ReportController.class differ diff --git a/backend/target/classes/com/bycrm/controller/SchoolController.class b/backend/target/classes/com/bycrm/controller/SchoolController.class new file mode 100644 index 0000000..27c10ff Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/SchoolController.class differ diff --git a/backend/target/classes/com/bycrm/controller/SystemConfigController.class b/backend/target/classes/com/bycrm/controller/SystemConfigController.class new file mode 100644 index 0000000..cd3e5e4 Binary files /dev/null and b/backend/target/classes/com/bycrm/controller/SystemConfigController.class differ diff --git a/backend/target/classes/com/bycrm/dto/ChangePasswordDTO.class b/backend/target/classes/com/bycrm/dto/ChangePasswordDTO.class new file mode 100644 index 0000000..6be3fc5 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/ChangePasswordDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/CustomerDTO.class b/backend/target/classes/com/bycrm/dto/CustomerDTO.class new file mode 100644 index 0000000..5d39c15 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/CustomerDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/DashboardStatisticsDTO.class b/backend/target/classes/com/bycrm/dto/DashboardStatisticsDTO.class new file mode 100644 index 0000000..b0c9379 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/DashboardStatisticsDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/DealerDTO.class b/backend/target/classes/com/bycrm/dto/DealerDTO.class new file mode 100644 index 0000000..a9e6430 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/DealerDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/LoginDTO.class b/backend/target/classes/com/bycrm/dto/LoginDTO.class new file mode 100644 index 0000000..e8fd1eb Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/LoginDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/PageQuery.class b/backend/target/classes/com/bycrm/dto/PageQuery.class new file mode 100644 index 0000000..2c2429b Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/PageQuery.class differ diff --git a/backend/target/classes/com/bycrm/dto/ReportAuditDTO.class b/backend/target/classes/com/bycrm/dto/ReportAuditDTO.class new file mode 100644 index 0000000..175fa59 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/ReportAuditDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/ReportDTO.class b/backend/target/classes/com/bycrm/dto/ReportDTO.class new file mode 100644 index 0000000..a4b185d Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/ReportDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/ResetPasswordDTO.class b/backend/target/classes/com/bycrm/dto/ResetPasswordDTO.class new file mode 100644 index 0000000..ed1c667 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/ResetPasswordDTO.class differ diff --git a/backend/target/classes/com/bycrm/dto/SchoolDTO.class b/backend/target/classes/com/bycrm/dto/SchoolDTO.class new file mode 100644 index 0000000..f8f8740 Binary files /dev/null and b/backend/target/classes/com/bycrm/dto/SchoolDTO.class differ diff --git a/backend/target/classes/com/bycrm/entity/Customer.class b/backend/target/classes/com/bycrm/entity/Customer.class new file mode 100644 index 0000000..ebe5520 Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/Customer.class differ diff --git a/backend/target/classes/com/bycrm/entity/Dealer.class b/backend/target/classes/com/bycrm/entity/Dealer.class new file mode 100644 index 0000000..779591b Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/Dealer.class differ diff --git a/backend/target/classes/com/bycrm/entity/Dict.class b/backend/target/classes/com/bycrm/entity/Dict.class new file mode 100644 index 0000000..a60cf8a Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/Dict.class differ diff --git a/backend/target/classes/com/bycrm/entity/DictItem.class b/backend/target/classes/com/bycrm/entity/DictItem.class new file mode 100644 index 0000000..fba6e0b Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/DictItem.class differ diff --git a/backend/target/classes/com/bycrm/entity/OperationLog.class b/backend/target/classes/com/bycrm/entity/OperationLog.class new file mode 100644 index 0000000..92274d7 Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/OperationLog.class differ diff --git a/backend/target/classes/com/bycrm/entity/Report.class b/backend/target/classes/com/bycrm/entity/Report.class new file mode 100644 index 0000000..88d0b08 Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/Report.class differ diff --git a/backend/target/classes/com/bycrm/entity/School.class b/backend/target/classes/com/bycrm/entity/School.class new file mode 100644 index 0000000..5f07b2d Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/School.class differ diff --git a/backend/target/classes/com/bycrm/entity/SystemConfig.class b/backend/target/classes/com/bycrm/entity/SystemConfig.class new file mode 100644 index 0000000..51c4e73 Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/SystemConfig.class differ diff --git a/backend/target/classes/com/bycrm/entity/User.class b/backend/target/classes/com/bycrm/entity/User.class new file mode 100644 index 0000000..51d2324 Binary files /dev/null and b/backend/target/classes/com/bycrm/entity/User.class differ diff --git a/backend/target/classes/com/bycrm/exception/BusinessException.class b/backend/target/classes/com/bycrm/exception/BusinessException.class new file mode 100644 index 0000000..c3944df Binary files /dev/null and b/backend/target/classes/com/bycrm/exception/BusinessException.class differ diff --git a/backend/target/classes/com/bycrm/exception/GlobalExceptionHandler.class b/backend/target/classes/com/bycrm/exception/GlobalExceptionHandler.class new file mode 100644 index 0000000..0c18c6f Binary files /dev/null and b/backend/target/classes/com/bycrm/exception/GlobalExceptionHandler.class differ diff --git a/backend/target/classes/com/bycrm/mapper/CustomerMapper.class b/backend/target/classes/com/bycrm/mapper/CustomerMapper.class new file mode 100644 index 0000000..71362f3 Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/CustomerMapper.class differ diff --git a/backend/target/classes/com/bycrm/mapper/DealerMapper.class b/backend/target/classes/com/bycrm/mapper/DealerMapper.class new file mode 100644 index 0000000..a205076 Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/DealerMapper.class differ diff --git a/backend/target/classes/com/bycrm/mapper/ReportMapper.class b/backend/target/classes/com/bycrm/mapper/ReportMapper.class new file mode 100644 index 0000000..9225910 Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/ReportMapper.class differ diff --git a/backend/target/classes/com/bycrm/mapper/SchoolMapper.class b/backend/target/classes/com/bycrm/mapper/SchoolMapper.class new file mode 100644 index 0000000..20a2a3c Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/SchoolMapper.class differ diff --git a/backend/target/classes/com/bycrm/mapper/SystemConfigMapper.class b/backend/target/classes/com/bycrm/mapper/SystemConfigMapper.class new file mode 100644 index 0000000..51f35bd Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/SystemConfigMapper.class differ diff --git a/backend/target/classes/com/bycrm/mapper/UserMapper.class b/backend/target/classes/com/bycrm/mapper/UserMapper.class new file mode 100644 index 0000000..24801cc Binary files /dev/null and b/backend/target/classes/com/bycrm/mapper/UserMapper.class differ diff --git a/backend/target/classes/com/bycrm/service/CustomerService.class b/backend/target/classes/com/bycrm/service/CustomerService.class new file mode 100644 index 0000000..8ecdb26 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/CustomerService.class differ diff --git a/backend/target/classes/com/bycrm/service/DealerService.class b/backend/target/classes/com/bycrm/service/DealerService.class new file mode 100644 index 0000000..4ebb954 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/DealerService.class differ diff --git a/backend/target/classes/com/bycrm/service/ReportService.class b/backend/target/classes/com/bycrm/service/ReportService.class new file mode 100644 index 0000000..0cd9b5e Binary files /dev/null and b/backend/target/classes/com/bycrm/service/ReportService.class differ diff --git a/backend/target/classes/com/bycrm/service/SchoolService.class b/backend/target/classes/com/bycrm/service/SchoolService.class new file mode 100644 index 0000000..168bd68 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/SchoolService.class differ diff --git a/backend/target/classes/com/bycrm/service/SystemConfigService.class b/backend/target/classes/com/bycrm/service/SystemConfigService.class new file mode 100644 index 0000000..2c0bdda Binary files /dev/null and b/backend/target/classes/com/bycrm/service/SystemConfigService.class differ diff --git a/backend/target/classes/com/bycrm/service/UserService.class b/backend/target/classes/com/bycrm/service/UserService.class new file mode 100644 index 0000000..11b2cb8 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/UserService.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/CustomerServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/CustomerServiceImpl.class new file mode 100644 index 0000000..d787c74 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/CustomerServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/DealerServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/DealerServiceImpl.class new file mode 100644 index 0000000..6992b6e Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/DealerServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/ReportServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/ReportServiceImpl.class new file mode 100644 index 0000000..5d2cf39 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/ReportServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/SchoolServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/SchoolServiceImpl.class new file mode 100644 index 0000000..cc7ecd8 Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/SchoolServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/SystemConfigServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/SystemConfigServiceImpl.class new file mode 100644 index 0000000..3e6bead Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/SystemConfigServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/service/impl/UserServiceImpl.class b/backend/target/classes/com/bycrm/service/impl/UserServiceImpl.class new file mode 100644 index 0000000..9f1c9af Binary files /dev/null and b/backend/target/classes/com/bycrm/service/impl/UserServiceImpl.class differ diff --git a/backend/target/classes/com/bycrm/task/ReportExpireTask.class b/backend/target/classes/com/bycrm/task/ReportExpireTask.class new file mode 100644 index 0000000..4826394 Binary files /dev/null and b/backend/target/classes/com/bycrm/task/ReportExpireTask.class differ diff --git a/backend/target/classes/com/bycrm/util/CheckExcelStructure$1.class b/backend/target/classes/com/bycrm/util/CheckExcelStructure$1.class new file mode 100644 index 0000000..ea9ffdc Binary files /dev/null and b/backend/target/classes/com/bycrm/util/CheckExcelStructure$1.class differ diff --git a/backend/target/classes/com/bycrm/util/CheckExcelStructure.class b/backend/target/classes/com/bycrm/util/CheckExcelStructure.class new file mode 100644 index 0000000..538f1b6 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/CheckExcelStructure.class differ diff --git a/backend/target/classes/com/bycrm/util/ImportSchools.class b/backend/target/classes/com/bycrm/util/ImportSchools.class new file mode 100644 index 0000000..f7622d7 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/ImportSchools.class differ diff --git a/backend/target/classes/com/bycrm/util/JwtUtil.class b/backend/target/classes/com/bycrm/util/JwtUtil.class new file mode 100644 index 0000000..87a22e8 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/JwtUtil.class differ diff --git a/backend/target/classes/com/bycrm/util/PasswordTest.class b/backend/target/classes/com/bycrm/util/PasswordTest.class new file mode 100644 index 0000000..aabb7c9 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/PasswordTest.class differ diff --git a/backend/target/classes/com/bycrm/util/SchoolImporter$1.class b/backend/target/classes/com/bycrm/util/SchoolImporter$1.class new file mode 100644 index 0000000..5dc27da Binary files /dev/null and b/backend/target/classes/com/bycrm/util/SchoolImporter$1.class differ diff --git a/backend/target/classes/com/bycrm/util/SchoolImporter.class b/backend/target/classes/com/bycrm/util/SchoolImporter.class new file mode 100644 index 0000000..ce914e6 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/SchoolImporter.class differ diff --git a/backend/target/classes/com/bycrm/util/SecureKeyGenerator.class b/backend/target/classes/com/bycrm/util/SecureKeyGenerator.class new file mode 100644 index 0000000..3a70272 Binary files /dev/null and b/backend/target/classes/com/bycrm/util/SecureKeyGenerator.class differ diff --git a/backend/target/classes/com/bycrm/vo/CustomerVO.class b/backend/target/classes/com/bycrm/vo/CustomerVO.class new file mode 100644 index 0000000..3f7c3ad Binary files /dev/null and b/backend/target/classes/com/bycrm/vo/CustomerVO.class differ diff --git a/backend/target/classes/com/bycrm/vo/ReportVO.class b/backend/target/classes/com/bycrm/vo/ReportVO.class new file mode 100644 index 0000000..3433359 Binary files /dev/null and b/backend/target/classes/com/bycrm/vo/ReportVO.class differ diff --git a/backend/target/classes/com/bycrm/vo/SchoolVO.class b/backend/target/classes/com/bycrm/vo/SchoolVO.class new file mode 100644 index 0000000..b63a2bf Binary files /dev/null and b/backend/target/classes/com/bycrm/vo/SchoolVO.class differ diff --git a/backend/target/classes/com/bycrm/vo/UserInfoVO.class b/backend/target/classes/com/bycrm/vo/UserInfoVO.class new file mode 100644 index 0000000..f706abc Binary files /dev/null and b/backend/target/classes/com/bycrm/vo/UserInfoVO.class differ diff --git a/backend/target/classes/mapper/CustomerMapper.xml b/backend/target/classes/mapper/CustomerMapper.xml new file mode 100644 index 0000000..29f2097 --- /dev/null +++ b/backend/target/classes/mapper/CustomerMapper.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO crm_customer (name, phone, address, industry, status) + VALUES (#{name}, #{phone}, #{address}, #{industry}, #{status}) + + + + UPDATE crm_customer + + name = #{name}, + phone = #{phone}, + address = #{address}, + industry = #{industry}, + status = #{status}, + + WHERE id = #{id} + + + + DELETE FROM crm_customer WHERE id = #{id} + + + + + diff --git a/backend/target/classes/mapper/DealerMapper.xml b/backend/target/classes/mapper/DealerMapper.xml new file mode 100644 index 0000000..52fe218 --- /dev/null +++ b/backend/target/classes/mapper/DealerMapper.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO crm_dealer (name, code, contact_person, contact_phone, email, status) + VALUES (#{name}, #{code}, #{contactPerson}, #{contactPhone}, #{email}, #{status}) + + + + UPDATE crm_dealer + + name = #{name}, + code = #{code}, + contact_person = #{contactPerson}, + contact_phone = #{contactPhone}, + email = #{email}, + status = #{status}, + + WHERE id = #{id} + + + + DELETE FROM crm_dealer WHERE id = #{id} + + + + + diff --git a/backend/target/classes/mapper/ReportMapper.xml b/backend/target/classes/mapper/ReportMapper.xml new file mode 100644 index 0000000..ca15377 --- /dev/null +++ b/backend/target/classes/mapper/ReportMapper.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO crm_report (dealer_id, customer_id, description, status, protect_start_date, protect_end_date) + VALUES (#{dealerId}, #{customerId}, #{description}, #{status}, #{protectStartDate}, #{protectEndDate}) + + + + UPDATE crm_report + + status = #{status}, + reject_reason = #{rejectReason}, + protect_start_date = #{protectStartDate}, + protect_end_date = #{protectEndDate}, + + WHERE id = #{id} + + + + DELETE FROM crm_report WHERE id = #{id} + + + + + + UPDATE crm_report + SET status = 3 + WHERE id IN + + #{id} + + + + + + + + diff --git a/backend/target/classes/mapper/SchoolMapper.xml b/backend/target/classes/mapper/SchoolMapper.xml new file mode 100644 index 0000000..05826e2 --- /dev/null +++ b/backend/target/classes/mapper/SchoolMapper.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + INSERT INTO crm_school (school_code, school_name, location, created_at, updated_at) + VALUES (#{schoolCode}, #{schoolName}, #{location}, #{createdAt}, #{updatedAt}) + + + + INSERT INTO crm_school (school_code, school_name, location, created_at, updated_at) + VALUES + + (#{item.schoolCode}, #{item.schoolName}, #{item.location}, #{item.createdAt}, #{item.updatedAt}) + + + + + + + + + + + + + + diff --git a/backend/target/classes/mapper/SystemConfigMapper.xml b/backend/target/classes/mapper/SystemConfigMapper.xml new file mode 100644 index 0000000..d0545e3 --- /dev/null +++ b/backend/target/classes/mapper/SystemConfigMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + UPDATE crm_system_config + SET config_value = #{configValue}, + updated_at = NOW() + WHERE config_key = #{configKey} + + + + + UPDATE crm_system_config + SET config_value = #{config.configValue}, + updated_at = NOW() + WHERE config_key = #{config.configKey} + + + + diff --git a/backend/target/classes/mapper/UserMapper.xml b/backend/target/classes/mapper/UserMapper.xml new file mode 100644 index 0000000..efc1d3c --- /dev/null +++ b/backend/target/classes/mapper/UserMapper.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO crm_user (username, password, real_name, dealer_id, role, status) + VALUES (#{username}, #{password}, #{realName}, #{dealerId}, #{role}, #{status}) + + + + UPDATE crm_user + + password = #{password}, + real_name = #{realName}, + dealer_id = #{dealerId}, + role = #{role}, + status = #{status}, + + WHERE id = #{id} + + + + DELETE FROM crm_user WHERE id = #{id} + + + diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-cli/createdFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-cli/createdFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-cli/inputFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-cli/inputFiles.lst new file mode 100644 index 0000000..9bec953 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-cli/inputFiles.lst @@ -0,0 +1,46 @@ +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\DealerDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\DealerController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\ReportAuditDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\ReportServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\LoginDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\AuthController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\util\JwtUtil.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\PageQuery.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\Result.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Dict.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\exception\BusinessException.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\WebMvcConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\UserInfoVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\DealerMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\UserMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Report.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\Constants.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\PageResult.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\CorsConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\ReportController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Customer.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\UserService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\SwaggerConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\ByCrmApplication.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\ReportService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\User.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Dealer.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\DealerService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\ReportMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\DealerServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\OperationLog.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\CustomerVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\DictItem.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\exception\GlobalExceptionHandler.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\ReportVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\CustomerService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\MyBatisConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\CustomerDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\ReportDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\CustomerMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\CustomerController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\CustomerServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\annotations\AuthRequired.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\AuthInterceptor.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\UserServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\task\ReportExpireTask.java diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..28731ab --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +com\bycrm\util\PasswordTest.class diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..0f5e831 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,47 @@ +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\DealerDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\DealerController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\ReportAuditDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\ReportServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\LoginDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\AuthController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\util\JwtUtil.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\PageQuery.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\Result.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Dict.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\exception\BusinessException.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\WebMvcConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\UserInfoVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\DealerMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\UserMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Report.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\Constants.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\common\PageResult.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\CorsConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\ReportController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\util\PasswordTest.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Customer.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\UserService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\SwaggerConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\ByCrmApplication.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\ReportService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\User.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\Dealer.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\DealerService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\ReportMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\DealerServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\OperationLog.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\CustomerVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\entity\DictItem.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\exception\GlobalExceptionHandler.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\vo\ReportVO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\CustomerService.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\MyBatisConfig.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\CustomerDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\dto\ReportDTO.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\mapper\CustomerMapper.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\controller\CustomerController.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\CustomerServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\annotations\AuthRequired.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\config\AuthInterceptor.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\service\impl\UserServiceImpl.java +E:\boyun-workspace\by-crm\backend\src\main\java\com\bycrm\task\ReportExpireTask.java