Compare commits

...

2 Commits

Author SHA1 Message Date
zhonghua1
0e316d64c3 微信小程序修改个人密码 2025-12-22 21:49:09 +08:00
zhonghua1
47cee381f4 修改销售密码, 代码优化。 2025-12-22 20:42:33 +08:00
4 changed files with 555 additions and 50 deletions

View File

@@ -9,7 +9,7 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cst</groupId>
<artifactId>Langchain4j-rj</artifactId>
<artifactId>AIDriverEEBackend</artifactId>
<version>1.251130.7-SNAPSHOT</version>
<name>Langchain4j-rj</name>
<description>Langchain4j-rj20250803</description>

View File

@@ -34,6 +34,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import java.util.*;
/**
@@ -80,6 +81,9 @@ public class AudioFileController {
@Autowired
private DeviceManagementMapper deviceManagementMapper;
@Autowired
private com.rj.service.IAudioManagementSegmentsService audioManagementSegmentsService;
public String deviceKey = "deviceManagementKey";
/**
@@ -972,6 +976,14 @@ public class AudioFileController {
audioUploadLog.getId(), audioUploadLog.getDeviceNo(), audioUploadLog.getFileName(),
audioUploadLog.getAudioManagementId());
// 保存到 audio_management_segments 表
try {
saveAudioManagementSegment(requestBody, processedData, localFilePath, file, audioUploadLog);
} catch (Exception e) {
log.error("保存音频分段记录到audio_management_segments表失败", e);
// 即使保存失败,也不影响音频上传日志的保存,只记录日志
}
} catch (Exception e) {
log.error("保存音频上传日志到数据库失败", e);
throw new RuntimeException("保存音频上传日志失败: " + e.getMessage(), e);
@@ -1112,6 +1124,384 @@ public class AudioFileController {
audioUploadLog.setCreateTime(now);
audioUploadLog.setUpdateTime(now);
}
/**
* 保存音频分段记录到 audio_management_segments 表
* 如果已存在相同的分段记录,则跳过保存(避免重复)
*
* @param requestBody 请求体数据
* @param processedData 处理后的数据
* @param localFilePath 本地文件路径
* @param file 上传的文件可能为null
* @param audioUploadLog 音频上传日志对象(已保存)
*/
private void saveAudioManagementSegment(Map<String, Object> requestBody,
Map<String, Object> processedData,
String localFilePath,
MultipartFile file,
YhyAudioUploadLog audioUploadLog) {
try {
// 1. 检查是否已经保存过使用requestBody中的标记
String segmentSavedKey = "audioManagementSegmentSaved";
if (requestBody.containsKey(segmentSavedKey) && Boolean.TRUE.equals(requestBody.get(segmentSavedKey))) {
log.info("音频分段记录已保存过,跳过重复保存");
return;
}
// 2. 创建音频分段对象
AudioManagementSegments segment = new AudioManagementSegments();
segment.setId(UUID.randomUUID().toString());
// 3. 设置父录音ID从requestBody中获取audioManagementId
Object audioManagementIdObj = requestBody.get("audioManagementId");
if (audioManagementIdObj != null) {
segment.setParentId(audioManagementIdObj.toString());
}
// 4. 从DeviceManagement中获取设备信息
DeviceManagement deviceManagement = (DeviceManagement) requestBody.get(deviceKey);
if (deviceManagement != null) {
segment.setTenantId(deviceManagement.getTenantId());
segment.setSalesPhone(deviceManagement.getSalesPhone());
segment.setSalesName(deviceManagement.getSalesName());
segment.setDealershipId(deviceManagement.getDealershipId());
segment.setDealershipName(deviceManagement.getDealershipName());
}
// 5. 从requestBody和processedData中提取字段
populateSegmentFromRequestData(segment, requestBody, processedData);
// 6. 设置文件相关字段
setSegmentFileFields(segment, localFilePath, file, audioUploadLog);
// 7. 解析时间字段并计算录音时长
parseAndSetSegmentTimeFields(segment, processedData);
// 8. 检查数据库中是否已存在相同的分段记录
if (isSegmentExists(segment)) {
log.info("音频分段记录已存在跳过保存。父录音ID: {}, chunkIndex: {}, deviceNo: {}, startTime: {}",
segment.getParentId(), segment.getChunkIndex(), segment.getDeviceNo(), segment.getStartTime());
// 标记为已保存,避免后续重复检查
requestBody.put(segmentSavedKey, true);
return;
}
// 9. 从AudioManagement中获取录音名称如果存在父录音
if (segment.getParentId() != null) {
populateSegmentFromAudioManagement(segment, segment.getParentId());
}
// 10. 设置通用字段
LocalDateTime now = TimeZoneUtils.now();
segment.setCreateTime(now);
segment.setUploadTime(now);
segment.setRecordingTime(now);
// 11. 设置默认状态
if (segment.getUploadStatus() == null) {
segment.setUploadStatus("已上传");
}
if (segment.getSyncStatus() == null) {
segment.setSyncStatus("未同步");
}
if (segment.getIsMerged() == null) {
segment.setIsMerged(false);
}
// 12. 保存到数据库
audioManagementSegmentsService.save(segment);
log.info("音频分段记录保存成功ID: {}, 父录音ID: {}, 设备号: {}, 文件名: {}",
segment.getId(), segment.getParentId(), segment.getDeviceNo(), segment.getAudioFileOriginalName());
// 13. 标记为已保存,避免重复保存
requestBody.put(segmentSavedKey, true);
} catch (Exception e) {
log.error("保存音频分段记录到audio_management_segments表失败", e);
throw new RuntimeException("保存音频分段记录失败: " + e.getMessage(), e);
}
}
/**
* 检查音频分段记录是否已存在
* 判断标准parent_id + chunk_index + deviceNo + start_time如果都存在
*
* @param segment 音频分段对象
* @return true表示已存在false表示不存在
*/
private boolean isSegmentExists(AudioManagementSegments segment) {
try {
// 如果缺少关键字段无法判断返回false允许保存
if (segment.getParentId() == null || segment.getParentId().isEmpty()) {
return false;
}
// 构建查询条件
LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AudioManagementSegments::getParentId, segment.getParentId());
// chunkIndex 如果存在,则必须匹配
if (segment.getChunkIndex() != null && !segment.getChunkIndex().isEmpty()) {
queryWrapper.eq(AudioManagementSegments::getChunkIndex, segment.getChunkIndex());
}
// deviceNo 如果存在,则必须匹配
if (segment.getDeviceNo() != null && !segment.getDeviceNo().isEmpty()) {
queryWrapper.eq(AudioManagementSegments::getDeviceNo, segment.getDeviceNo());
}
// startTime 如果存在,则必须匹配(精确到秒)
if (segment.getStartTime() != null) {
// 使用时间范围查询前后1秒内避免时间精度问题
LocalDateTime startTime = segment.getStartTime();
queryWrapper.between(AudioManagementSegments::getStartTime,
startTime.minusSeconds(1), startTime.plusSeconds(1));
}
// 如果文件路径存在,也作为判断条件之一
if (segment.getAudioFilePath() != null && !segment.getAudioFilePath().isEmpty()) {
queryWrapper.eq(AudioManagementSegments::getAudioFilePath, segment.getAudioFilePath());
}
// 查询是否存在
long count = audioManagementSegmentsService.count(queryWrapper);
return count > 0;
} catch (Exception e) {
log.warn("检查音频分段记录是否存在时发生异常,将允许保存: {}", e.getMessage());
// 如果检查失败,允许保存(避免因为检查逻辑问题导致数据丢失)
return false;
}
}
/**
* 从请求数据中填充音频分段字段
*
* @param segment 音频分段对象
* @param requestBody 请求体数据
* @param processedData 处理后的数据
*/
private void populateSegmentFromRequestData(AudioManagementSegments segment,
Map<String, Object> requestBody,
Map<String, Object> processedData) {
// 从requestBody中提取设备号
String deviceNo = extractStringField(requestBody, "deviceNo");
if (deviceNo != null) {
segment.setDeviceNo(deviceNo);
}
// 从processedData中提取字段
if (processedData != null) {
segment.setChunkIndex(extractStringField(processedData, "chunkIndex"));
}
}
/**
* 设置音频分段的文件相关字段
*
* @param segment 音频分段对象
* @param localFilePath 本地文件路径
* @param file 上传的文件可能为null
* @param audioUploadLog 音频上传日志对象
*/
private void setSegmentFileFields(AudioManagementSegments segment,
String localFilePath,
MultipartFile file,
YhyAudioUploadLog audioUploadLog) {
// 设置文件路径
if (localFilePath != null && !localFilePath.isEmpty()) {
segment.setAudioFilePath(localFilePath);
} else if (audioUploadLog.getSavePath() != null && audioUploadLog.getFileName() != null) {
segment.setAudioFilePath(audioUploadLog.getSavePath() + File.separator + audioUploadLog.getFileName());
}
// 设置文件原始名称
if (file != null && file.getOriginalFilename() != null) {
segment.setAudioFileOriginalName(file.getOriginalFilename());
} else if (audioUploadLog.getFileName() != null) {
segment.setAudioFileOriginalName(audioUploadLog.getFileName());
}
// 设置文件扩展名
String fileName = segment.getAudioFileOriginalName();
if (fileName != null) {
String extension = getFileExtension(fileName);
if (!extension.isEmpty()) {
segment.setAudioFileExtension(extension);
}
}
// 设置文件大小
if (file != null && file.getSize() > 0) {
segment.setAudioFileSize(file.getSize());
}
}
/**
* 解析时间字段并计算录音时长
*
* @param segment 音频分段对象
* @param processedData 处理后的数据
*/
private void parseAndSetSegmentTimeFields(AudioManagementSegments segment,
Map<String, Object> processedData) {
if (processedData == null) {
return;
}
// 解析开始时间
LocalDateTime startTime = parseDateTimeField(processedData, "startTime");
if (startTime != null) {
segment.setStartTime(startTime);
}
// 解析结束时间
LocalDateTime endTime = parseDateTimeField(processedData, "endTime");
if (endTime != null) {
segment.setEndTime(endTime);
}
// 计算录音时长(分钟)
if (startTime != null && endTime != null && endTime.isAfter(startTime)) {
long seconds = java.time.Duration.between(startTime, endTime).getSeconds();
BigDecimal durationMinutes = BigDecimal.valueOf(seconds).divide(BigDecimal.valueOf(60), 2,
java.math.RoundingMode.HALF_UP);
segment.setDuration(durationMinutes);
}
}
/**
* 解析时间字段
*
* @param dataMap 数据Map
* @param fieldName 字段名
* @return LocalDateTime对象如果解析失败则返回null
*/
private LocalDateTime parseDateTimeField(Map<String, Object> dataMap, String fieldName) {
if (dataMap == null || fieldName == null) {
return null;
}
Object timeObj = dataMap.get(fieldName);
if (timeObj == null) {
return null;
}
// 如果已经是LocalDateTime类型直接返回
if (timeObj instanceof LocalDateTime) {
return (LocalDateTime) timeObj;
}
// 如果是String类型尝试解析
if (timeObj instanceof String) {
String timeStr = (String) timeObj;
if (timeStr.trim().isEmpty()) {
return null;
}
try {
// 使用TimeZoneUtils或类似的方法解析时间字符串
// 这里简化处理使用LocalDateTimeDeserializer的逻辑
return parseTimeString(timeStr);
} catch (Exception e) {
log.warn("解析时间字段失败: {} = {}", fieldName, timeStr, e);
return null;
}
}
return null;
}
/**
* 解析时间字符串
* 支持多种格式ISO格式、标准格式等
*
* @param timeStr 时间字符串
* @return LocalDateTime对象
*/
private LocalDateTime parseTimeString(String timeStr) {
if (timeStr == null || timeStr.trim().isEmpty()) {
return null;
}
try {
// 检测是否包含时区信息
boolean hasTimezone = timeStr.endsWith("Z") ||
timeStr.matches(".*[+-]\\d{2}:\\d{2}(?:\\d{2})?$");
if (hasTimezone) {
// 处理带时区的时间
java.time.ZonedDateTime zonedDateTime;
if (timeStr.endsWith("Z")) {
zonedDateTime = java.time.ZonedDateTime.parse(timeStr.replace("Z", "+00:00"))
.withZoneSameInstant(TimeZoneUtils.getZoneId());
} else {
zonedDateTime = java.time.ZonedDateTime.parse(timeStr)
.withZoneSameInstant(TimeZoneUtils.getZoneId());
}
return zonedDateTime.toLocalDateTime();
} else {
// 处理不带时区的时间
String cleanTimeStr = timeStr;
if (cleanTimeStr.contains("T")) {
cleanTimeStr = cleanTimeStr.replace("T", " ");
}
if (cleanTimeStr.contains(".")) {
cleanTimeStr = cleanTimeStr.substring(0, cleanTimeStr.indexOf("."));
}
if (cleanTimeStr.length() > 19) {
cleanTimeStr = cleanTimeStr.substring(0, 19);
}
return LocalDateTime.parse(cleanTimeStr,
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
} catch (Exception e) {
log.warn("解析时间字符串失败: {}", timeStr, e);
return null;
}
}
/**
* 从AudioManagement中获取录音名称等信息
*
* @param segment 音频分段对象
* @param parentId 父录音ID
*/
private void populateSegmentFromAudioManagement(AudioManagementSegments segment, String parentId) {
try {
AudioManagement audioManagement = serviceManager.getAudioManagementService().getById(parentId);
if (audioManagement != null) {
// 如果录音名称为空,使用父录音的名称
if (segment.getRecordingName() == null || segment.getRecordingName().isEmpty()) {
segment.setRecordingName(audioManagement.getRecordingName());
}
// 如果销售信息为空,使用父录音的销售信息
if (segment.getSalesPhone() == null || segment.getSalesPhone().isEmpty()) {
segment.setSalesPhone(audioManagement.getSalesPhone());
}
if (segment.getSalesName() == null || segment.getSalesName().isEmpty()) {
segment.setSalesName(audioManagement.getSalesName());
}
// 如果经销商信息为空,使用父录音的经销商信息
if (segment.getDealershipId() == null || segment.getDealershipId().isEmpty()) {
segment.setDealershipId(audioManagement.getDealershipId());
}
if (segment.getDealershipName() == null || segment.getDealershipName().isEmpty()) {
segment.setDealershipName(audioManagement.getDealershipName());
}
// 如果租户ID为空使用父录音的租户ID
if (segment.getTenantId() == null || segment.getTenantId().isEmpty()) {
segment.setTenantId(audioManagement.getTenantId());
}
}
} catch (Exception e) {
log.warn("从AudioManagement获取信息失败parentId: {}", parentId, e);
// 不影响主流程,只记录日志
}
}
/**
* 提取请求头信息
@@ -1467,48 +1857,153 @@ public class AudioFileController {
/**
* 处理Audio数据类型录音推送
* 适配新的数据结构dataType="Audio"数据在data字段中
* 同时兼容旧的数据结构数据直接在requestBody中
*
* @param requestBody 请求体数据
* @param file 上传的音频文件
* @return 处理结果包含success、message、localFilePath等
*/
private Map<String, Object> handleAudioDataType(Map<String, Object> requestBody, MultipartFile file) {
Map<String, Object> result = new HashMap<>();
log.info("开始处理Audio数据类型录音推送");
try {
log.info("处理Audio数据类型录音推送");
// 提取data字段
Object dataObj = requestBody.get("data");
Map<String, Object> dataMap = null;
if (dataObj != null) {
dataMap = objectMapper.convertValue(dataObj, new TypeReference<Map<String, Object>>() {});
// 1. 提取并解析data字段新数据结构
Map<String, Object> dataFromDataField = extractDataField(requestBody);
// 2. 判断使用新数据结构还是旧数据结构
if (isLegacyDataStructure(dataFromDataField)) {
log.info("检测到旧数据结构使用requestBody作为processedData");
return processLegacyAudioData(requestBody, file);
}
// 如果没有data字段尝试使用旧的数据结构(兼容处理
if (dataMap == null || dataMap.isEmpty()) {
// 使用旧的数据结构直接使用requestBody作为processedData
return handleAudioUpload(requestBody, requestBody, file,
(String) requestBody.get("deviceNo"),
(String) requestBody.get("filePath"));
}
// 构建兼容旧接口的数据结构
Map<String, Object> processedData = new HashMap<>(dataMap);
// 从requestBody中提取其他字段
String deviceNo = (String) requestBody.get("deviceNo");
String filePath = (String) requestBody.get("filePath");
if (filePath == null && dataMap.get("filePath") != null) {
filePath = (String) dataMap.get("filePath");
}
// 调用原有的音频上传处理方法
return handleAudioUpload(requestBody, processedData, file, deviceNo, filePath);
// 3. 使用新数据结构处理
log.info("检测到新数据结构从data字段提取数据");
return processNewAudioData(requestBody, dataFromDataField, file);
} catch (Exception e) {
log.error("处理Audio数据类型异常", e);
result.put("success", false);
result.put("message", "处理Audio数据类型异常: " + e.getMessage());
return result;
return createErrorResult("处理Audio数据类型异常: " + e.getMessage());
}
}
/**
* 从requestBody中提取data字段并转换为Map
*
* @param requestBody 请求体数据
* @return data字段转换后的Map如果不存在或转换失败则返回null
*/
private Map<String, Object> extractDataField(Map<String, Object> requestBody) {
if (requestBody == null) {
return null;
}
Object dataObj = requestBody.get("data");
if (dataObj == null) {
return null;
}
try {
Map<String, Object> dataMap = objectMapper.convertValue(
dataObj,
new TypeReference<Map<String, Object>>() {}
);
return dataMap;
} catch (Exception e) {
log.warn("解析data字段失败可能不是Map类型: {}", e.getMessage());
return null;
}
}
/**
* 判断是否为旧的数据结构
* 旧数据结构data字段不存在或为空
* 新数据结构data字段存在且不为空
*
* @param dataFromDataField 从data字段提取的数据
* @return true表示旧数据结构false表示新数据结构
*/
private boolean isLegacyDataStructure(Map<String, Object> dataFromDataField) {
return dataFromDataField == null || dataFromDataField.isEmpty();
}
/**
* 处理旧数据结构的Audio数据
* 旧数据结构数据直接在requestBody中没有data字段
*
* @param requestBody 请求体数据同时作为processedData
* @param file 上传的音频文件
* @return 处理结果
*/
private Map<String, Object> processLegacyAudioData(Map<String, Object> requestBody, MultipartFile file) {
String deviceNo = extractStringField(requestBody, "deviceNo");
String filePath = extractStringField(requestBody, "filePath");
return handleAudioUpload(requestBody, requestBody, file, deviceNo, filePath);
}
/**
* 处理新数据结构的Audio数据
* 新数据结构数据在data字段中requestBody中可能还有其他字段如deviceNo、filePath等
*
* @param requestBody 请求体数据
* @param dataFromDataField 从data字段提取的数据
* @param file 上传的音频文件
* @return 处理结果
*/
private Map<String, Object> processNewAudioData(Map<String, Object> requestBody,
Map<String, Object> dataFromDataField,
MultipartFile file) {
// 构建processedData以data字段中的数据为主
Map<String, Object> processedData = new HashMap<>(dataFromDataField);
// 提取关键字段优先使用requestBody中的字段如果不存在则使用data字段中的
String deviceNo = extractStringField(requestBody, "deviceNo");
String filePath = extractStringFieldWithFallback(requestBody, dataFromDataField, "filePath");
return handleAudioUpload(requestBody, processedData, file, deviceNo, filePath);
}
/**
* 从Map中提取String类型字段
*
* @param map 数据Map
* @param fieldName 字段名
* @return 字段值如果不存在或类型不匹配则返回null
*/
private String extractStringField(Map<String, Object> map, String fieldName) {
if (map == null || fieldName == null) {
return null;
}
Object value = map.get(fieldName);
if (value == null) {
return null;
}
return value.toString();
}
/**
* 从Map中提取String类型字段如果不存在则从fallbackMap中获取
*
* @param primaryMap 优先使用的Map
* @param fallbackMap 备用Map
* @param fieldName 字段名
* @return 字段值如果都不存在则返回null
*/
private String extractStringFieldWithFallback(Map<String, Object> primaryMap,
Map<String, Object> fallbackMap,
String fieldName) {
// 优先从primaryMap中获取
String value = extractStringField(primaryMap, fieldName);
if (value != null) {
return value;
}
// 如果primaryMap中没有从fallbackMap中获取
return extractStringField(fallbackMap, fieldName);
}
/**
* 处理Gps数据类型GPS日志
*/

View File

@@ -100,22 +100,32 @@ public class SalesManagementController {
}
String phone = salesManagement.getLoginAccount();
// 生成密码:当前日期 + 联系方式后4位
String password = generatePasswordForSales(phone);
User oldUser = userService.getUserByUserName(phone);
// 创建用户对象
User user = new User();
User newUser = new User();
ResponseEntity<Map<String, Object>> response = ResponseEntity.ok(new HashMap<>());
if (oldUser == null){
// user.setUserId(salesManagement.getId().hashCode());
user.setUserName(phone); // 用户名 = 销售人员电话
user.setPhone(phone); // 电话号码 = 销售人员电话
user.setOriginalPassword(salesManagement.getPassword());
newUser.setUserName(phone); // 用户名 = 销售人员电话
newUser.setPhone(phone); // 电话号码 = 销售人员电话
newUser.setOriginalPassword(salesManagement.getPassword());
newUser.setPassword(salesManagement.getPassword()); // 设置密码UserController会自动加密
newUser.setEmail(phone+"@YiDuoWang.com");
newUser.setTenantId(salesManagement.getTenantId());
// 调用UserController的addUser方法保存用户
response = userController.addUser(newUser);
}else {
oldUser.setPhone(phone); // 电话号码 = 销售人员电话
oldUser.setOriginalPassword(salesManagement.getPassword());
// encryptPassword(inputPassword,DEFAULT_SALT);
user.setPassword(salesManagement.getPassword()); // 设置密码UserController会自动加密
user.setEmail(phone+"@YiDuoWang.com");
user.setTenantId(salesManagement.getTenantId());
// 调用UserController的addUser方法保存用户
ResponseEntity<Map<String, Object>> response = userController.addUser(user);
oldUser.setPassword(salesManagement.getPassword()); // 设置密码UserController会自动加密
oldUser.setTenantId(salesManagement.getTenantId());
userController.updateUser(oldUser);
}
// 检查响应结果
if (response.getBody() != null) {
@@ -299,7 +309,7 @@ public class SalesManagementController {
salesManagement.setUpdateTime(LocalDateTime.now());
boolean success = salesManagementService.updateById(salesManagement);
createUserForSales(salesManagement);
if (success) {
result.put("success", true);
result.put("message", "销售信息更新成功");

View File

@@ -248,15 +248,15 @@ public class UserController {
result.put("message", "用户ID不能为空");
return ResponseEntity.badRequest().body(result);
}
// 检查用户名是否已被其他用户使用
User existingUser = userService.getUserByUserName(user.getUserName());
if (existingUser != null && !existingUser.getUserId().equals(user.getUserId())) {
User existingUser = userService.getById(user.getUserId());
if (!existingUser.getOriginalPassword().equals(user.getOriginalPassword())){
result.put("success", false);
result.put("message", "用户名已被其他用户使用");
result.put("message", "原始密码错误");
return ResponseEntity.badRequest().body(result);
}
// 如果密码不为空,则保存原始密码并加密
if (user.getPassword() != null && !user.getPassword().trim().isEmpty()) {
// 保存原始密码