From 62f8d49c054823813dd2f5fa7dd1aee12b7cd84c Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期三, 08 四月 2026 18:27:34 +0800
Subject: [PATCH] feat:App首页-Banner
---
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/statistics/controller/AppUserEntryLogController.java | 14 +
traditionalApp/pages/home/home.vue | 228 ++++++++++++++++++------
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/controller/AppHomeBannerController.java | 37 ++++
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/vo/AppHomeBannerVO.java | 24 ++
traditionalApp/utils/request.js | 71 +++++--
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppWechatAuthClient.java | 3
traditionalApp/pages/home/service.js | 19 +
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppAuthSessionService.java | 22 ++
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/user/controller/AppUserFeedbackController.java | 11
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/config/SaTokenWebConfig.java | 17 -
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/service/AppHomeBannerService.java | 59 ++++++
11 files changed, 386 insertions(+), 119 deletions(-)
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppAuthSessionService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppAuthSessionService.java
index 14d59f6..b2d84c6 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppAuthSessionService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppAuthSessionService.java
@@ -18,6 +18,28 @@
}
/**
+ * 判断当前请求是否存在 APP 登录态。
+ */
+ public boolean isLogin() {
+ return StpAppUserUtil.isLogin();
+ }
+
+ /**
+ * 获取当前 APP 登录用户 ID。
+ */
+ public Long getLoginUserId() {
+ return StpAppUserUtil.getLoginIdAsLong();
+ }
+
+ /**
+ * 获取当前 APP 登录用户 ID,不存在时抛出未登录异常。
+ */
+ public Long requireLoginUserId() {
+ StpAppUserUtil.checkLogin();
+ return StpAppUserUtil.getLoginIdAsLong();
+ }
+
+ /**
* 获取当前 APP 登录态的 token 信息。
*/
public SaTokenInfo getTokenInfo() {
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppWechatAuthClient.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppWechatAuthClient.java
index 84e50e3..c8de56a 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppWechatAuthClient.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/auth/service/AppWechatAuthClient.java
@@ -6,6 +6,7 @@
import com.tcm.training.admin.app.auth.dto.AppWechatLoginRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
@@ -26,12 +27,14 @@
/**
* 使用默认 HTTP 客户端构造微信认证客户端。
*/
+ @Autowired
public AppWechatAuthClient(AppWechatAuthProperties properties, ObjectMapper objectMapper) {
this(properties, objectMapper, new RestTemplate());
}
/**
* 注入微信配置、JSON 解析器与 HTTP 客户端。
+ * 存在多个构造器时,这个扩展构造器仅供测试或内部定制使用,避免 Spring 误判默认注入入口。
*/
AppWechatAuthClient(AppWechatAuthProperties properties,
ObjectMapper objectMapper,
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/controller/AppHomeBannerController.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/controller/AppHomeBannerController.java
new file mode 100644
index 0000000..8209852
--- /dev/null
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/controller/AppHomeBannerController.java
@@ -0,0 +1,37 @@
+package com.tcm.training.admin.app.home.controller;
+
+import com.tcm.training.admin.app.home.service.AppHomeBannerService;
+import com.tcm.training.admin.app.home.vo.AppHomeBannerVO;
+import com.tcm.training.admin.common.ApiResponse;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * APP 首页 banner 接口。
+ */
+@Validated
+@RestController
+@RequestMapping({"/api/app/home", "/api/v1/app/home"})
+public class AppHomeBannerController {
+
+ private final AppHomeBannerService appHomeBannerService;
+
+ /**
+ * 注入 APP 首页 banner 服务。
+ */
+ public AppHomeBannerController(AppHomeBannerService appHomeBannerService) {
+ this.appHomeBannerService = appHomeBannerService;
+ }
+
+ /**
+ * 获取 APP 首页顶部 banner 列表。
+ */
+ @GetMapping("/banners")
+ public ApiResponse<List<AppHomeBannerVO>> listBanners() {
+ return ApiResponse.ok(appHomeBannerService.listEnabledBanners());
+ }
+}
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/service/AppHomeBannerService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/service/AppHomeBannerService.java
new file mode 100644
index 0000000..88b756f
--- /dev/null
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/service/AppHomeBannerService.java
@@ -0,0 +1,59 @@
+package com.tcm.training.admin.app.home.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.tcm.training.admin.app.home.vo.AppHomeBannerVO;
+import com.tcm.training.admin.system.entity.SystemBannerConfig;
+import com.tcm.training.admin.system.mapper.SystemBannerConfigMapper;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * APP 首页 banner 服务。
+ */
+@Service
+public class AppHomeBannerService {
+
+ private final SystemBannerConfigMapper systemBannerConfigMapper;
+
+ /**
+ * 注入 banner 配置查询能力。
+ */
+ public AppHomeBannerService(SystemBannerConfigMapper systemBannerConfigMapper) {
+ this.systemBannerConfigMapper = systemBannerConfigMapper;
+ }
+
+ /**
+ * 查询 APP 首页可展示的 banner 列表。
+ */
+ public List<AppHomeBannerVO> listEnabledBanners() {
+ LocalDateTime now = LocalDateTime.now();
+ List<SystemBannerConfig> records = systemBannerConfigMapper.selectList(new LambdaQueryWrapper<SystemBannerConfig>()
+ .eq(SystemBannerConfig::getDeleted, 0)
+ .eq(SystemBannerConfig::getPublishEnabled, 1)
+ .le(SystemBannerConfig::getStartAt, now)
+ .ge(SystemBannerConfig::getEndAt, now)
+ .orderByDesc(SystemBannerConfig::getId));
+ List<AppHomeBannerVO> result = new ArrayList<AppHomeBannerVO>(records.size());
+ for (SystemBannerConfig record : records) {
+ result.add(toBannerVO(record));
+ }
+ return result;
+ }
+
+ /**
+ * 将后台 banner 配置转换为 APP 首页展示对象。
+ */
+ private AppHomeBannerVO toBannerVO(SystemBannerConfig record) {
+ AppHomeBannerVO vo = new AppHomeBannerVO();
+ vo.setId(record.getId());
+ vo.setImageUrl(record.getBannerImg());
+ vo.setTitle(record.getTitle());
+ vo.setJumpType(record.getJumpType());
+ vo.setTargetId(record.getTargetId());
+ vo.setTargetUrl(record.getTargetUrl());
+ return vo;
+ }
+}
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/vo/AppHomeBannerVO.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/vo/AppHomeBannerVO.java
new file mode 100644
index 0000000..a332a36
--- /dev/null
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/home/vo/AppHomeBannerVO.java
@@ -0,0 +1,24 @@
+package com.tcm.training.admin.app.home.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * APP 首页顶部 banner 响应。
+ */
+@Getter
+@Setter
+public class AppHomeBannerVO {
+
+ private Long id;
+
+ private String imageUrl;
+
+ private String title;
+
+ private String jumpType;
+
+ private Long targetId;
+
+ private String targetUrl;
+}
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/statistics/controller/AppUserEntryLogController.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/statistics/controller/AppUserEntryLogController.java
index e67879d..1b61d6d 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/statistics/controller/AppUserEntryLogController.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/statistics/controller/AppUserEntryLogController.java
@@ -1,6 +1,6 @@
package com.tcm.training.admin.app.statistics.controller;
-import com.tcm.training.admin.app.auth.support.StpAppUserUtil;
+import com.tcm.training.admin.app.auth.service.AppAuthSessionService;
import com.tcm.training.admin.common.ApiResponse;
import com.tcm.training.admin.statistics.service.AppUserEntryLogAppService;
import org.springframework.validation.annotation.Validated;
@@ -17,20 +17,26 @@
public class AppUserEntryLogController {
private final AppUserEntryLogAppService appUserEntryLogAppService;
+ private final AppAuthSessionService appAuthSessionService;
/**
* 注入 APP 用户进入记录服务。
*/
- public AppUserEntryLogController(AppUserEntryLogAppService appUserEntryLogAppService) {
+ public AppUserEntryLogController(AppUserEntryLogAppService appUserEntryLogAppService,
+ AppAuthSessionService appAuthSessionService) {
this.appUserEntryLogAppService = appUserEntryLogAppService;
+ this.appAuthSessionService = appAuthSessionService;
}
/**
- * 记录 APP 用户进入行为。
+ * 记录 APP 用户进入行为,游客访问时静默跳过。
*/
@PostMapping("/user-entry-logs")
public ApiResponse<Void> record() {
- appUserEntryLogAppService.record(StpAppUserUtil.getLoginIdAsLong());
+ if (!appAuthSessionService.isLogin()) {
+ return ApiResponse.ok(null);
+ }
+ appUserEntryLogAppService.record(appAuthSessionService.getLoginUserId());
return ApiResponse.ok(null);
}
}
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/user/controller/AppUserFeedbackController.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/user/controller/AppUserFeedbackController.java
index 49b8929..4ff86f9 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/user/controller/AppUserFeedbackController.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/user/controller/AppUserFeedbackController.java
@@ -1,6 +1,6 @@
package com.tcm.training.admin.app.user.controller;
-import com.tcm.training.admin.app.auth.support.StpAppUserUtil;
+import com.tcm.training.admin.app.auth.service.AppAuthSessionService;
import com.tcm.training.admin.common.ApiResponse;
import com.tcm.training.admin.system.dto.UserFeedbackSubmitRequest;
import com.tcm.training.admin.system.service.UserFeedbackAppService;
@@ -21,20 +21,23 @@
public class AppUserFeedbackController {
private final UserFeedbackAppService userFeedbackAppService;
+ private final AppAuthSessionService appAuthSessionService;
/**
* 注入 APP 用户反馈服务。
*/
- public AppUserFeedbackController(UserFeedbackAppService userFeedbackAppService) {
+ public AppUserFeedbackController(UserFeedbackAppService userFeedbackAppService,
+ AppAuthSessionService appAuthSessionService) {
this.userFeedbackAppService = userFeedbackAppService;
+ this.appAuthSessionService = appAuthSessionService;
}
/**
- * 提交 APP 用户意见反馈。
+ * 提交 APP 用户意见反馈,游客访问时按全局规则返回 401。
*/
@PostMapping("/user-feedbacks")
public ApiResponse<Void> submit(@Valid @RequestBody UserFeedbackSubmitRequest request) {
- userFeedbackAppService.submit(StpAppUserUtil.getLoginIdAsLong(), request);
+ userFeedbackAppService.submit(appAuthSessionService.requireLoginUserId(), request);
return ApiResponse.ok(null);
}
}
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/config/SaTokenWebConfig.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/config/SaTokenWebConfig.java
index 3f62ad7..1fcff2c 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/config/SaTokenWebConfig.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/config/SaTokenWebConfig.java
@@ -52,10 +52,7 @@
}
String requestPath = SaHolder.getRequest().getRequestPath();
if (isAppApi(requestPath)) {
- if (isPublicAppApi(requestPath)) {
- return;
- }
- StpAppUserUtil.checkLogin();
+ // APP 端允许游客访问,只有真正需要用户身份的接口才在业务层显式要求登录。
return;
}
if (isPublicAdminApi(requestPath)) {
@@ -69,18 +66,6 @@
*/
private boolean isAppApi(String requestPath) {
return requestPath.startsWith("/api/app/") || requestPath.startsWith("/api/v1/app/");
- }
-
- /**
- * 判断当前 APP 路由是否允许匿名访问。
- */
- private boolean isPublicAppApi(String requestPath) {
- return requestPath.startsWith("/api/app/auth/")
- || requestPath.startsWith("/api/v1/app/auth/")
- || requestPath.startsWith("/api/app/register/")
- || requestPath.startsWith("/api/v1/app/register/")
- || "/api/app/version/check".equals(requestPath)
- || "/api/v1/app/version/check".equals(requestPath);
}
/**
diff --git a/traditionalApp/pages/home/home.vue b/traditionalApp/pages/home/home.vue
index b0c1030..96a4c94 100644
--- a/traditionalApp/pages/home/home.vue
+++ b/traditionalApp/pages/home/home.vue
@@ -26,17 +26,13 @@
</view>
<!-- Banners -->
- <view class="banner-section">
- <view class="banner-main">
- <image src="/static/image/home/live.png" mode="aspectFill" class="banner-img"></image>
- <!-- Carousel dots -->
- <view class="dots">
- <view class="dot active"></view>
- <image src="/static/image/home/circle.png" class="dot-img"></image>
- <image src="/static/image/home/circle.png" class="dot-img"></image>
- </view>
+ <view v-if="bannerList.length" class="banner-section">
+ <u-swiper :list="bannerList" :height="280" mode="none" name="imageUrl" bgColor="#fff" border-radius="20"
+ :interval="3000" @change="handleBannerChange" @click="handleBannerClick"></u-swiper>
+ <view class="dots">
+ <view v-for="(item, index) in bannerList" :key="item.id || index" class="dot"
+ :class="{ active: bannerActiveIndex === index }"></view>
</view>
- <image src="/static/image/home/AI.png" mode="aspectFill" class="banner-sub"></image>
</view>
<!-- Live Section -->
@@ -134,13 +130,28 @@
<script setup lang="ts">
import UpdatePopup from "@/components/updatePopup.vue";
- import { ref, onMounted, computed, } from "vue";
- import { onPageScroll } from "@dcloudio/uni-app";
+ import { ref, onMounted, computed } from "vue";
+ import { onPageScroll, onShow } from "@dcloudio/uni-app";
+ import { getBannerList } from "./service";
+
+ interface HomeBannerItem {
+ id: number | string;
+ imageUrl: string;
+ title?: string;
+ jumpType?: string;
+ targetId?: number | string | null;
+ targetUrl?: string;
+ }
const statusBarHeight = ref(0);
- const scrollY = ref(0); // Add scrollY reactive variable
- const showUpdatePopup = ref(false); // Update popup visibility, set to true by default for immediate display
+ const scrollY = ref(0);
+ const showUpdatePopup = ref(false);
+ const bannerList = ref<HomeBannerItem[]>([]);
+ const bannerActiveIndex = ref(0);
+ /**
+ * 初始化导航栏所需系统信息。
+ */
onMounted(() => {
uni.getSystemInfo({
success: (res) => {
@@ -149,47 +160,159 @@
});
});
- onPageScroll((e) => {
- scrollY.value = e.scrollTop; // Update scrollY on page scroll
+ /**
+ * 每次进入首页都刷新 banner,确保拿到后台最新上下架结果。
+ */
+ onShow(() => {
+ loadBannerList();
});
+ /**
+ * 监听页面滚动以驱动导航栏渐变。
+ */
+ onPageScroll((e) => {
+ scrollY.value = e.scrollTop;
+ });
+
+ /**
+ * 计算自定义导航栏占位高度。
+ */
const navbarHeightPx = computed(() => {
- const navContentHeightRpx = 88; // Height of nav-content in rpx
+ const navContentHeightRpx = 88;
const screenWidthPx = uni.getSystemInfoSync().screenWidth;
const navContentHeightPx = (navContentHeightRpx / 750) * screenWidthPx;
return statusBarHeight.value + navContentHeightPx;
});
+ /**
+ * 根据滚动距离切换导航栏背景色。
+ */
const navbarBackgroundColor = computed(() => {
- // Change to white after scrolling down 50rpx
const thresholdRpx = 50;
const screenWidthPx = uni.getSystemInfoSync().screenWidth;
const thresholdPx = (thresholdRpx / 750) * screenWidthPx;
- const color = scrollY.value > thresholdPx ? 'white' : 'transparent';
-
- return color;
+ return scrollY.value > thresholdPx ? 'white' : 'transparent';
});
+ /**
+ * 请求首页顶部 banner 列表。
+ */
+ const loadBannerList = async () => {
+ try {
+ const res = await getBannerList();
+ if (res?.code !== 0 || !Array.isArray(res.data)) {
+ bannerList.value = [];
+ bannerActiveIndex.value = 0;
+ return;
+ }
+ bannerList.value = res.data.filter((item: HomeBannerItem) => !!item?.imageUrl);
+ bannerActiveIndex.value = 0;
+ } catch {
+ bannerList.value = [];
+ bannerActiveIndex.value = 0;
+ }
+ };
+
+ /**
+ * 同步当前轮播索引,用于自定义指示器展示。
+ */
+ const handleBannerChange = (index: number) => {
+ bannerActiveIndex.value = index;
+ };
+
+ /**
+ * 根据 banner 跳转类型分发到现有页面。
+ */
+ const handleBannerClick = (index: number) => {
+ const currentBanner = bannerList.value[index];
+ if (!currentBanner) {
+ return;
+ }
+
+ // 课程和直播必须携带目标主键,避免跳进空白详情页。
+ if (currentBanner.jumpType === 'HEALTH_COURSE' || currentBanner.jumpType === 'LIVE_COURSE') {
+ if (!currentBanner.targetId) {
+ return;
+ }
+ }
+
+ if (currentBanner.jumpType === 'HEALTH_COURSE') {
+ uni.navigateTo({
+ url: `/pages/courseDetail/courseDetail?id=${currentBanner.targetId}`
+ });
+ return;
+ }
+
+ if (currentBanner.jumpType === 'LIVE_COURSE') {
+ uni.navigateTo({
+ url: `/pages/liveDetail/liveDetail?id=${currentBanner.targetId}`
+ });
+ return;
+ }
+
+ if (currentBanner.jumpType === 'MEMBER') {
+ uni.navigateTo({
+ url: '/pages/vip/vip'
+ });
+ return;
+ }
+
+ if (currentBanner.jumpType === 'THIRD_PARTY_URL') {
+ openThirdPartyUrl(currentBanner.targetUrl);
+ }
+ };
+
+ /**
+ * 打开第三方链接。
+ */
+ const openThirdPartyUrl = (targetUrl?: string) => {
+ if (!targetUrl) {
+ return;
+ }
+ // APP 端已适配第三方链接时,直接交由系统浏览器打开。
+ // #ifdef APP-PLUS
+ plus.runtime.openURL(targetUrl);
+ return;
+ // #endif
+ // #ifdef H5
+ window.open(targetUrl, '_blank');
+ return;
+ // #endif
+ };
+
+ /**
+ * 打开更新弹窗。
+ */
const handleOpenUpdate = () => {
showUpdatePopup.value = true;
};
+ /**
+ * 关闭更新弹窗。
+ */
const closeUpdatePopup = () => {
showUpdatePopup.value = false;
};
+ /**
+ * 确认更新后关闭弹窗。
+ */
const handleUpdateConfirm = () => {
- console.log('User confirmed update');
- // Handle update logic here
closeUpdatePopup();
};
+ /**
+ * 跳转直播详情页。
+ */
const goLiveDetail = () => {
uni.navigateTo({
url: '/pages/liveDetail/liveDetail'
});
};
+ /**
+ * 跳转搜索页。
+ */
const goSearch = () => {
uni.navigateTo({
url: '/pages/search/search'
@@ -320,50 +443,31 @@
.banner-section {
margin: 0 24rpx;
margin-top: 32rpx;
+ position: relative;
- .banner-main {
- position: relative;
- width: 702rpx;
- height: 280rpx;
- border-radius: 20rpx;
- overflow: hidden;
+ .dots {
+ position: absolute;
+ bottom: 16rpx;
+ left: 0;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ pointer-events: none;
- .banner-img {
- width: 100%;
- height: 100%;
+ .dot {
+ width: 10rpx;
+ height: 10rpx;
+ background: rgba(255, 255, 255, 0.5);
+ border-radius: 10rpx;
+ margin: 0 6rpx;
+ transition: all 0.3s ease;
}
- .dots {
- position: absolute;
- bottom: 16rpx;
- left: 0;
- width: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
-
- .dot {
- width: 24rpx;
- height: 10rpx;
- background: #FFF;
- border-radius: 6rpx;
- margin: 0 6rpx;
- }
-
- .dot-img {
- width: 10rpx;
- height: 10rpx;
- margin: 0 6rpx;
- opacity: 0.5;
- }
+ .dot.active {
+ width: 24rpx;
+ background: #FFF;
}
- }
-
- .banner-sub {
- width: 702rpx;
- height: 160rpx;
- margin-top: 20rpx;
- border-radius: 16rpx;
}
}
diff --git a/traditionalApp/pages/home/service.js b/traditionalApp/pages/home/service.js
index d30e618..87d0b69 100644
--- a/traditionalApp/pages/home/service.js
+++ b/traditionalApp/pages/home/service.js
@@ -1,17 +1,22 @@
import request from '@/utils/request.js'
-//首页模块--轮播图
-export const getBannerList = (params) => {
- return request.get(`/index/getBannerList`, params, 1)
+/**
+ * 获取 APP 首页顶部 Banner 列表。
+ */
+export const getBannerList = () => {
+ return request.get('/api/app/home/banners', {}, false, false)
}
-
-//获取攻略列表
+/**
+ * 获取首页攻略列表。
+ */
export const getGuideList = (params) => {
return request.get(`/index/getGuideList`, params, 1)
}
-//获取公告列表
+/**
+ * 获取首页公告列表。
+ */
export const getNoticeList = (params) => {
return request.get(`/index/getNoticeList`, params, 1)
-}
\ No newline at end of file
+}
diff --git a/traditionalApp/utils/request.js b/traditionalApp/utils/request.js
index 3a53ec7..4fe0608 100644
--- a/traditionalApp/utils/request.js
+++ b/traditionalApp/utils/request.js
@@ -8,6 +8,7 @@
const waitingList = [] //等待队列
const excutingList = [] //执行队列
+let appAuthRedirecting = false
/**
* 判断当前响应码是否属于成功态。
@@ -80,11 +81,7 @@
return
}
if (payload.code == 401 || payload.code == 510 || payload.code == 504 || payload.code == 505) {
- // uni.clearStorageSync()
- // handleLogout('登录过期,请重新登录')
- // uni.navigateTo({
- // url: '/pages/login/login'
- // })
+ handleUnauthorized(payload)
resolve(payload)
return
}
@@ -135,29 +132,51 @@
}
/**
- * 被冻结时跳转到登录页并取消后续请求。
+ * 收到未登录响应时清理 APP 登录态并跳转登录页。
*/
-function handleLogout(str) {
- let routeStr = getCurrentPages()[getCurrentPages().length - 1].route
- if (uni.getStorageSync('showLogoutModal') == 1) {
- uni.setStorageSync('showLogoutModal', 0)
- uni.showModal({
- title: '提示',
- content: str,
- showCancel: false,
- success: function(res) {
- if (res.confirm) {
- if (routeStr == 'pages/login/login') {
- return
- }
- uni.reLaunch({
- url: '/pages/login/login'
- })
- }
- }
- });
- clearAllRequest()
+function handleUnauthorized(payload) {
+ const routeStr = getCurrentRoute()
+ clearLoginSession()
+ clearAllRequest()
+ if (routeStr === 'pages/login/login' || appAuthRedirecting) {
+ return
}
+ appAuthRedirecting = true
+ uni.showToast({
+ title: resolveMessage(payload) || '请先登录',
+ duration: 1500,
+ icon: 'none',
+ mask: true,
+ })
+ setTimeout(() => {
+ uni.reLaunch({
+ url: '/pages/login/login'
+ })
+ setTimeout(() => {
+ appAuthRedirecting = false
+ }, 300)
+ }, 150)
+}
+
+/**
+ * 清除 APP 登录态缓存。
+ */
+function clearLoginSession() {
+ uni.removeStorageSync('token')
+ uni.removeStorageSync('appUserInfo')
+ uni.removeStorageSync('loginRedirectMeta')
+ uni.setStorageSync('showLogoutModal', 0)
+}
+
+/**
+ * 获取当前页面路由,便于避免在登录页重复跳转。
+ */
+function getCurrentRoute() {
+ const currentPages = getCurrentPages()
+ if (!currentPages || currentPages.length === 0) {
+ return ''
+ }
+ return currentPages[currentPages.length - 1].route || ''
}
/**
--
Gitblit v1.7.1