init
This commit is contained in:
parent
7b2991bc84
commit
9eb9223bd8
@ -0,0 +1,15 @@
|
||||
package top.biwin.xinayu.common.dto.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2026-01-30 21:28
|
||||
*/
|
||||
@Data
|
||||
public class AccountUpdateRequest {
|
||||
private Boolean enabled;
|
||||
private String remark;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package top.biwin.xinayu.common.dto.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2026-01-30 21:10
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@SuperBuilder
|
||||
public class DefaultReplyResponse extends BaseResponse {
|
||||
|
||||
private Boolean enabled;
|
||||
@JsonProperty("reply_content")
|
||||
private String replyContent;
|
||||
@JsonProperty("reply_once")
|
||||
private Boolean replyOnce;
|
||||
@JsonProperty("reply_image_url")
|
||||
private String replyImageUrl;
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
package top.biwin.xinayu.common.dto.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@ -10,6 +13,9 @@ import lombok.Data;
|
||||
* @since 2026-01-22 21:52
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GoofishAccountResponse {
|
||||
private String id;
|
||||
private String cookie;
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package top.biwin.xianyu.core.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "default_replies")
|
||||
public class DefaultReplyEntity {
|
||||
|
||||
@Id
|
||||
@Column(name = "goofish_id")
|
||||
@JsonProperty("goofish_id")
|
||||
private String goofishId;
|
||||
|
||||
private Boolean enabled = false;
|
||||
|
||||
@Column(name = "reply_content", columnDefinition = "TEXT")
|
||||
@JsonProperty("reply_content")
|
||||
private String replyContent;
|
||||
|
||||
@Column(name = "reply_image_url")
|
||||
@JsonProperty("reply_image_url")
|
||||
private String replyImageUrl;
|
||||
|
||||
@Column(name = "reply_once")
|
||||
@JsonProperty("reply_once")
|
||||
private Boolean replyOnce = false;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_at", updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@UpdateTimestamp
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package top.biwin.xianyu.core.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.biwin.xianyu.core.entity.DefaultReplyEntity;
|
||||
|
||||
@Repository
|
||||
public interface DefaultReplyRepository extends JpaRepository<DefaultReplyEntity, String> {
|
||||
}
|
||||
@ -86,10 +86,13 @@ public class GoofishPwdLoginService {
|
||||
boolean resolveResult = attemptSolveSlider(loginFrame, account, new AtomicInteger(3));
|
||||
log.debug("【{}】滑块结果: {}!", account, resolveResult ? "成功" : "失败");
|
||||
if(resolveResult) {
|
||||
// 这里可能已经登录成功,等待选择是否持久化登录
|
||||
loginFrame.waitForTimeout(10000);
|
||||
log.debug("【{}】验证是否登录成功...", account);
|
||||
Frame lastCheckFrame = findLoginFrame(page, account);
|
||||
if(Objects.nonNull(lastCheckFrame)) {
|
||||
log.debug("【{}】登录失败,仍存在登录页面...", account);
|
||||
log.error("【{}】登录失败,仍存在登录页面...", account);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log.error("【{}】账号密码登录失败", account);
|
||||
|
||||
@ -3,6 +3,7 @@ package top.biwin.xianyu.goofish.util;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.microsoft.playwright.ElementHandle;
|
||||
import com.microsoft.playwright.Frame;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.Mouse;
|
||||
import com.microsoft.playwright.options.BoundingBox;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -12,6 +13,9 @@ import java.util.Objects;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.microsoft.playwright.CDPSession;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* 滑块验证码处理工具类
|
||||
* 模拟人类操作行为解决滑块验证
|
||||
@ -58,7 +62,6 @@ public final class SliderUtils {
|
||||
// 定位滑块按钮
|
||||
sliderButton = frame.querySelector("#nc_1_n1z");
|
||||
if (sliderButton == null) sliderButton = frame.querySelector(".nc_iconfont");
|
||||
|
||||
if (sliderButton != null && sliderButton.isVisible()) {
|
||||
log.info("【{}-处理滑块】检测到滑块验证,Frame: {}", goofishId, frame.url());
|
||||
BoundingBox box = sliderButton.boundingBox();
|
||||
@ -79,15 +82,10 @@ public final class SliderUtils {
|
||||
// 等待验证结果
|
||||
Thread.sleep(800 + ThreadLocalRandom.current().nextInt(400));
|
||||
|
||||
// // 检查滑块是否消失(成功标志)
|
||||
// if (!sliderButton.isVisible()) {
|
||||
// log.info("【{}-处理滑块】滑块验证成功!(按钮已消失)", goofishId);
|
||||
// return true;
|
||||
// }
|
||||
ElementHandle elementHandle = frame.querySelector("#nc_1_refresh1");
|
||||
if (Objects.nonNull(elementHandle)) {
|
||||
ElementHandle sliderBox = frame.querySelector("#nc_1_refresh1");
|
||||
if (Objects.nonNull(sliderBox) && sliderBox.isVisible()) {
|
||||
log.info("【{}-处理滑块】滑块验证失败,点击滑块重试!", goofishId);
|
||||
elementHandle.click();
|
||||
sliderBox.click();
|
||||
if (maxRetryCount.decrementAndGet() > 0) {
|
||||
return attemptSolveSlider(frame, goofishId, maxRetryCount);
|
||||
} else {
|
||||
@ -96,6 +94,8 @@ public final class SliderUtils {
|
||||
}
|
||||
}
|
||||
return success;
|
||||
} else {
|
||||
log.debug("【{}-处理滑块】未找到滑块按钮,可能是已经登录成功!", goofishId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("【{}-处理滑块】解决滑块时出错: {}", goofishId, e.getMessage(), e);
|
||||
@ -119,46 +119,98 @@ public final class SliderUtils {
|
||||
* @return 是否执行成功
|
||||
*/
|
||||
private static boolean performSmoothSlide(Frame frame, BoundingBox buttonBox, double distance, String goofishId) {
|
||||
CDPSession cdpSession = null;
|
||||
try {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
cdpSession = frame.page().context().newCDPSession(frame.page());
|
||||
|
||||
// 计算滑块起始位置(微小随机偏移)
|
||||
double startX = buttonBox.x + buttonBox.width / 2 + (random.nextDouble() - 0.5) * 4;
|
||||
double startY = buttonBox.y + buttonBox.height / 2 + (random.nextDouble() - 0.5) * 3;
|
||||
// 1. 计算人类特征起点(加入随机生理震颤偏移)
|
||||
double startX = buttonBox.x + buttonBox.width / 2 + random.nextDouble(-5.0, 5.0);
|
||||
double startY = buttonBox.y + buttonBox.height / 2 + random.nextDouble(-3.0, 3.0);
|
||||
|
||||
// 步骤1:移动鼠标到滑块位置
|
||||
frame.page().mouse().move(startX, startY);
|
||||
// 2. 鼠标移动到起点
|
||||
JsonObject moveParams = new JsonObject();
|
||||
moveParams.addProperty("type", "mouseMoved");
|
||||
moveParams.addProperty("x", startX);
|
||||
moveParams.addProperty("y", startY);
|
||||
cdpSession.send("Input.dispatchMouseEvent", moveParams);
|
||||
|
||||
// 步骤2:短暂停顿(人类反应时间:100-250ms)
|
||||
Thread.sleep(100 + random.nextInt(150));
|
||||
// 视觉确认时间
|
||||
Thread.sleep(80 + random.nextInt(120));
|
||||
|
||||
// 步骤3:按下鼠标
|
||||
frame.page().mouse().down();
|
||||
// 3. 点击鼠标按下
|
||||
JsonObject downParams = new JsonObject();
|
||||
downParams.addProperty("type", "mousePressed");
|
||||
downParams.addProperty("button", "left");
|
||||
downParams.addProperty("clickCount", 1);
|
||||
downParams.addProperty("x", startX);
|
||||
downParams.addProperty("y", startY);
|
||||
cdpSession.send("Input.dispatchMouseEvent", downParams);
|
||||
|
||||
// 步骤4:按下后极短延迟(30-60ms)
|
||||
Thread.sleep(30 + random.nextInt(30));
|
||||
// 肌肉准备发力延迟
|
||||
Thread.sleep(40 + random.nextInt(40));
|
||||
|
||||
// 步骤5:生成丝滑轨迹
|
||||
// 4. 执行轨迹渲染
|
||||
List<BrowserTrajectoryUtils.TrajectoryPoint> trajectory =
|
||||
BrowserTrajectoryUtils.generateFastTrajectory(distance);
|
||||
BrowserTrajectoryUtils.generateSmoothTrajectory(distance);
|
||||
|
||||
log.debug("【{}-处理滑块】生成轨迹点数: {}", goofishId, trajectory.size());
|
||||
log.info("【{}-处理滑块】CDP 发送高仿真轨迹,总计点数: {}", goofishId, trajectory.size());
|
||||
|
||||
// 步骤6:一气呵成快速滑动!!不加任何sleep!!
|
||||
for (BrowserTrajectoryUtils.TrajectoryPoint point : trajectory) {
|
||||
frame.page().mouse().move(startX + point.x, startY + point.y);
|
||||
// 不加sleep!让Playwright自己处理速度!
|
||||
int totalPoints = trajectory.size();
|
||||
for (int i = 0; i < totalPoints; i++) {
|
||||
BrowserTrajectoryUtils.TrajectoryPoint point = trajectory.get(i);
|
||||
|
||||
// 坐标映射:基础位置 + 轨迹偏移 + 微小生理抖动
|
||||
double targetX = startX + point.x;
|
||||
double targetY = startY + point.y + random.nextDouble(-0.8, 0.8);
|
||||
|
||||
JsonObject dragParams = new JsonObject();
|
||||
dragParams.addProperty("type", "mouseMoved");
|
||||
dragParams.addProperty("button", "left");
|
||||
dragParams.addProperty("x", targetX);
|
||||
dragParams.addProperty("y", targetY);
|
||||
cdpSession.send("Input.dispatchMouseEvent", dragParams);
|
||||
|
||||
// 仿真节奏:菲茨定律应用。前期(0-40%)极速冲刺,后期(70%后)精准瞄准降速
|
||||
double progress = (double) i / totalPoints;
|
||||
if (progress < 0.3) {
|
||||
// 极速段
|
||||
if (i % 2 == 0) Thread.sleep(1 + random.nextInt(2));
|
||||
} else if (progress < 0.7) {
|
||||
// 匀速段
|
||||
Thread.sleep(2 + random.nextInt(4));
|
||||
} else {
|
||||
// 减速修正段:人眼在接近目标时会频繁修正,延迟拉长
|
||||
Thread.sleep(5 + random.nextInt(12));
|
||||
}
|
||||
}
|
||||
|
||||
// 步骤7:释放鼠标
|
||||
frame.page().mouse().up();
|
||||
// 瞄准终点后的生理停顿
|
||||
Thread.sleep(30 + random.nextInt(50));
|
||||
|
||||
log.info("【{}-处理滑块】滑动执行完成,等待验证结果...", goofishId);
|
||||
// 5. 释放鼠标(在终点附近的最后一次修正位置释放)
|
||||
BrowserTrajectoryUtils.TrajectoryPoint lastPoint = trajectory.get(totalPoints - 1);
|
||||
double finalX = startX + lastPoint.x;
|
||||
double finalY = startY + lastPoint.y;
|
||||
|
||||
JsonObject upParams = new JsonObject();
|
||||
upParams.addProperty("type", "mouseReleased");
|
||||
upParams.addProperty("button", "left");
|
||||
upParams.addProperty("clickCount", 1);
|
||||
upParams.addProperty("x", finalX);
|
||||
upParams.addProperty("y", finalY);
|
||||
cdpSession.send("Input.dispatchMouseEvent", upParams);
|
||||
|
||||
log.info("【{}-处理滑块】CDP 高仿交互已全量下发,Master 等待佳音吧! (๑•̀ㅂ•́)و✧", goofishId);
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("【{}-处理滑块】执行滑动时出错: {}", goofishId, e.getMessage(), e);
|
||||
log.error("【{}-处理滑块】CDP 执行滑动失败(可能是 JsonObject 序列化或协议异常): {}", goofishId, e.getMessage(), e);
|
||||
return false;
|
||||
} finally {
|
||||
if (cdpSession != null) {
|
||||
cdpSession.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
@ -15,6 +16,7 @@ import top.biwin.xianyu.core.repository.GoofishAccountRepository;
|
||||
import top.biwin.xianyu.goofish.service.GoofishApiService;
|
||||
import top.biwin.xianyu.goofish.service.GoofishPwdLoginService;
|
||||
import top.biwin.xianyu.goofish.service.QrLoginService;
|
||||
import top.biwin.xinayu.common.dto.request.AccountUpdateRequest;
|
||||
import top.biwin.xinayu.common.dto.request.GoofishAddCookieRequest;
|
||||
import top.biwin.xinayu.common.dto.request.GoofishPwdLoginRequest;
|
||||
import top.biwin.xinayu.common.dto.response.BaseResponse;
|
||||
@ -153,4 +155,51 @@ public class GoofishAccountController {
|
||||
}
|
||||
goofishAccountRepository.delete(entity);
|
||||
}
|
||||
|
||||
@PutMapping("/cookies/{id}/remark")
|
||||
public ResponseEntity<GoofishAccountResponse> updateAccountRemark(@PathVariable("id") String goofishId, @RequestBody AccountUpdateRequest request) {
|
||||
GoofishAccountEntity account = goofishAccountRepository.findById(goofishId).orElseThrow(() -> new IllegalStateException("账号不存在"));
|
||||
if (!CurrentUserUtil.isSuperAdmin()) {
|
||||
if (!Objects.equals(account.getUserId(), CurrentUserUtil.getCurrentUserId())) {
|
||||
log.warn("该闲鱼账号不归属当前登录用户!");
|
||||
}
|
||||
}
|
||||
account.setRemark(request.getRemark());
|
||||
goofishAccountRepository.save(account);
|
||||
return ResponseEntity.ok(GoofishAccountResponse.builder()
|
||||
.id(account.getId())
|
||||
.cookie(account.getCookie())
|
||||
.enabled(account.getEnabled())
|
||||
.autoConfirm(account.getAutoConfirm())
|
||||
.remark(account.getRemark())
|
||||
.pauseDuration(account.getPauseDuration())
|
||||
.username(account.getUsername())
|
||||
.loginPassword(account.getPassword())
|
||||
.showBrowser(account.getShowBrowser() == 1)
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
@PutMapping("/cookies/{id}/status")
|
||||
public ResponseEntity<GoofishAccountResponse> updateAccountStatus(@PathVariable("id") String goofishId, @RequestBody AccountUpdateRequest request) {
|
||||
GoofishAccountEntity account = goofishAccountRepository.findById(goofishId).orElseThrow(() -> new IllegalStateException("账号不存在"));
|
||||
if (!CurrentUserUtil.isSuperAdmin()) {
|
||||
if (!Objects.equals(account.getUserId(), CurrentUserUtil.getCurrentUserId())) {
|
||||
log.warn("该闲鱼账号不归属当前登录用户!");
|
||||
}
|
||||
}
|
||||
account.setEnabled(request.getEnabled());
|
||||
goofishAccountRepository.save(account);
|
||||
return ResponseEntity.ok(GoofishAccountResponse.builder()
|
||||
.id(account.getId())
|
||||
.cookie(account.getCookie())
|
||||
.enabled(account.getEnabled())
|
||||
.autoConfirm(account.getAutoConfirm())
|
||||
.remark(account.getRemark())
|
||||
.pauseDuration(account.getPauseDuration())
|
||||
.username(account.getUsername())
|
||||
.loginPassword(account.getPassword())
|
||||
.showBrowser(account.getShowBrowser() == 1)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ 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.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
@ -11,16 +12,20 @@ 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;
|
||||
import top.biwin.xianyu.core.entity.DefaultReplyEntity;
|
||||
import top.biwin.xianyu.core.entity.GoofishAccountEntity;
|
||||
import top.biwin.xianyu.core.entity.KeywordEntity;
|
||||
import top.biwin.xianyu.core.repository.AiReplySettingRepository;
|
||||
import top.biwin.xianyu.core.repository.DefaultReplyRepository;
|
||||
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.DefaultReplyResponse;
|
||||
import top.biwin.xinayu.common.dto.response.KeywordResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -39,6 +44,8 @@ public class KeywordController {
|
||||
private AiReplySettingRepository aiReplySettingRepository;
|
||||
@Autowired
|
||||
private KeywordRepository keywordRepository;
|
||||
@Autowired
|
||||
private DefaultReplyRepository defaultReplyRepository;
|
||||
|
||||
|
||||
@GetMapping("/ai-reply-settings")
|
||||
@ -52,19 +59,19 @@ 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));
|
||||
@GetMapping("/ai-reply-settings/{goofishId}")
|
||||
public ResponseEntity<AiReplySettingEntity> getAiSetting(@PathVariable String goofishId) {
|
||||
return ResponseEntity.ok(aiReplySettingRepository.findById(goofishId).orElse(null));
|
||||
}
|
||||
|
||||
@PutMapping("/ai-reply-settings/{accountId}")
|
||||
public ResponseEntity<AiReplySettingEntity> upsertAiSetting(@PathVariable String accountId, @RequestBody AiSettingRequest request) {
|
||||
@PutMapping("/ai-reply-settings/{goofishId}")
|
||||
public ResponseEntity<AiReplySettingEntity> upsertAiSetting(@PathVariable String goofishId, @RequestBody AiSettingRequest request) {
|
||||
// Upsert 逻辑:存在则更新,不存在则创建
|
||||
AiReplySettingEntity entity = aiReplySettingRepository.findById(accountId)
|
||||
AiReplySettingEntity entity = aiReplySettingRepository.findById(goofishId)
|
||||
.orElseGet(() -> {
|
||||
// 不存在时创建新实体
|
||||
AiReplySettingEntity newEntity = new AiReplySettingEntity();
|
||||
newEntity.setGoofishId(accountId);
|
||||
newEntity.setGoofishId(goofishId);
|
||||
return newEntity;
|
||||
});
|
||||
// 忽略 null 值,防止前端未传的字段覆盖已有值或默认值
|
||||
@ -72,11 +79,11 @@ public class KeywordController {
|
||||
return ResponseEntity.ok(aiReplySettingRepository.save(entity));
|
||||
}
|
||||
|
||||
@GetMapping("/keywords-with-item-id/{gid}")
|
||||
public ResponseEntity<List<KeywordResponse>> getKeywordsWithItemId(@PathVariable Long gid) {
|
||||
@GetMapping("/keywords-with-item-id/{goofishId}")
|
||||
public ResponseEntity<List<KeywordResponse>> getKeywordsWithItemId(@PathVariable Long goofishId) {
|
||||
|
||||
// 获取关键词列表
|
||||
List<KeywordEntity> keywordEntities = keywordRepository.findByGoofishId(gid);
|
||||
List<KeywordEntity> keywordEntities = keywordRepository.findByGoofishId(goofishId);
|
||||
|
||||
// 转换为前端需要的格式(与 Python 实现一致)
|
||||
return ResponseEntity.ok(keywordEntities.stream()
|
||||
@ -89,4 +96,38 @@ public class KeywordController {
|
||||
k.getImageUrl()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@GetMapping("/default-reply/{goofishId}")
|
||||
public ResponseEntity<DefaultReplyResponse> getDefaultReply(@PathVariable String goofishId) {
|
||||
DefaultReplyEntity defaultReply = defaultReplyRepository.findById(goofishId).orElse(null);
|
||||
DefaultReplyResponse response = DefaultReplyResponse.builder()
|
||||
.success(true)
|
||||
.enabled(false)
|
||||
.replyContent("")
|
||||
.replyOnce(false)
|
||||
.replyImageUrl("")
|
||||
.build();
|
||||
if (Objects.isNull(defaultReply)) {
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
response.setEnabled(defaultReply.getEnabled());
|
||||
response.setReplyContent(StringUtils.hasText(defaultReply.getReplyContent()) ? defaultReply.getReplyContent() : "");
|
||||
response.setReplyOnce(defaultReply.getReplyOnce());
|
||||
response.setReplyImageUrl(StringUtils.hasText(defaultReply.getReplyImageUrl()) ? defaultReply.getReplyImageUrl() : "");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@PutMapping("/default-reply/{goofishId}")
|
||||
public ResponseEntity<DefaultReplyResponse> updateDefaultReply(@PathVariable String goofishId, @RequestBody DefaultReplyEntity request) {
|
||||
request.setGoofishId(goofishId);
|
||||
DefaultReplyEntity saved = defaultReplyRepository.save(request);
|
||||
return ResponseEntity.ok(DefaultReplyResponse.builder()
|
||||
.success(true)
|
||||
.enabled(saved.getEnabled())
|
||||
.replyContent(StringUtils.hasText(saved.getReplyContent()) ? saved.getReplyContent() : "")
|
||||
.replyOnce(saved.getReplyOnce())
|
||||
.replyImageUrl(StringUtils.hasText(saved.getReplyImageUrl()) ? saved.getReplyImageUrl() : "")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
app:
|
||||
ddl-auto: create # valid values: none, validate, update, create, create-drop
|
||||
ddl-auto: update # valid values: none, validate, update, create, create-drop
|
||||
# 应用验证码配置
|
||||
verification:
|
||||
code-length: 6 # 验证码长度(6位数字)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user