feat: 新增积分外部页面(免认证三页 + 配套基础设施)

前端:
- 新增 EmptyLayout 空壳布局(无侧边栏/导航)
- 新增 requestNoAuth Axios 实例(不注入 token)
- 新增 integralExternal 路由模块(/integral-external/*)
- permission.js 加入 whiteListPrefixes 前缀白名单跳过登录
- 新增 phoneDesensitize 手机号脱敏过滤器
- 新增三个免认证页面:
  · 积分订单页(/integral-external/order)
  · 用户积分页(/integral-external/user,手机号脱敏)
  · 用户积分明细子页(/integral-external/user/integral-detail)

后端:
- 新增 ExternalIntegralController(无 @PreAuthorize)
  · GET  /api/external/integral/order/list
  · GET  /api/external/integral/user/list
  · POST /api/external/integral/log/list
- WebSecurityConfig 加入 /api/external/integral/** permitAll

文档与工具:
- 新增 coding plan、schedule、测试报告
- 新增 start-backend.sh / start-frontend.sh 本地启动脚本
- 新增 .mvn/wrapper/maven-wrapper.properties

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
scott
2026-03-31 10:41:30 +08:00
parent fe9e1916fa
commit ee0886b800
25 changed files with 4360 additions and 2 deletions

BIN
backend/.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@@ -148,6 +148,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/api/admin/store/product/copy/**").permitAll()
.antMatchers("/api/admin/merchandise/select").permitAll()
.antMatchers("/api/admin/merchandise/update").permitAll()
// 积分模块外部免认证只读接口(供 /integral-external/* 页面调用)
.antMatchers("/api/external/integral/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()

View File

@@ -0,0 +1,92 @@
package com.zbkj.admin.controller;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.*;
import com.zbkj.common.response.StoreOrderDetailResponse;
import com.zbkj.common.response.UserIntegralRecordResponse;
import com.zbkj.common.response.UserResponse;
import com.zbkj.common.result.CommonResult;
import com.zbkj.service.service.StoreOrderService;
import com.zbkj.service.service.UserIntegralRecordService;
import com.zbkj.service.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 积分模块外部免认证接口 Controller
* 供管理后台外部页面(/integral-external/*)调用,跳过登录验证。
* 所有接口仅提供只读查询能力,不包含任何写操作。
*
* 安全说明:此 Controller 映射路径已在 WebSecurityConfig 中配置为 permitAll。
* 建议生产环境配合 IP 白名单或反向代理层访问控制使用。
*/
@Slf4j
@RestController
@RequestMapping("api/external/integral")
@Api(tags = "积分外部免认证接口")
public class ExternalIntegralController {
@Autowired
private UserIntegralRecordService integralRecordService;
@Autowired
private StoreOrderService storeOrderService;
@Autowired
private UserService userService;
/**
* 积分明细分页列表(免认证)
* 复用 UserIntegralRecordService.findAdminList与 /admin/user/integral/list 逻辑完全一致。
*
* @param request 搜索条件dateLimit / keywords / uid
* @param pageParamRequest 分页参数page / limit
*/
@ApiOperation(value = "积分明细分页列表(免认证)")
@RequestMapping(value = "/log/list", method = RequestMethod.POST)
public CommonResult<CommonPage<UserIntegralRecordResponse>> getIntegralLogList(
@RequestBody @Validated AdminIntegralSearchRequest request,
@Validated PageParamRequest pageParamRequest) {
CommonPage<UserIntegralRecordResponse> restPage =
CommonPage.restPage(integralRecordService.findAdminList(request, pageParamRequest));
return CommonResult.success(restPage);
}
/**
* 订单分页列表(免认证)
* 复用 StoreOrderService.getAdminList与 /admin/store/order/list 逻辑完全一致。
*
* @param request 搜索条件status / dateLimit / orderNo / type
* @param pageParamRequest 分页参数page / limit
*/
@ApiOperation(value = "订单分页列表(免认证)")
@GetMapping(value = "/order/list")
public CommonResult<CommonPage<StoreOrderDetailResponse>> getOrderList(
@Validated StoreOrderSearchRequest request,
@Validated PageParamRequest pageParamRequest) {
CommonPage<StoreOrderDetailResponse> restPage =
CommonPage.restPage(storeOrderService.getAdminList(request, pageParamRequest));
return CommonResult.success(restPage);
}
/**
* 用户分页列表(免认证)
* 复用 UserService.getList与 /admin/user/list 逻辑完全一致。
*
* @param request 搜索条件keywords / dateLimit 等)
* @param pageParamRequest 分页参数page / limit
*/
@ApiOperation(value = "用户分页列表(免认证)")
@GetMapping(value = "/user/list")
public CommonResult<CommonPage<UserResponse>> getUserList(
@ModelAttribute @Validated UserSearchRequest request,
@Validated PageParamRequest pageParamRequest) {
CommonPage<UserResponse> restPage =
CommonPage.restPage(userService.getList(request, pageParamRequest));
return CommonResult.success(restPage);
}
}