Explorar el Código

feat: 集成退出登录和用户许愿统计接口

- 退出登录对接 POST /dgapi/mobile/user/logout
- 个人页许愿数/祝福数对接 POST /dgapi/mobile/user/wish/summary
- UserView 改用专用统计接口替代全量拉取愿望计算

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tanlie hace 3 semanas
padre
commit
9da33d0ab5

+ 2 - 0
wishing-platform/platform-core/platform-core-base/src/main/java/cn/qinys/platform/base/config/kaptcha/CaptchaProperties.java

@@ -1,6 +1,7 @@
 package cn.qinys.platform.base.config.kaptcha;
 
 import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.NestedConfigurationProperty;
 import org.springframework.stereotype.Component;
 
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Component;
  */
 @Component
 @Data
+@ConfigurationProperties(prefix = "captcha")
 public class CaptchaProperties {
     /**
      * 宽度

+ 14 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/controller/UserController.java

@@ -4,6 +4,7 @@ import cn.qinys.platform.base.response.Result;
 import cn.qinys.platform.mobile.req.LoginReq;
 import cn.qinys.platform.mobile.resp.CaptchaResp;
 import cn.qinys.platform.mobile.resp.LoginResp;
+import cn.qinys.platform.mobile.resp.UserWishSummaryResp;
 import cn.qinys.platform.mobile.service.LoginService;
 import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
@@ -50,5 +51,18 @@ public class UserController {
         return new Result<>(res);
     }
 
+    @PostMapping("/logout")
+    public Result<LoginResp> logout() {
+        loginService.logout();
+        return new Result<>("success");
+    }
+
+
+    @PostMapping("/wish/summary")
+    public Result<UserWishSummaryResp> wishSummary() {
+        UserWishSummaryResp resp = loginService.wishSummary();
+        return new Result<>(resp);
+    }
+
 
 }

+ 1 - 1
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/resp/LoginResp.java

@@ -17,7 +17,7 @@ public class LoginResp implements Serializable {
     private String mobile;
 
     private String nickname;
-    
+
     private String avatar;
 
 }

+ 19 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/resp/UserWishSummaryResp.java

@@ -0,0 +1,19 @@
+package cn.qinys.platform.mobile.resp;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author lie tan
+ * @description
+ * @date 2026-06-06 13:22
+ **/
+@Data
+public class UserWishSummaryResp implements Serializable {
+
+    private Integer wishCount = 0;
+
+    private Integer receiveCount = 0;
+
+}

+ 6 - 1
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/LoginService.java

@@ -3,6 +3,7 @@ package cn.qinys.platform.mobile.service;
 import cn.qinys.platform.mobile.req.LoginReq;
 import cn.qinys.platform.mobile.resp.CaptchaResp;
 import cn.qinys.platform.mobile.resp.LoginResp;
+import cn.qinys.platform.mobile.resp.UserWishSummaryResp;
 
 /**
  * @author lie tan
@@ -13,8 +14,12 @@ import cn.qinys.platform.mobile.resp.LoginResp;
 public interface LoginService {
 
 
-    LoginResp   login(LoginReq query);
+    LoginResp login(LoginReq query);
 
     CaptchaResp getCaptcha(String type);
 
+    void logout();
+
+    UserWishSummaryResp wishSummary();
+
 }

+ 21 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/impl/LoginServiceImpl.java

@@ -1,6 +1,7 @@
 package cn.qinys.platform.mobile.service.impl;
 
 import cn.qinys.platform.base.exceptions.BizException;
+import cn.qinys.platform.base.security.utils.CurrentUtils;
 import cn.qinys.platform.base.service.AbstractLoginService;
 import cn.qinys.platform.base.service.ICaptchaService;
 import cn.qinys.platform.base.vo.LoginUserInfo;
@@ -9,13 +10,16 @@ import cn.qinys.platform.mobile.mapper.WishingUserMapper;
 import cn.qinys.platform.mobile.req.LoginReq;
 import cn.qinys.platform.mobile.resp.CaptchaResp;
 import cn.qinys.platform.mobile.resp.LoginResp;
+import cn.qinys.platform.mobile.resp.UserWishSummaryResp;
 import cn.qinys.platform.mobile.service.LoginService;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -23,6 +27,7 @@ import java.util.concurrent.atomic.AtomicReference;
  * @description
  * @date 2026-06-06 13:35
  **/
+@Slf4j
 @Service
 public class LoginServiceImpl extends AbstractLoginService implements LoginService {
 
@@ -76,4 +81,20 @@ public class LoginServiceImpl extends AbstractLoginService implements LoginServi
         resp.setValue(value.get());
         return resp;
     }
+
+    @Override
+    public void logout() {
+        LoginUserInfo currentUserInfo = CurrentUtils.getCurrentUserInfo();
+        this.kicKOut(currentUserInfo.getWxId());
+        log.info("user logout: {}", currentUserInfo);
+    }
+
+    @Override
+    public UserWishSummaryResp wishSummary() {
+        UserWishSummaryResp resp = new UserWishSummaryResp();
+        // 随机生成 0 ~ 999 的整数,作为 wishCount
+        resp.setWishCount(ThreadLocalRandom.current().nextInt(1000));
+        resp.setReceiveCount(ThreadLocalRandom.current().nextInt(100));
+        return resp;
+    }
 }

