Files
smartDriveEE/src/main/java/com/rj/controller/CustomerManagementController.java

524 lines
26 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.rj.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rj.common.AudioManagementConstants;
import com.rj.common.DataEnrichmentUtil;
import com.rj.dto.CustomerPhotoPreviewResult;
import com.rj.dto.CustomerPhotoUploadResult;
import com.rj.dto.CustomerStageUpdateResult;
import com.rj.dto.NearbyMerchantSearchResult;
import com.rj.entity.AudioManagement;
import com.rj.entity.CustomerManagement;
import com.rj.entity.SalesManagement;
import com.rj.service.IAudioManagementService;
import com.rj.service.ICustomerManagementService;
import com.rj.service.INearbyMerchantSearchService;
import com.rj.service.ISalesManagementService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* <p>
* 客户管理表 前端控制器
* </p>
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@RestController
@RequestMapping("/api/customerManagement")
@Tag(name = "客户管理", description = "客户管理相关接口")
public class CustomerManagementController {
@Autowired
private ICustomerManagementService customerManagementService;
@Autowired
private IAudioManagementService audioManagementService;
@Autowired
private ISalesManagementService salesManagementService;
@Autowired
private INearbyMerchantSearchService nearbyMerchantSearchService;
/**
* 新增客户
*/
@PostMapping("/add")
@Operation(summary = "新增客户", description = "添加新的客户信息")
@Transactional(rollbackFor = Exception.class)
public ResponseEntity<Map<String, Object>> addCustomer(
@Parameter(description = "客户信息", required = true)
@RequestBody CustomerManagement customerManagement) {
Map<String, Object> result = new HashMap<>();
try {
boolean isUpdate = customerManagement.getId() != null && !customerManagement.getId().trim().isEmpty();
LocalDateTime now = LocalDateTime.now();
String operationType = customerManagement.getOperationType();
String salesPhone = customerManagement.getSalesPhone();
if (isUpdate) {
CustomerManagement existing = customerManagementService.getById(customerManagement.getId());
if (existing == null) {
result.put("success", false);
result.put("message", "客户不存在,无法更新");
return ResponseEntity.badRequest().body(result);
}
// customerManagement.setCreateTime(existing.getCreateTime());
customerManagement.setUpdateTime(now);
customerManagement.setRecordingCount(customerManagement.getRecordingCount()+1);
} else {
// 根据salesPhone查询销售管理表获取经销商信息
if (salesPhone != null && !salesPhone.trim().isEmpty()) {
LambdaQueryWrapper<SalesManagement> salesQueryWrapper = new LambdaQueryWrapper<>();
salesQueryWrapper.eq(SalesManagement::getLoginAccount, salesPhone.trim());
List<SalesManagement> salesList = salesManagementService.list(salesQueryWrapper);
if (salesList != null && !salesList.isEmpty()) {
SalesManagement sales = salesList.get(0);
customerManagement.setDealershipId(sales.getDealershipId());
customerManagement.setDealershipName(sales.getDealershipName());
// 同时设置销售ID和销售名称
if (customerManagement.getSalesId() == null || customerManagement.getSalesId().trim().isEmpty()) {
customerManagement.setSalesId(sales.getId());
}
if (customerManagement.getSalesName() == null || customerManagement.getSalesName().trim().isEmpty()) {
customerManagement.setSalesName(sales.getSalesName());
}
}
}
customerManagement.setCreateTime(now);
customerManagement.setUpdateTime(now);
customerManagement.setRecordingCount(1);
}
boolean success = customerManagementService.saveOrUpdate(customerManagement);
if (success) {
if ("start".equalsIgnoreCase(operationType)) {
if (customerManagement.getId() == null || customerManagement.getId().trim().isEmpty()) {
throw new IllegalStateException("客户ID为空无法同步录音记录");
}
// 检查销售人员是否正在服务其他客户
if (salesPhone != null && !salesPhone.trim().isEmpty()) {
LambdaQueryWrapper<AudioManagement> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AudioManagement::getSalesPhone, salesPhone.trim())
.eq(AudioManagement::getServiceStatus, AudioManagementConstants.SERVICE_STATUS_IN_SERVICE);
long count = audioManagementService.count(queryWrapper);
if (count > 0) { //如果正在服务,就直接返回,不能新增记录
result.put("success", true);
result.put("message", isUpdate ? "客户信息更新成功" : "客户添加成功");
result.put("message", "该销售人员正在服务其他客户,无法创建新的服务记录");
return ResponseEntity.badRequest().body(result); //如果正在服务,就直接返回,不能新增记录
}
}
AudioManagement audioRecord = buildAudioRecordFromCustomer(customerManagement, now);
boolean audioSaved = audioManagementService.save(audioRecord);
if (!audioSaved) {
throw new IllegalStateException("录音管理数据保存失败");
}
result.put("audioRecordId", audioRecord.getId());
}
result.put("success", true);
result.put("message", isUpdate ? "客户信息更新成功" : "客户添加成功");
result.put("data", customerManagement);
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", isUpdate ? "客户信息更新失败" : "客户添加失败");
return ResponseEntity.badRequest().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "客户添加异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 根据ID查询客户
*/
@GetMapping("/get/{id}")
@Operation(summary = "根据ID查询客户", description = "根据客户ID获取客户详细信息")
public ResponseEntity<Map<String, Object>> getCustomerById(
@Parameter(description = "客户ID", required = true)
@PathVariable String id) {
Map<String, Object> result = new HashMap<>();
try {
CustomerManagement customer = customerManagementService.getById(id);
if (customer != null) {
result.put("success", true);
result.put("message", "查询成功");
result.put("data", customer);
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "客户不存在");
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 根据联系方式查询客户
*/
@GetMapping("/getByContact")
@Operation(summary = "根据联系方式查询客户", description = "根据客户联系方式查询客户信息")
public ResponseEntity<Map<String, Object>> getCustomerByContact(
@Parameter(description = "联系方式", required = true)
@RequestParam String contact) {
Map<String, Object> result = new HashMap<>();
try {
LambdaQueryWrapper<CustomerManagement> queryWrapper = new LambdaQueryWrapper<>();
if (contact != null && !contact.trim().isEmpty()) {
queryWrapper.like(CustomerManagement::getContact, contact.trim());
}
List<CustomerManagement> customers = customerManagementService.list(queryWrapper);
result.put("success", true);
result.put("message", "查询成功");
result.put("data", customers);
result.put("count", customers.size());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
@Autowired
private DataEnrichmentUtil dataEnrichmentUtil;
/**
* 根据城市与地址做地理编码,再按半径搜索周边商家(高德 place/around逻辑同 AllShopCollectorV5
*/
@GetMapping("/searchNearbyMerchants")
@Operation(summary = "附近商家检索", description = "根据 CITY、ADDRESS 解析坐标,按 RADIUS、MAX_PAGE、maxRecordsOfpage 调用高德周边搜索")
public ResponseEntity<Map<String, Object>> searchNearbyMerchants(
@Parameter(description = "城市(传给高德地理编码 city", required = true) @RequestParam("CITY") String city,
@Parameter(description = "地址/地标(传给高德地理编码 address", required = true) @RequestParam("ADDRESS") String address,
@Parameter(description = "搜索半径(米)", required = true) @RequestParam("RADIUS") int radius,
@Parameter(description = "最大请求页数", required = true) @RequestParam("MAX_PAGE") int maxPage,
@Parameter(description = "每页条数150高德 offset", required = true) @RequestParam("maxRecordsOfpage") int maxRecordsOfpage) {
NearbyMerchantSearchResult search = nearbyMerchantSearchService.searchNearbyMerchants(
city, address, radius, maxPage, maxRecordsOfpage);
Map<String, Object> result = new HashMap<>();
result.put("success", search.isSuccess());
result.put("message", search.getMessage());
if (search.isSuccess()) {
result.put("centerLocation", search.getCenterLocation());
result.put("totalCount", search.getTotalCount());
result.put("data", search.getMerchants());
result.put("detailedReport", search.getDetailedReport());
result.put("customerInsertedCount", search.getCustomerInsertedCount());
}
return ResponseEntity.status(search.getHttpStatus()).body(result);
}
/**
* 分页查询客户列表
*/
@GetMapping("/list")
@Operation(summary = "分页查询客户列表", description = "分页查询客户信息列表")
public ResponseEntity<Map<String, Object>> getCustomerList(
@Parameter(description = "页码", example = "1")
@RequestParam(defaultValue = "1") Integer current,
@Parameter(description = "每页大小", example = "10")
@RequestParam(defaultValue = "10") Integer size,
@Parameter(description = "客户姓名(模糊查询)")@RequestParam(required = false) String customerName,
@Parameter(description = "所属人姓名(模糊查询)")@RequestParam(required = false) String salesName,
@Parameter(description = "所属人电话")@RequestParam(required = false) String salesPhone,
@Parameter(description = "联系方式(模糊查询)")
@RequestParam(required = false) String contact,
@Parameter(description = "联系方式(模糊查询)")
@RequestParam(required = false) String stage
) {
Map<String, Object> result = new HashMap<>();
try {
Page<CustomerManagement> page = new Page<>(current, size);
LambdaQueryWrapper<CustomerManagement> queryWrapper = new LambdaQueryWrapper<>();
// 添加查询条件
if (customerName != null && !customerName.trim().isEmpty()) {
queryWrapper.like(CustomerManagement::getCustomerName, customerName);
}
if (salesPhone != null && !salesPhone.trim().isEmpty()) {
queryWrapper.like(CustomerManagement::getSalesPhone, salesPhone);
}
if (contact != null && !contact.trim().isEmpty()) {
queryWrapper.like(CustomerManagement::getContact, contact);
}
if (stage != null && !stage.trim().isEmpty()) {
queryWrapper.eq(CustomerManagement::getStage, stage);
}
// 按创建时间倒序排列
queryWrapper.orderByDesc(CustomerManagement::getUpdateTime);
Page<CustomerManagement> customerPage = customerManagementService.page(page, queryWrapper);
// 使用工具类提取ID列表
List<String> dealershipIds = DataEnrichmentUtil.extractIds(customerPage.getRecords(), CustomerManagement::getDealershipId);
List<String> saleIds = DataEnrichmentUtil.extractIds(customerPage.getRecords(), CustomerManagement::getSalesId);
// 使用工具类批量获取关联数据
Map<String, String> dealershipNameMap = dataEnrichmentUtil.getDealershipIdNameMap(dealershipIds);
Map<String, String> saleNameMap = dataEnrichmentUtil.getSalesIdNameMap(saleIds);
// 填充关联数据
customerPage.getRecords().forEach(customer -> {
customer.setDealershipName(dealershipNameMap.get(customer.getDealershipId()));
customer.setSalesName(saleNameMap.get(customer.getSalesId()));
});
result.put("success", true);
result.put("message", "查询成功");
result.put("data", customerPage.getRecords());
result.put("total", customerPage.getTotal());
result.put("current", customerPage.getCurrent());
result.put("size", customerPage.getSize());
result.put("pages", customerPage.getPages());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("success", false);
result.put("message", "查询异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 更新客户信息
*/
@PutMapping("/update")
@Operation(summary = "更新客户信息", description = "更新客户详细信息")
public ResponseEntity<Map<String, Object>> updateCustomer(
@Parameter(description = "客户信息", required = true)
@RequestBody CustomerManagement customerManagement) {
Map<String, Object> result = new HashMap<>();
try {
if (customerManagement.getId() == null || customerManagement.getId().trim().isEmpty()) {
result.put("success", false);
result.put("message", "客户ID不能为空");
return ResponseEntity.badRequest().body(result);
}
customerManagement.setUpdateTime(LocalDateTime.now());
boolean success = customerManagementService.updateById(customerManagement);
if (success) {
result.put("success", true);
result.put("message", "客户信息更新成功");
result.put("data", customerManagement);
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "客户信息更新失败");
return ResponseEntity.badRequest().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "更新异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 根据客户 ID 更新阶段stage
*/
@PatchMapping("/updateStage")
@Operation(summary = "更新客户阶段", description = "根据客户 ID 更新 stage 字段")
public ResponseEntity<Map<String, Object>> updateStage(
@Parameter(description = "客户ID", required = true) @RequestParam String id,
@Parameter(description = "阶段", required = true) @RequestParam String stage) {
CustomerStageUpdateResult updateResult = customerManagementService.updateCustomerStage(id, stage);
Map<String, Object> result = new HashMap<>();
result.put("success", updateResult.isSuccess());
result.put("message", updateResult.getMessage());
if (updateResult.getCustomer() != null) {
result.put("data", updateResult.getCustomer());
}
return ResponseEntity.status(updateResult.getHttpStatus()).body(result);
}
/**
* 根据ID删除客户
*/
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除客户", description = "根据客户ID删除客户信息")
public ResponseEntity<Map<String, Object>> deleteCustomer(
@Parameter(description = "客户ID", required = true)
@PathVariable String id) {
Map<String, Object> result = new HashMap<>();
try {
boolean success = customerManagementService.removeById(id);
if (success) {
result.put("success", true);
result.put("message", "客户删除成功");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "客户删除失败");
return ResponseEntity.badRequest().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "删除异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 批量删除客户
*/
@DeleteMapping("/batchDelete")
@Operation(summary = "批量删除客户", description = "根据客户ID列表批量删除客户信息")
public ResponseEntity<Map<String, Object>> batchDeleteCustomers(
@Parameter(description = "客户ID列表", required = true)
@RequestBody List<String> ids) {
Map<String, Object> result = new HashMap<>();
try {
if (ids == null || ids.isEmpty()) {
result.put("success", false);
result.put("message", "客户ID列表不能为空");
return ResponseEntity.badRequest().body(result);
}
boolean success = customerManagementService.removeByIds(ids);
if (success) {
result.put("success", true);
result.put("message", "批量删除成功,共删除 " + ids.size() + " 条记录");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "批量删除失败");
return ResponseEntity.badRequest().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "批量删除异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 获取客户统计信息
*/
@GetMapping("/statistics")
@Operation(summary = "获取客户统计信息", description = "获取客户总数等统计信息")
public ResponseEntity<Map<String, Object>> getCustomerStatistics() {
Map<String, Object> result = new HashMap<>();
try {
long totalCount = customerManagementService.count();
Map<String, Object> statistics = new HashMap<>();
statistics.put("totalCustomers", totalCount);
result.put("success", true);
result.put("message", "统计信息获取成功");
result.put("data", statistics);
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("success", false);
result.put("message", "统计信息获取异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 客户照片上传至 MinIO返回可访问 URL
*/
@PostMapping("/uploadPhoto")
@Operation(summary = "上传客户照片", description = "根据客户ID上传照片到 MinIO返回文件访问 URL")
public ResponseEntity<Map<String, Object>> uploadCustomerPhoto(
@Parameter(description = "客户ID")
@RequestParam String id,
@Parameter(description = "照片文件", required = true)
@RequestParam("file") MultipartFile file) {
CustomerPhotoUploadResult uploadResult = customerManagementService.uploadCustomerPhoto(id, file);
Map<String, Object> result = new HashMap<>();
result.put("success", uploadResult.isSuccess());
result.put("message", uploadResult.getMessage());
if (uploadResult.getUrl() != null) {
result.put("url", uploadResult.getUrl());
}
return ResponseEntity.status(uploadResult.getHttpStatus()).body(result);
}
/**
* 客户照片预览:从 MinIO 拉流返回图片。
* 方式一:传 {@code url}(与上传接口返回的 MinIO 访问 URL 一致)。
* 方式二:传 {@code id} + {@code photoType}front / side / life读取客户表中对应照片 URL。
*/
@GetMapping("/previewPhoto")
@Operation(summary = "预览客户照片", description = "根据 MinIO URL 或客户ID+照片类型从 MinIO 读取并返回图片流,便于 img 标签 src 引用")
public ResponseEntity<Resource> previewCustomerPhoto(
@Parameter(description = "MinIO 完整访问 URL与 uploadPhoto 返回的 url 一致)")
@RequestParam(required = false) String url,
@Parameter(description = "客户ID与 photoType 联用")
@RequestParam(required = false) String id,
@Parameter(description = "照片类型front 正面 / side 侧面 / life 生活照", example = "front")
@RequestParam(required = false) String photoType) {
CustomerPhotoPreviewResult preview = customerManagementService.openCustomerPhotoPreview(url, id, photoType);
if (preview.getStatus() == CustomerPhotoPreviewResult.Status.NOT_FOUND) {
return ResponseEntity.notFound().build();
}
if (preview.getStatus() == CustomerPhotoPreviewResult.Status.BAD_REQUEST) {
return ResponseEntity.badRequest().build();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(preview.getContentType()));
headers.setCacheControl("private, max-age=3600");
Resource resource = new InputStreamResource(preview.getInputStream());
return ResponseEntity.ok().headers(headers).body(resource);
}
private AudioManagement buildAudioRecordFromCustomer(CustomerManagement customer, LocalDateTime now) {
AudioManagement audio = new AudioManagement();
audio.setId(UUID.randomUUID().toString());
String recordingName = customer.getCustomerName() != null && !customer.getCustomerName().trim().isEmpty()
? customer.getCustomerName() + "的接待记录"
: "客户接待记录";
audio.setRecordingName(recordingName);
audio.setRecordingTime(now);
audio.setUploadTime(now);
audio.setCreateTime(now);
audio.setUpdateTime(now);
audio.setCustomerId(customer.getId());
audio.setCustomerName(customer.getCustomerName());
audio.setCustomerPhone(customer.getContact());
audio.setSalesId(customer.getSalesId());
audio.setSalesName(customer.getSalesName());
audio.setSalesPhone(customer.getSalesPhone());
audio.setDealershipId(customer.getDealershipId());
audio.setDealershipName(customer.getDealershipName());
audio.setIntentionLevel(customer.getStage());
audio.setRemarks(customer.getDetailedAddress());
audio.setInfoCarddescription(customer.getInfoCard());
audio.setCompanyType(customer.getCustomerSource());
audio.setScenario(customer.getScenario());
audio.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_IN_SERVICE);
return audio;
}
}