This commit is contained in:
wangli 2026-01-30 00:41:50 +08:00
parent 628d9c9567
commit 16bb8fac3f
6 changed files with 105 additions and 24 deletions

View File

@ -0,0 +1,39 @@
package top.biwin.xinayu.common.dto.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* TODO
*
* @author wangli
* @since 2026-01-29 23:58
*/
@Data
public class AiSettingRequest {
@JsonProperty("ai_enabled")
private Boolean aiEnabled;
@JsonProperty("api_key")
private String apiKey;
@JsonProperty("base_url")
private String baseUrl;
@JsonProperty("custom_prompts")
private String customPrompts;
@JsonProperty("max_bargain_rounds")
private Integer maxBargainRounds;
@JsonProperty("max_discount_amount")
private Integer maxDiscountAmount;
@JsonProperty("max_discount_percent")
private Integer maxDiscountPercent;
@JsonProperty("model_name")
private String modelName;
}

View File

@ -1,5 +1,6 @@
package top.biwin.xianyu.core.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@ -17,37 +18,48 @@ public class AiReplySettingEntity {
@Id
@Column(name = "goofish_id")
@JsonProperty("goofish_id")
private String goofishId;
@Column(name = "ai_enabled")
@JsonProperty("ai_enabled")
private Boolean aiEnabled = false;
@Column(name = "model_name")
@JsonProperty("model_name")
private String modelName = "qwen-plus";
@Column(name = "api_key")
@JsonProperty("api_key")
private String apiKey;
@Column(name = "base_url")
@JsonProperty("base_url")
private String baseUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1";
@Column(name = "max_discount_percent")
@JsonProperty("max_discount_percent")
private Integer maxDiscountPercent = 10;
@Column(name = "max_discount_amount")
@JsonProperty("max_discount_amount")
private Integer maxDiscountAmount = 100;
@Column(name = "max_bargain_rounds")
@JsonProperty("max_bargain_rounds")
private Integer maxBargainRounds = 3;
@Column(name = "custom_prompts", columnDefinition = "TEXT")
@JsonProperty("custom_prompts")
private String customPrompts;
@CreationTimestamp
@Column(name = "created_at", updatable = false)
@JsonProperty("created_at")
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(name = "updated_at")
@JsonProperty("updated_at")
private LocalDateTime updatedAt;
}

View File

@ -2,8 +2,12 @@ package top.biwin.xianyu.core.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import top.biwin.xianyu.core.entity.AdminUserEntity;
import top.biwin.xianyu.core.entity.AiReplySettingEntity;
import java.util.Optional;
@Repository
public interface AiReplySettingRepository extends JpaRepository<AiReplySettingEntity, String> {
}

View File

@ -85,6 +85,11 @@ public class HttpClientConfig {
*/
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
ObjectMapper mapper = new ObjectMapper();
// 注册 JavaTimeModule 以支持 Java 8 时间类型 (LocalDateTime )
mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
// 禁用将日期写为时间戳使其序列化为 ISO 格式字符串
mapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}

View File

@ -1,9 +1,13 @@
package top.biwin.xinayu.server.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.biwin.xianyu.core.entity.AiReplySettingEntity;
@ -12,6 +16,7 @@ import top.biwin.xianyu.core.entity.KeywordEntity;
import top.biwin.xianyu.core.repository.AiReplySettingRepository;
import top.biwin.xianyu.core.repository.GoofishAccountRepository;
import top.biwin.xianyu.core.repository.KeywordRepository;
import top.biwin.xinayu.common.dto.request.AiSettingRequest;
import top.biwin.xinayu.common.dto.response.KeywordResponse;
import java.util.List;
@ -47,6 +52,26 @@ public class KeywordController {
return ResponseEntity.ok(settings.stream().collect(Collectors.toMap(AiReplySettingEntity::getGoofishId, s -> s)));
}
@GetMapping("/ai-reply-settings/{accountId}")
public ResponseEntity<AiReplySettingEntity> getAiSetting(@PathVariable String accountId) {
return ResponseEntity.ok(aiReplySettingRepository.findById(accountId).orElse(null));
}
@PutMapping("/ai-reply-settings/{accountId}")
public ResponseEntity<AiReplySettingEntity> upsertAiSetting(@PathVariable String accountId, @RequestBody AiSettingRequest request) {
// Upsert 逻辑存在则更新不存在则创建
AiReplySettingEntity entity = aiReplySettingRepository.findById(accountId)
.orElseGet(() -> {
// 不存在时创建新实体
AiReplySettingEntity newEntity = new AiReplySettingEntity();
newEntity.setGoofishId(accountId);
return newEntity;
});
// 忽略 null 防止前端未传的字段覆盖已有值或默认值
BeanUtil.copyProperties(request, entity, CopyOptions.create().setIgnoreNullValue(true));
return ResponseEntity.ok(aiReplySettingRepository.save(entity));
}
@GetMapping("/keywords-with-item-id/{gid}")
public ResponseEntity<List<KeywordResponse>> getKeywordsWithItemId(@PathVariable Long gid) {

View File

@ -1,17 +1,11 @@
package top.biwin.xinayu.server.exception;
import org.springframework.http.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import top.biwin.xinayu.common.dto.response.BaseResponse;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* 全局异常处理器
* 统一处理认证授权相关的异常返回友好的 JSON 错误响应
@ -34,23 +28,25 @@ import java.util.Map;
* @author wangli
* @since 2026-01-21
*/
@Slf4j
@RestControllerAdvice
public class AuthenticationExceptionHandler {
/**
* 处理未知异常
* <p>
* 触发场景
* - 其他未被捕获的异常
*
* @param ex 异常对象
* @return ResponseEntity<BaseResponse> 错误响应
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<BaseResponse> handleException(Exception ex) {
return ResponseEntity.ok(BaseResponse.builder()
.success(false)
.message(ex.getMessage())
.build());
}
/**
* 处理未知异常
* <p>
* 触发场景
* - 其他未被捕获的异常
*
* @param ex 异常对象
* @return ResponseEntity<BaseResponse> 错误响应
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<BaseResponse> handleException(Exception ex) {
log.error("发生异常:{}", ex.getMessage(), ex);
return ResponseEntity.ok(BaseResponse.builder()
.success(false)
.message(ex.getMessage())
.build());
}
}