|
@@ -0,0 +1,439 @@
|
|
|
|
+/*
|
|
|
|
+package cn.sikey.selenium.api;
|
|
|
|
+
|
|
|
|
+import cn.sikey.framework.common.exception.ServiceException;
|
|
|
|
+import cn.sikey.framework.common.pojo.CommonResult;
|
|
|
|
+import cn.sikey.selenium.api.selenium.SmsApi;
|
|
|
|
+import cn.sikey.selenium.api.selenium.dto.AuthRespVO;
|
|
|
|
+import cn.sikey.selenium.api.selenium.dto.TriggerSmsReqDTO;
|
|
|
|
+import cn.sikey.selenium.api.selenium.dto.VerifyCodeReqDTO;
|
|
|
|
+import cn.sikey.selenium.util.AppIdGeneratorUtil;
|
|
|
|
+import cn.sikey.selenium.util.PlaywrightContextManagerUtil;
|
|
|
|
+import cn.sikey.selenium.util.PlaywrightContextManagerUtil.PlaywrightSession;
|
|
|
|
+import com.microsoft.playwright.*;
|
|
|
|
+import com.microsoft.playwright.options.WaitUntilState;
|
|
|
|
+import io.netty.handler.timeout.TimeoutException;
|
|
|
|
+import jakarta.annotation.Resource;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.apache.http.HttpStatus;
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
+import org.springframework.validation.annotation.Validated;
|
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
|
+
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
+import java.time.Duration;
|
|
|
|
+import java.util.Objects;
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
+
|
|
|
|
+*/
|
|
|
|
+/**
|
|
|
|
+ * @Author: nelson
|
|
|
|
+ * @Date: 2025/6/26
|
|
|
|
+ * @Description: 验证码
|
|
|
|
+ *//*
|
|
|
|
+
|
|
|
|
+@Slf4j
|
|
|
|
+@RestController // 提供 RESTful API 接口,给 Feign 调用
|
|
|
|
+@Validated
|
|
|
|
+public class SmsNewServiceImpl implements SmsApi {
|
|
|
|
+
|
|
|
|
+ @Value("${selenium.remote.url}")
|
|
|
|
+ private String url;
|
|
|
|
+
|
|
|
|
+ @Value("${selenium.remote.loginUrl}")
|
|
|
|
+ private String loginUrl;
|
|
|
|
+
|
|
|
|
+ @Value("${selenium.remote.redirectUrl}")
|
|
|
|
+ private String redirectUrl;
|
|
|
|
+
|
|
|
|
+ public static final String ACCESS_TOKEN1 = "/app-api/mcdisk/wristwatch/authorize/accessToken1";
|
|
|
|
+
|
|
|
|
+ @Value("${selenium.remote.appid}")
|
|
|
|
+ private String appid;
|
|
|
|
+
|
|
|
|
+ @Value("${selenium.remote.appkey}")
|
|
|
|
+ private String appkey;
|
|
|
|
+
|
|
|
|
+ public static final String APP_TITLE = "移动云盘";
|
|
|
|
+
|
|
|
|
+ public static final int GET_VERIFICATION_CODE_AGAIN = 10001;
|
|
|
|
+
|
|
|
|
+ public static final int UUID_EXPIRES_MINUTE = 15;
|
|
|
|
+
|
|
|
|
+ public static final String SMS_CODE_KEY = "sms:code:phone:";
|
|
|
|
+
|
|
|
|
+ public static final String SMS_SESSION_ID_KEY = "sms:session:id:";
|
|
|
|
+
|
|
|
|
+ @Resource
|
|
|
|
+ private RedisTemplate<String, Object> redisTemplate;
|
|
|
|
+
|
|
|
|
+ // 超时时间(秒)
|
|
|
|
+ private static final long SMS_TIMEOUT = 30;
|
|
|
|
+
|
|
|
|
+ // 最大重试次数
|
|
|
|
+ private static final int MAX_RETRY = 3;
|
|
|
|
+
|
|
|
|
+ */
|
|
|
|
+/**
|
|
|
|
+ * 发送验证码
|
|
|
|
+ *
|
|
|
|
+ * @param request 请求
|
|
|
|
+ * @return
|
|
|
|
+ *//*
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public CommonResult<Void> triggerSmsVerification(TriggerSmsReqDTO request) {
|
|
|
|
+ String uuid = AppIdGeneratorUtil.generateUuid(appid);
|
|
|
|
+ PlaywrightSession session;
|
|
|
|
+
|
|
|
|
+ String phoneNumber = request.getPhoneNumber();
|
|
|
|
+ String deviceId = request.getTicket();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 创建 Playwright 会话(使用 Chromium 浏览器)
|
|
|
|
+ String sessionId = PlaywrightContextManagerUtil.createSession(url);
|
|
|
|
+ session = PlaywrightContextManagerUtil.getSession(sessionId);
|
|
|
|
+ Page page = session.getPage();
|
|
|
|
+
|
|
|
|
+ // 设置导航超时和操作超时
|
|
|
|
+ page.setDefaultNavigationTimeout(TimeUnit.SECONDS.toMillis(SMS_TIMEOUT));
|
|
|
|
+ page.setDefaultTimeout(TimeUnit.SECONDS.toMillis(SMS_TIMEOUT));
|
|
|
|
+
|
|
|
|
+ // 构建登录URL
|
|
|
|
+ String encodedUrl = URLEncoder.encode(redirectUrl + ACCESS_TOKEN1 + "?uuid=" + uuid + "&ticket=" + deviceId, StandardCharsets.UTF_8);
|
|
|
|
+ String toLoginUrl = String.format("%s?pageType=3&appId=%s&appKey=%s&deviceId=%s&appTitle=%s&uuid=%s&redirectUrl=%s", loginUrl, appid, appkey, deviceId, APP_TITLE, uuid, encodedUrl);
|
|
|
|
+
|
|
|
|
+ log.info("[发送验证码]获取移动云盘地址:{}", toLoginUrl);
|
|
|
|
+
|
|
|
|
+ // 导航到登录页,等待网络空闲
|
|
|
|
+ Response response = page.navigate(toLoginUrl, new Page.NavigateOptions().setWaitUntil(WaitUntilState.NETWORKIDLE));
|
|
|
|
+
|
|
|
|
+ if (!response.ok()) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_GATEWAY, "页面加载失败,状态码: " + response.status());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 确保页面包含关键元素
|
|
|
|
+ page.waitForSelector("//input[@type='number' and @maxlength='11']", new Page.WaitForSelectorOptions().setTimeout(SMS_TIMEOUT * 1000));
|
|
|
|
+
|
|
|
|
+ // 输入手机号 - 使用精确选择器
|
|
|
|
+ Locator phoneInput = page.locator("xpath=//input[@type='number' and @maxlength='11']");
|
|
|
|
+ phoneInput.fill(phoneNumber);
|
|
|
|
+
|
|
|
|
+ // 获取验证码按钮 - 使用文本定位
|
|
|
|
+ Locator codeBtn = page.locator("button:has-text('获取验证码')");
|
|
|
|
+
|
|
|
|
+ // 重试机制处理可能的点击失败
|
|
|
|
+ boolean clickSuccess = false;
|
|
|
|
+ for (int i = 0; i < MAX_RETRY && !clickSuccess; i++) {
|
|
|
|
+ try {
|
|
|
|
+ // 确保按钮可见
|
|
|
|
+ codeBtn.scrollIntoViewIfNeeded();
|
|
|
|
+
|
|
|
|
+ // 使用 Playwright 的点击(带自动等待)
|
|
|
|
+ codeBtn.click(new Locator.ClickOptions().setTimeout(5000) // 5秒超时
|
|
|
|
+ .setForce(true)); // 强制点击
|
|
|
|
+
|
|
|
|
+ clickSuccess = true;
|
|
|
|
+ log.info("[发送验证码]第{}次点击成功", i + 1);
|
|
|
|
+ } catch (PlaywrightException e) {
|
|
|
|
+ log.warn("[发送验证码]点击失败,重试中... 原因: {}", e.getMessage());
|
|
|
|
+
|
|
|
|
+ // 等待可能的状态更新
|
|
|
|
+ page.waitForTimeout(1000); // 1秒等待
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!clickSuccess) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "无法点击验证码按钮");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查是否出现成功提示
|
|
|
|
+ Locator successTip = page.locator("text=验证码已发送");
|
|
|
|
+ if (successTip.isVisible(new Locator.IsVisibleOptions().setTimeout(3000))) {
|
|
|
|
+ log.info("[发送验证码]短信验证码已发送,手机号:{}", phoneNumber);
|
|
|
|
+ } else {
|
|
|
|
+ // 检查错误提示
|
|
|
|
+ Locator errorTip = page.locator("div.el-message--error, div.error-message");
|
|
|
|
+ if (errorTip.isVisible()) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "发送失败: " + errorTip.textContent());
|
|
|
|
+ }
|
|
|
|
+ log.warn("[发送验证码]未检测到成功提示,但可能已发送");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 存储到Redis
|
|
|
|
+ redisTemplate.opsForValue().set(SMS_CODE_KEY + phoneNumber, uuid, Duration.ofMinutes(UUID_EXPIRES_MINUTE));
|
|
|
|
+
|
|
|
|
+ redisTemplate.opsForValue().set(SMS_SESSION_ID_KEY + phoneNumber, sessionId, Duration.ofMinutes(UUID_EXPIRES_MINUTE));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "触发短信验证码失败: " + e.getMessage());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return CommonResult.success();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ */
|
|
|
|
+/**
|
|
|
|
+ * 验证码登录
|
|
|
|
+ *
|
|
|
|
+ * @param request 校验验证码登录
|
|
|
|
+ * @return
|
|
|
|
+ *//*
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public CommonResult<AuthRespVO> verifyCodeAndLogin(VerifyCodeReqDTO request) {
|
|
|
|
+ String phoneNumber = request.getPhoneNumber();
|
|
|
|
+ Object uuid = redisTemplate.opsForValue().get(SMS_CODE_KEY + phoneNumber);
|
|
|
|
+ if (Objects.isNull(uuid)) {
|
|
|
|
+ throw new ServiceException(GET_VERIFICATION_CODE_AGAIN, "请重新获取验证码");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Object sessionId = redisTemplate.opsForValue().get(SMS_SESSION_ID_KEY + phoneNumber);
|
|
|
|
+ if (Objects.isNull(sessionId)) {
|
|
|
|
+ throw new ServiceException(GET_VERIFICATION_CODE_AGAIN, "会话已过期,请重新获取验证码");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String deviceId = request.getTicket();
|
|
|
|
+ String verificationCode = request.getVerificationCode();
|
|
|
|
+ String sId = String.valueOf(sessionId);
|
|
|
|
+ PlaywrightSession session;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 获取Playwright会话
|
|
|
|
+ session = PlaywrightContextManagerUtil.getSession(sId);
|
|
|
|
+ Page page = session.getPage();
|
|
|
|
+
|
|
|
|
+ // 设置超时
|
|
|
|
+ page.setDefaultTimeout(TimeUnit.SECONDS.toMillis(SMS_TIMEOUT));
|
|
|
|
+
|
|
|
|
+ // 构建登录URL
|
|
|
|
+ String encodedUrl = redirectUrl + ACCESS_TOKEN1;
|
|
|
|
+ String toLoginUrl = String.format(
|
|
|
|
+ "%s?pageType=3&appId=%s&appKey=%s&deviceId=%s&appTitle=%s&uuid=%s&redirectUrl=%s",
|
|
|
|
+ loginUrl, appid, appkey, deviceId, APP_TITLE, uuid, encodedUrl
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ log.info("[校验验证码登录]获取移动云盘地址:{}", toLoginUrl);
|
|
|
|
+
|
|
|
|
+ // 如果当前页面不是登录页,则导航到登录页
|
|
|
|
+ if (!page.url().contains("middlePage")) {
|
|
|
|
+ page.navigate(toLoginUrl, new Page.NavigateOptions()
|
|
|
|
+ .setWaitUntil(WaitUntilState.NETWORKIDLE));
|
|
|
|
+
|
|
|
|
+ // 等待页面关键元素
|
|
|
|
+ page.waitForSelector("//input[@type='number' and @maxlength='11']",
|
|
|
|
+ new Page.WaitForSelectorOptions().setTimeout(5000));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 输入验证码
|
|
|
|
+ Locator codeInput = page.locator("xpath=//input[@placeholder='输入验证码' and @maxlength='6']");
|
|
|
|
+ if (!codeInput.isVisible()) {
|
|
|
|
+ log.warn("验证码输入框不可见,尝试滚动到视图中");
|
|
|
|
+ codeInput.scrollIntoViewIfNeeded();
|
|
|
|
+ }
|
|
|
|
+ codeInput.fill(verificationCode);
|
|
|
|
+
|
|
|
|
+ // 勾选协议
|
|
|
|
+ Locator agreementLabel = page.locator("xpath=//div[contains(@class,'login_agreementGroup')]//label[contains(@class,'el-checkbox')]");
|
|
|
|
+
|
|
|
|
+ // 确保协议复选框可见
|
|
|
|
+ if (!agreementLabel.isVisible()) {
|
|
|
|
+ agreementLabel.scrollIntoViewIfNeeded();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查是否已勾选
|
|
|
|
+ Locator agreementCheckbox = page.locator("xpath=//div[contains(@class,'login_agreementGroup')]//input[@type='checkbox']");
|
|
|
|
+ if (!"true".equals(agreementCheckbox.getAttribute("aria-checked"))) {
|
|
|
|
+ log.info("尝试勾选协议复选框");
|
|
|
|
+
|
|
|
|
+ // 重试勾选协议
|
|
|
|
+ boolean agreementChecked = false;
|
|
|
|
+ for (int i = 0; i < MAX_RETRY && !agreementChecked; i++) {
|
|
|
|
+ try {
|
|
|
|
+ agreementLabel.click(new Locator.ClickOptions()
|
|
|
|
+ .setForce(true)
|
|
|
|
+ .setTimeout(3000));
|
|
|
|
+
|
|
|
|
+ // 验证是否勾选成功
|
|
|
|
+ if ("true".equals(agreementCheckbox.getAttribute("aria-checked"))) {
|
|
|
|
+ agreementChecked = true;
|
|
|
|
+ log.info("协议勾选成功");
|
|
|
|
+ } else {
|
|
|
|
+ log.warn("协议未勾选,尝试JavaScript点击");
|
|
|
|
+ page.evaluate("document.querySelector('div.login_agreementGroup input[type=checkbox]').click()");
|
|
|
|
+ }
|
|
|
|
+ } catch (PlaywrightException e) {
|
|
|
|
+ log.warn("勾选协议失败,重试中... ({}/3)", i + 1);
|
|
|
|
+ page.waitForTimeout(1000); // 等待1秒
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!agreementChecked) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
|
|
|
+ "无法勾选协议复选框");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 3. 点击登录按钮
|
|
|
|
+ Locator loginButton = page.locator("xpath=//button[contains(@class, 'login_btn') " +
|
|
|
|
+ "and not(contains(@class, 'one_key_login_btn')) " +
|
|
|
|
+ "and .//span[normalize-space()='登录'] " +
|
|
|
|
+ "and not(@disabled)]");
|
|
|
|
+
|
|
|
|
+ // 确保按钮可见
|
|
|
|
+ if (!loginButton.isVisible()) {
|
|
|
|
+ loginButton.scrollIntoViewIfNeeded();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 重试点击登录按钮
|
|
|
|
+ boolean loginClicked = false;
|
|
|
|
+ for (int i = 0; i < MAX_RETRY && !loginClicked; i++) {
|
|
|
|
+ try {
|
|
|
|
+ loginButton.click(new Locator.ClickOptions()
|
|
|
|
+ .setForce(true)
|
|
|
|
+ .setTimeout(5000));
|
|
|
|
+ loginClicked = true;
|
|
|
|
+ log.info("登录按钮点击成功");
|
|
|
|
+ } catch (PlaywrightException e) {
|
|
|
|
+ log.warn("登录按钮点击失败,重试中... ({}/3)", i + 1);
|
|
|
|
+ page.waitForTimeout(1000); // 等待1秒
|
|
|
|
+
|
|
|
|
+ // 检查按钮是否被禁用
|
|
|
|
+ if ("true".equals(loginButton.getAttribute("disabled"))) {
|
|
|
|
+ log.warn("登录按钮被禁用,检查协议是否勾选");
|
|
|
|
+ if (!"true".equals(agreementCheckbox.getAttribute("aria-checked"))) {
|
|
|
|
+ agreementLabel.click(new Locator.ClickOptions().setForce(true));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!loginClicked) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
|
|
|
+ "无法点击登录按钮");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 验证登录成功
|
|
|
|
+ verifyLoginSuccess(page);
|
|
|
|
+
|
|
|
|
+ log.info("[校验验证码登录]登录成功,手机号:{},验证码:{}", phoneNumber, verificationCode);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("[校验验证码登录]异常:{0}", e);
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "触发校验验证码登录失败");
|
|
|
|
+ } finally {
|
|
|
|
+ // 清理会话
|
|
|
|
+ if (sessionId != null) {
|
|
|
|
+ PlaywrightContextManagerUtil.destroySession(sId);
|
|
|
|
+
|
|
|
|
+ // 清理Redis中的会话信息
|
|
|
|
+ redisTemplate.delete(SMS_CODE_KEY + phoneNumber);
|
|
|
|
+ redisTemplate.delete(SMS_SESSION_ID_KEY + phoneNumber);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 验证登录成功
|
|
|
|
+ private void verifyLoginSuccess(Page page) {
|
|
|
|
+ try {
|
|
|
|
+ // 验证URL变化 - 等待重定向
|
|
|
|
+ page.waitForURL(url ->
|
|
|
|
+ url.contains("/home") ||
|
|
|
|
+ url.contains("/dashboard") ||
|
|
|
|
+ url.contains("/console"),
|
|
|
|
+ new Page.WaitForURLOptions().setTimeout(15000));
|
|
|
|
+
|
|
|
|
+ log.info("[校验验证码登录]登录成功!当前URL:{}", page.url());
|
|
|
|
+
|
|
|
|
+ // 验证用户信息元素
|
|
|
|
+ Locator userInfo = page.locator("xpath=//div[contains(@class, 'user-info') or contains(@class, 'user-name')]");
|
|
|
|
+ if (userInfo.isVisible(new Locator.IsVisibleOptions().setTimeout(5000))) {
|
|
|
|
+ log.info("[校验验证码登录]登录成功!用户名:{}", userInfo.textContent());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查认证Cookie
|
|
|
|
+ BrowserContext context = page.context();
|
|
|
|
+ String authToken = context.cookies().stream()
|
|
|
|
+ .filter(cookie ->
|
|
|
|
+ "CMCC-TOKEN".equals(cookie.name) ||
|
|
|
|
+ "CMCC_SESSION".equals(cookie.name))
|
|
|
|
+ .findFirst()
|
|
|
|
+ .map(cookie -> cookie.value)
|
|
|
|
+ .orElse(null);
|
|
|
|
+
|
|
|
|
+ if (authToken != null) {
|
|
|
|
+ log.info("[校验验证码登录]登录成功!认证Token存在");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查本地存储
|
|
|
|
+ Object localStorageToken = page.evaluate(
|
|
|
|
+ "() => localStorage.getItem('CMCC_AUTH_TOKEN') || " +
|
|
|
|
+ "localStorage.getItem('access_token')");
|
|
|
|
+
|
|
|
|
+ if (localStorageToken != null) {
|
|
|
|
+ log.info("[校验验证码登录]登录成功!本地存储Token存在");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 如果以上验证都失败,尝试检查错误
|
|
|
|
+ checkLoginErrors(page);
|
|
|
|
+
|
|
|
|
+ // 最终验证失败
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
|
|
|
+ "无法确认登录状态,但未检测到错误");
|
|
|
|
+
|
|
|
|
+ } catch (TimeoutException e) {
|
|
|
|
+ // 处理登录超时
|
|
|
|
+ checkLoginErrors(page);
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_REQUEST_TIMEOUT, "登录验证超时");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查登录错误
|
|
|
|
+ private void checkLoginErrors(Page page) {
|
|
|
|
+ // 检查错误消息
|
|
|
|
+ Locator errorTip = page.locator("div.el-message--error, div.error-message");
|
|
|
|
+ if (errorTip.isVisible(new Locator.IsVisibleOptions().setTimeout(3000))) {
|
|
|
|
+ String errorText = errorTip.textContent();
|
|
|
|
+ log.error("[校验验证码登录]登录失败!原因:{}", errorText);
|
|
|
|
+
|
|
|
|
+ if (errorText.contains("验证码") || errorText.contains("验证码错误")) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "验证码错误,请重新输入");
|
|
|
|
+ } else if (errorText.contains("账号") || errorText.contains("用户不存在")) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "账号不存在或密码错误");
|
|
|
|
+ } else if (errorText.contains("协议") || errorText.contains("未同意")) {
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "请同意用户协议");
|
|
|
|
+ }
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "登录失败: " + errorText);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查表单错误
|
|
|
|
+ Locator formErrors = page.locator("div.el-form-item__error");
|
|
|
|
+ if (formErrors.isVisible()) {
|
|
|
|
+ String errorText = formErrors.first().textContent();
|
|
|
|
+ log.error("[校验验证码登录]表单错误:{}", errorText);
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_BAD_REQUEST, "表单错误: " + errorText);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查系统错误提示
|
|
|
|
+ Locator systemErrors = page.locator("text=/状态码|错误码|系统异常/");
|
|
|
|
+ if (systemErrors.isVisible()) {
|
|
|
|
+ String errorText = systemErrors.textContent();
|
|
|
|
+ log.error("[校验验证码登录]系统错误:{}", errorText);
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "系统错误: " + errorText);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查页面内容中的错误关键字
|
|
|
|
+ String pageContent = page.content();
|
|
|
|
+ if (pageContent.contains("错误") || pageContent.contains("exception")) {
|
|
|
|
+ log.error("[校验验证码登录]页面包含错误信息关键字");
|
|
|
|
+ throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "系统异常,请稍后重试");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+*/
|