diff --git a/backend/src/main/java/com/openisle/config/SecurityConfig.java b/backend/src/main/java/com/openisle/config/SecurityConfig.java index ba982d980..100c0a2e3 100644 --- a/backend/src/main/java/com/openisle/config/SecurityConfig.java +++ b/backend/src/main/java/com/openisle/config/SecurityConfig.java @@ -119,6 +119,8 @@ public class SecurityConfig { .requestMatchers(HttpMethod.GET, "/api/reaction-types").permitAll() .requestMatchers(HttpMethod.GET, "/api/activities/**").permitAll() .requestMatchers(HttpMethod.GET, "/api/sitemap.xml").permitAll() + .requestMatchers(HttpMethod.GET, "/api/point-goods").permitAll() + .requestMatchers(HttpMethod.POST, "/api/point-goods").permitAll() .requestMatchers(HttpMethod.POST, "/api/categories/**").hasAuthority("ADMIN") .requestMatchers(HttpMethod.POST, "/api/tags/**").authenticated() .requestMatchers(HttpMethod.DELETE, "/api/categories/**").hasAuthority("ADMIN") @@ -151,6 +153,7 @@ public class SecurityConfig { uri.startsWith("/api/search") || uri.startsWith("/api/users") || uri.startsWith("/api/reaction-types") || uri.startsWith("/api/config") || uri.startsWith("/api/activities") || uri.startsWith("/api/push/public-key") || + uri.startsWith("/api/point-goods") || uri.startsWith("/api/sitemap.xml") || uri.startsWith("/api/medals")); if (authHeader != null && authHeader.startsWith("Bearer ")) { diff --git a/frontend_nuxt/pages/points.vue b/frontend_nuxt/pages/points.vue index 36b16673b..2a0e1ec22 100644 --- a/frontend_nuxt/pages/points.vue +++ b/frontend_nuxt/pages/points.vue @@ -7,6 +7,10 @@ +
+ +
+

我的积分:{{ @@ -23,7 +27,13 @@ {{ good.cost }} 积分

-
兑换
+
+ 兑换 +
{ + isLoading.value = true if (authState.loggedIn) { const user = await fetchCurrentUser() point.value = user ? user.point : null } await loadGoods() + isLoading.value = false }) const loadGoods = async () => { @@ -76,6 +89,10 @@ const loadGoods = async () => { } const openRedeem = (good) => { + if (!authState.loggedIn || point.value === null || point.value < good.cost) { + toast.error('积分不足') + return + } selectedGood.value = good dialogVisible.value = true } @@ -117,6 +134,13 @@ const submitRedeem = async () => { margin: 0 auto; } +.loading-points-container { + margin-top: 100px; + display: flex; + justify-content: center; + align-items: center; +} + .point-info { font-size: 18px; } @@ -184,6 +208,12 @@ const submitRedeem = async () => { background-color: var(--primary-color-hover); } +.goods-item-button.disabled, +.goods-item-button.disabled:hover { + background-color: var(--primary-color-disabled); + cursor: not-allowed; +} + .section-title { font-size: 18px; font-weight: bold;