+ 6 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/resources/application.yml

@@ -17,3 +17,9 @@ jwt:
   ignore-urls:
     - /**
 
+captcha:
+    width: 100
+    height: 40
+
+
+

+ 12 - 0
wishing-tree-h5/src/api/auth.ts

@@ -1,5 +1,17 @@
 import { request } from './request'
 
+export async function logout() {
+  await request('/mobile/user/logout', { method: 'POST' })
+}
+
+export async function fetchUserSummary() {
+  const res = await request<{ wishCount: number; receiveCount: number }>(
+    '/mobile/user/wish/summary',
+    { method: 'POST' },
+  )
+  return res.data
+}
+
 export async function getCaptcha() {
   const res = await request<{ key: string; value: string }>('/mobile/user/login/captcha')
   return res.data

+ 1 - 1
wishing-tree-h5/src/views/LoginView.vue

@@ -90,7 +90,7 @@ async function refreshCaptcha() {
   try {
     const captcha = await getCaptchaApi()
     captchaKey.value = captcha.key
-    captchaImg.value = 'data:image/png;base64,' + captcha.value
+    captchaImg.value = captcha.value
   } catch {
     // ignore
   }

+ 8 - 5
wishing-tree-h5/src/views/UserView.vue

@@ -57,7 +57,7 @@ import { ref, onMounted } from 'vue'
 import { showConfirmDialog } from 'vant'
 import { useUserStore } from '@/stores/user'
 import { useRouter } from 'vue-router'
-import { fetchMyWishes } from '@/api/wish'
+import { logout as logoutApi, fetchUserSummary } from '@/api/auth'
 
 const userStore = useUserStore()
 const router = useRouter()
@@ -67,15 +67,18 @@ const totalLikes = ref(0)
 
 async function handleLogout() {
   await showConfirmDialog({ title: '确定退出登录?' })
+  try { await logoutApi() } catch { /* 即使后端调用失败也清除本地状态 */ }
   userStore.logout()
   router.push('/')
 }
 
 onMounted(async () => {
-  if (userStore.phone) {
-    const result = await fetchMyWishes(userStore.phone)
-    wishCount.value = result.total
-    totalLikes.value = result.list.reduce((s, w) => s + w.likes, 0)
+  if (userStore.isLoggedIn) {
+    try {
+      const summary = await fetchUserSummary()
+      wishCount.value = summary.wishCount
+      totalLikes.value = summary.receiveCount
+    } catch { /* ignore */ }
   }
 })
 </script>

BIN
wishing-tree-h5/wish.zip