Merge branch 'refs/heads/order_v2'

# Conflicts:
#	src/main/java/com/ycwl/basic/controller/mobile/manage/AppScenicAccountController.java
This commit is contained in:
2025-08-30 10:53:11 +08:00
112 changed files with 7427 additions and 948 deletions

View File

@@ -0,0 +1,304 @@
package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.pricing.dto.*;
import com.ycwl.basic.pricing.service.IPriceCalculationService;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.service.PriceCacheService;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.dto.MobileOrderRequest;
import com.ycwl.basic.order.service.IOrderService;
import com.ycwl.basic.order.dto.OrderV2DetailResponse;
import com.ycwl.basic.order.dto.OrderV2ListResponse;
import com.ycwl.basic.order.dto.OrderV2PageRequest;
import com.ycwl.basic.order.dto.PaymentParamsRequest;
import com.ycwl.basic.order.dto.PaymentParamsResponse;
import com.ycwl.basic.order.dto.PaymentCallbackResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
/**
* 移动端订单控制器V2
* 包含价格查询和订单管理功能
*/
@Slf4j
@RestController
@RequestMapping("/api/mobile/order/v2")
@RequiredArgsConstructor
public class AppOrderV2Controller {
private final IPriceCalculationService priceCalculationService;
private final FaceService faceService;
private final PriceCacheService priceCacheService;
private final IOrderService orderService;
/**
* 移动端价格计算
* 包含权限验证:验证人脸所属景区与当前用户匹配
* 集成Redis缓存机制,提升查询性能
*/
@PostMapping("/calculate")
public ApiResponse<PriceCalculationResult> calculatePrice(@RequestBody MobilePriceCalculationRequest request) {
// 获取当前登录用户ID
String currentUserIdStr = BaseContextHandler.getUserId();
if (currentUserIdStr == null) {
log.warn("移动端价格计算:用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
log.info("移动端价格计算请求: userId={}, faceId={}, products={}",
currentUserId, request.getFaceId(), request.getProducts().size());
// 验证faceId参数
if (request.getFaceId() == null) {
log.warn("移动端价格计算:faceId参数缺失");
return ApiResponse.fail("faceId参数不能为空");
}
// 查询人脸信息进行权限验证
ApiResponse<FaceRespVO> faceResponse = faceService.getById(request.getFaceId());
if (!faceResponse.isSuccess() || faceResponse.getData() == null) {
log.warn("移动端价格计算:人脸信息不存在, faceId={}", request.getFaceId());
return ApiResponse.fail("人脸信息不存在");
}
FaceRespVO face = faceResponse.getData();
Long scenicId = face.getScenicId();
// 先尝试从Redis缓存获取价格计算结果
PriceCalculationResult cachedResult = priceCacheService.getCachedPriceResult(
currentUserId, scenicId, request.getProducts());
if (cachedResult != null) {
log.info("命中价格缓存: userId={}, scenicId={}, finalAmount={}",
currentUserId, scenicId, cachedResult.getFinalAmount());
return ApiResponse.success(cachedResult);
}
// 转换为标准价格计算请求
PriceCalculationRequest standardRequest = request.toStandardRequest(currentUserId, scenicId);
// 执行价格计算
PriceCalculationResult result = priceCalculationService.calculatePrice(standardRequest);
// 将计算结果缓存到Redis
String cacheKey = priceCacheService.cachePriceResult(currentUserId, scenicId, request.getProducts(), result);
log.info("移动端价格计算完成: userId={}, scenicId={}, originalAmount={}, finalAmount={}, cacheKey={}",
currentUserId, scenicId, result.getOriginalAmount(), result.getFinalAmount(), cacheKey);
return ApiResponse.success(result);
}
/**
* 移动端下单接口
* 验证价格缓存有效性,确保5分钟内使用缓存价格下单
*/
@PostMapping("/add")
public ApiResponse<String> addOrder(@RequestBody MobileOrderRequest request) {
// 获取当前登录用户ID
String currentUserIdStr = BaseContextHandler.getUserId();
if (currentUserIdStr == null) {
log.warn("移动端下单:用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
log.info("移动端下单请求: userId={}, faceId={}, products={}, expectedFinalAmount={}",
currentUserId, request.getFaceId(), request.getProducts().size(), request.getExpectedFinalAmount());
// 验证必填参数
if (request.getFaceId() == null) {
log.warn("移动端下单:faceId参数缺失");
return ApiResponse.fail("faceId参数不能为空");
}
if (request.getProducts() == null || request.getProducts().isEmpty()) {
log.warn("移动端下单:商品列表为空");
return ApiResponse.fail("商品列表不能为空");
}
if (request.getExpectedFinalAmount() == null) {
log.warn("移动端下单:预期价格参数缺失");
return ApiResponse.fail("预期价格不能为空");
}
// 查询人脸信息进行权限验证
ApiResponse<FaceRespVO> faceResponse = faceService.getById(request.getFaceId());
if (!faceResponse.isSuccess() || faceResponse.getData() == null) {
log.warn("移动端下单:人脸信息不存在, faceId={}", request.getFaceId());
return ApiResponse.fail("人脸信息不存在");
}
FaceRespVO face = faceResponse.getData();
Long scenicId = face.getScenicId();
// 验证并消费价格缓存(一次性使用)
PriceCalculationResult cachedResult = priceCacheService.validateAndConsumePriceCache(
currentUserId, scenicId, request.getProducts());
if (cachedResult == null) {
log.warn("移动端下单:价格缓存已过期或不存在, userId={}, scenicId={}", currentUserId, scenicId);
return ApiResponse.fail("请重新下单!");
}
// 验证价格是否匹配
if (cachedResult.getFinalAmount().compareTo(request.getExpectedFinalAmount()) != 0) {
log.warn("移动端下单:价格不匹配, cached={}, expected={}, userId={}, scenicId={}",
cachedResult.getFinalAmount(), request.getExpectedFinalAmount(), currentUserId, scenicId);
return ApiResponse.fail("请重新下单!");
}
// 验证原价是否匹配(可选)
if (request.getExpectedOriginalAmount() != null &&
cachedResult.getOriginalAmount().compareTo(request.getExpectedOriginalAmount()) != 0) {
log.warn("移动端下单:原价不匹配, cached={}, expected={}, userId={}, scenicId={}",
cachedResult.getOriginalAmount(), request.getExpectedOriginalAmount(), currentUserId, scenicId);
return ApiResponse.fail("原价信息不匹配,请重新查询价格后再下单");
}
log.info("价格缓存验证通过: userId={}, scenicId={}, finalAmount={}",
currentUserId, scenicId, cachedResult.getFinalAmount());
// 创建订单
try {
Long orderId = orderService.createOrder(request, currentUserId, scenicId, cachedResult);
log.info("移动端订单创建成功: orderId={}, userId={}, scenicId={}, finalAmount={}",
orderId, currentUserId, scenicId, cachedResult.getFinalAmount());
return ApiResponse.success(orderId.toString());
} catch (Exception e) {
log.error("订单创建失败: userId={}, scenicId={}, error={}", currentUserId, scenicId, e.getMessage(), e);
return ApiResponse.fail("订单创建失败,请稍后重试");
}
}
// ====== 新增移动端订单查询功能 ======
/**
* 用户分页查询自己的订单列表
*/
@PostMapping("/page")
public ApiResponse<PageInfo<OrderV2ListResponse>> pageUserOrders(@RequestBody OrderV2PageRequest request) {
String currentUserIdStr = BaseContextHandler.getUserId();
if (currentUserIdStr == null) {
log.warn("用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
request.setMemberId(currentUserId); // 设置当前用户ID,确保只查询自己的订单
log.info("用户查询订单列表: userId={}, request={}", currentUserId, request);
try {
PageInfo<OrderV2ListResponse> pageInfo = orderService.pageOrdersByUser(request);
return ApiResponse.success(pageInfo);
} catch (Exception e) {
log.error("查询用户订单列表失败: userId={}", currentUserId, e);
return ApiResponse.fail("查询失败:" + e.getMessage());
}
}
/**
* 用户查询自己的订单详情
*/
@GetMapping("/detail/{orderId}")
public ApiResponse<OrderV2DetailResponse> getUserOrderDetail(@PathVariable("orderId") Long orderId) {
String currentUserIdStr = BaseContextHandler.getUserId();
if (currentUserIdStr == null) {
log.warn("用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
log.info("用户查询订单详情: userId={}, orderId={}", currentUserId, orderId);
try {
OrderV2DetailResponse detail = orderService.getOrderDetail(orderId);
if (detail == null) {
return ApiResponse.fail("订单不存在");
}
// 验证订单是否属于当前用户
if (!currentUserId.equals(detail.getMemberId())) {
log.warn("用户尝试访问他人订单: userId={}, orderId={}, orderOwner={}",
currentUserId, orderId, detail.getMemberId());
return ApiResponse.fail("无权访问该订单");
}
return ApiResponse.success(detail);
} catch (Exception e) {
log.error("查询用户订单详情失败: userId={}, orderId={}", currentUserId, orderId, e);
return ApiResponse.fail("查询失败:" + e.getMessage());
}
}
// ====== 支付相关接口 ======
/**
* 获取订单支付参数
* 用于小程序调起支付
*/
@PostMapping("/{orderId}/payment-params")
public ApiResponse<PaymentParamsResponse> getPaymentParams(
@PathVariable("orderId") Long orderId,
@RequestBody PaymentParamsRequest request) {
String currentUserIdStr = BaseContextHandler.getUserId();
if (currentUserIdStr == null) {
log.warn("用户未登录");
return ApiResponse.fail("用户未登录");
}
Long currentUserId = Long.valueOf(currentUserIdStr);
log.info("获取支付参数: userId={}, orderId={}", currentUserId, orderId);
try {
PaymentParamsResponse response = orderService.getPaymentParams(orderId, currentUserId, request);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("获取支付参数失败: userId={}, orderId={}", currentUserId, orderId, e);
return ApiResponse.fail(e.getMessage());
}
}
/**
* 支付回调处理接口
* 供第三方支付平台回调使用
*/
@PostMapping("/payment/callback/{scenicId}")
public String handlePaymentCallback(
@PathVariable("scenicId") Long scenicId,
HttpServletRequest request) {
log.info("接收支付回调: scenicId={}", scenicId);
try {
PaymentCallbackResponse response = orderService.handlePaymentCallback(scenicId, request);
if (response.isSuccess()) {
log.info("支付回调处理成功: scenicId={}, orderId={}, statusChangeType={}",
scenicId, response.getOrderId(), response.getStatusChangeType());
return "SUCCESS"; // 返回给第三方支付平台的成功标识
} else {
log.error("支付回调处理失败: scenicId={}, message={}", scenicId, response.getMessage());
return "FAIL"; // 返回给第三方支付平台的失败标识
}
} catch (Exception e) {
log.error("支付回调异常: scenicId={}", scenicId, e);
return "FAIL";
}
}
}

View File

@@ -3,12 +3,12 @@ package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicConfigResp;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
@@ -16,11 +16,14 @@ import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@@ -49,7 +52,7 @@ public class AppScenicController {
// 分页查询景区列表
@PostMapping("/page")
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
public ApiResponse<PageInfo<ScenicEntity>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
String userId = BaseContextHandler.getUserId();
if (ENABLED_USER_IDs.contains(userId)) {
return appScenicService.pageQuery(scenicReqQuery);

View File

@@ -2,6 +2,7 @@ package com.ycwl.basic.controller.mobile.manage;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginOldRespVO;
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
@@ -12,6 +13,7 @@ import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.pc.ScenicAccountService;
import com.ycwl.basic.service.pc.ScenicService;
@@ -25,10 +27,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
/**
@@ -45,6 +47,8 @@ public class AppScenicAccountController {
private AppScenicService scenicService;
@Autowired
private ScenicService adminScenicService;
@Autowired
private ScenicRepository scenicRepository;
// 登录
@PostMapping("/login")
@@ -73,8 +77,8 @@ public class AppScenicAccountController {
}
@GetMapping("/myScenicList")
public ApiResponse<List<ScenicRespVO>> myScenicList() {
List<ScenicRespVO> list;
public ApiResponse<List<ScenicV2DTO>> myScenicList() {
List<ScenicV2DTO> list = Collections.emptyList();
if (Strings.CS.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
String userId = BaseContextHandler.getUserId();
ScenicAccountEntity account = accountService.getScenicAccountById(Long.valueOf(userId));
@@ -82,10 +86,12 @@ public class AppScenicAccountController {
return ApiResponse.fail("景区账号未绑定景区");
}
list = account.getScenicId().stream()
.map(id -> scenicService.getDetails(id).getData())
.map(id -> scenicRepository.getScenicBasic(id))
.toList();
} else {
list = adminScenicService.list(new ScenicReqQuery()).getData();
} else if (Strings.CS.equals(BaseContextHandler.getRoleId(), ADMIN.type)) {
ScenicReqQuery query = new ScenicReqQuery();
query.setPageSize(1000);
list = scenicRepository.list(query);
}
return ApiResponse.success(list);
}

View File

@@ -0,0 +1,100 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO;
import com.ycwl.basic.integration.scenic.service.DefaultConfigIntegrationService;
import com.ycwl.basic.utils.ApiConst;
import com.ycwl.basic.utils.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 默认配置管理控制器
* 提供默认配置的增删查改功能
*/
@Slf4j
@RestController
@RequestMapping("/api/default-config")
@RequiredArgsConstructor
public class DefaultConfigController {
private final DefaultConfigIntegrationService defaultConfigIntegrationService;
/**
* 获取默认配置列表
*/
@GetMapping("/")
public ApiResponse<List<DefaultConfigDTO>> listDefaultConfigs() {
log.info("获取默认配置列表");
try {
List<DefaultConfigDTO> configs = defaultConfigIntegrationService.listDefaultConfigs();
return ApiResponse.success(configs);
} catch (Exception e) {
log.error("获取默认配置列表失败", e);
return ApiResponse.fail("获取默认配置列表失败: " + e.getMessage());
}
}
/**
* 根据配置键获取默认配置
*/
@GetMapping("/{configKey}")
public ApiResponse<DefaultConfigDTO> getDefaultConfig(@PathVariable String configKey) {
log.info("获取默认配置, configKey: {}", configKey);
try {
DefaultConfigDTO config = defaultConfigIntegrationService.getDefaultConfig(configKey);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("获取默认配置失败, configKey: {}", configKey, e);
return ApiResponse.fail("获取默认配置失败: " + e.getMessage());
}
}
/**
* 创建默认配置
*/
@PostMapping("/")
public ApiResponse<DefaultConfigDTO> createDefaultConfig(@RequestBody DefaultConfigDTO request) {
log.info("创建默认配置, configKey: {}", request.getConfigKey());
try {
DefaultConfigDTO config = defaultConfigIntegrationService.createDefaultConfig(request);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("创建默认配置失败, configKey: {}", request.getConfigKey(), e);
return ApiResponse.fail("创建默认配置失败: " + e.getMessage());
}
}
/**
* 更新默认配置
*/
@PutMapping("/{configKey}")
public ApiResponse<DefaultConfigDTO> updateDefaultConfig(@PathVariable String configKey,
@RequestBody DefaultConfigDTO request) {
log.info("更新默认配置, configKey: {}", configKey);
try {
DefaultConfigDTO config = defaultConfigIntegrationService.updateDefaultConfig(configKey, request);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("更新默认配置失败, configKey: {}", configKey, e);
return ApiResponse.fail("更新默认配置失败: " + e.getMessage());
}
}
/**
* 删除默认配置
*/
@DeleteMapping("/{configKey}")
public ApiResponse<Void> deleteDefaultConfig(@PathVariable String configKey) {
log.info("删除默认配置, configKey: {}", configKey);
try {
defaultConfigIntegrationService.deleteDefaultConfig(configKey);
return ApiResponse.buildResponse(ApiConst.Code.CODE_SUCCESS.code(), null, "删除成功");
} catch (Exception e) {
log.error("删除默认配置失败, configKey: {}", configKey, e);
return ApiResponse.fail("删除默认配置失败: " + e.getMessage());
}
}
}

View File

@@ -1,13 +1,12 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.service.pc.ScenicAccountService;
@@ -17,16 +16,20 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.WxMpUtil;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import org.apache.commons.lang3.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.util.Collections;
import java.util.List;
import static com.ycwl.basic.constant.JwtRoleConstant.ADMIN;
import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;
/**
@@ -50,68 +53,6 @@ public class ScenicController {
@Autowired
private ScenicAccountService accountService;
// 分页查询景区
@PostMapping("/page")
public ApiResponse<PageInfo<ScenicRespVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery) {
return scenicService.pageQuery(scenicReqQuery);
}
// 查询景区列表
@PostMapping("/list")
public ApiResponse<List<ScenicRespVO>> list(@RequestBody ScenicReqQuery scenicReqQuery) {
return scenicService.list(scenicReqQuery);
}
// 查询景区详情
@GetMapping("/getDetail/{id}")
public ApiResponse<ScenicRespVO> getDetail(@PathVariable Long id) {
return scenicService.getById(id);
}
// 新增景区
@PostMapping("/add")
public ApiResponse<Boolean> add(@RequestBody ScenicAddOrUpdateReq scenicAddReq) {
return scenicService.add(scenicAddReq);
}
// 删除景区
@GetMapping("/delete/{id}")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
return scenicService.deleteById(id);
}
// 修改景区
@PostMapping("/update")
public ApiResponse<Boolean> update(@RequestBody ScenicAddOrUpdateReq scenicAddReq) {
return scenicService.update(scenicAddReq);
}
// 修改景区状态
@GetMapping("/updateStatus/{id}")
public ApiResponse<Boolean> updateStatus(@PathVariable Long id) {
return scenicService.updateStatus(id);
}
// 新增景区配置
@PostMapping("/addConfig")
public ApiResponse<Boolean> addConfig(@RequestBody ScenicConfigEntity scenicConfig) {
return scenicService.addConfig(scenicConfig);
}
// 修改景区配置
@PostMapping("/updateConfig")
public ApiResponse<Boolean> updateConfig(@RequestBody ScenicConfigEntity scenicConfig) {
return scenicService.updateConfigById(scenicConfig);
}
// 查询景区配置
@GetMapping("/config/{id}")
public ApiResponse<ScenicConfigEntity> getConfig(@PathVariable("id") Long id) {
return ApiResponse.success(scenicService.getConfig(id));
}
@PostMapping("/saveConfig/{id}")
public ApiResponse saveConfig(@PathVariable("id") Long id, @RequestBody ScenicConfigEntity config) {
scenicService.saveConfig(id, config);
return ApiResponse.success(null);
}
@PostMapping("/saveConfig/undefined")
public ApiResponse saveConfig(@RequestBody ScenicConfigEntity config) {
scenicService.addConfig(config);
return ApiResponse.success(null);
}
// 根据景区ID下载小程序二维码
@GetMapping("/{id}/QRCode")
public ApiResponse<String> downloadQrCode(@PathVariable Long id) {
@@ -167,19 +108,19 @@ public class ScenicController {
}
@GetMapping("/myScenicList")
public ApiResponse<List<ScenicRespVO>> myScenicList() {
List<ScenicRespVO> list = Collections.emptyList();
public ApiResponse<List<ScenicV2DTO>> myScenicList() {
List<ScenicV2DTO> list = Collections.emptyList();
if (Strings.CS.equals(BaseContextHandler.getRoleId(), MERCHANT.type)) {
String userId = BaseContextHandler.getUserId();
ScenicAccountEntity account = accountService.getScenicAccountById(Long.valueOf(userId));
if (account == null || account.getScenicId().isEmpty()) {
return ApiResponse.fail("景区账号未绑定景区");
}
list = account.getScenicId().stream().map(id -> {
return appScenicService.getDetails(id).getData();
}).toList();
} else {
list = scenicService.list(new ScenicReqQuery()).getData();
list = account.getScenicId().stream().map(id -> scenicRepository.getScenicBasic(id)).toList();
} else if (Strings.CS.equals(BaseContextHandler.getRoleId(), ADMIN.type)) {
ScenicReqQuery query = new ScenicReqQuery();
query.setPageSize(1000);
list = scenicRepository.list(query);
}
return ApiResponse.success(list);
}

View File

@@ -0,0 +1,336 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.integration.scenic.dto.config.BatchConfigRequest;
import com.ycwl.basic.integration.scenic.dto.config.BatchUpdateResponse;
import com.ycwl.basic.integration.scenic.dto.config.CreateConfigRequest;
import com.ycwl.basic.integration.scenic.dto.config.ScenicConfigV2DTO;
import com.ycwl.basic.integration.scenic.dto.config.UpdateConfigRequest;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse;
import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse;
import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest;
import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService;
import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService;
import com.ycwl.basic.utils.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* @Author:longbinbin
* @Date:2024/12/26
* 景区管理 V2 版本控制器 - 基于 zt-scenic 集成服务
*/
@Slf4j
@RestController
@RequestMapping("/api/scenic/v2")
@RequiredArgsConstructor
public class ScenicV2Controller {
private final ScenicIntegrationService scenicIntegrationService;
private final ScenicConfigIntegrationService scenicConfigIntegrationService;
// ========== 景区基础 CRUD 操作 ==========
/**
* 景区V2核心信息分页列表
*/
@GetMapping("/")
public ApiResponse<ScenicV2ListResponse> listScenics(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status,
@RequestParam(required = false) String name) {
log.info("分页查询景区核心信息列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name);
// 参数验证:限制pageSize最大值为100
if (pageSize > 100) {
pageSize = 100;
}
try {
ScenicV2ListResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("分页查询景区核心信息列表失败", e);
return ApiResponse.fail("分页查询景区列表失败: " + e.getMessage());
}
}
/**
* 景区V2带配置信息分页列表
*/
@GetMapping("/with-config")
public ApiResponse<ScenicV2WithConfigListResponse> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status,
@RequestParam(required = false) String name) {
log.info("分页查询景区带配置信息列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name);
// 参数验证:限制pageSize最大值为100
if (pageSize > 100) {
pageSize = 100;
}
try {
ScenicV2WithConfigListResponse response = scenicIntegrationService.listScenicsWithConfig(page, pageSize, status, name);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("分页查询景区带配置信息列表失败", e);
return ApiResponse.fail("分页查询景区带配置信息列表失败: " + e.getMessage());
}
}
/**
* 查询单个景区详情
*/
@GetMapping("/{scenicId}")
public ApiResponse<ScenicV2DTO> getScenic(@PathVariable Long scenicId) {
log.info("查询景区详情, scenicId: {}", scenicId);
try {
ScenicV2DTO scenic = scenicIntegrationService.getScenic(scenicId);
return ApiResponse.success(scenic);
} catch (Exception e) {
log.error("查询景区详情失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("查询景区详情失败: " + e.getMessage());
}
}
/**
* 查询景区列表(支持筛选和分页)- 高级筛选
*/
@PostMapping("/filter")
public ApiResponse<ScenicFilterPageResponse> filterScenics(@RequestBody @Valid ScenicFilterRequest request) {
log.info("高级筛选景区列表, 筛选条件数: {}, 页码: {}, 页大小: {}",
request.getFilters().size(), request.getPage(), request.getPageSize());
try {
ScenicFilterPageResponse response = scenicIntegrationService.filterScenics(request);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("高级筛选景区列表失败", e);
return ApiResponse.fail("高级筛选景区列表失败: " + e.getMessage());
}
}
/**
* 新增景区
*/
@PostMapping("/create")
public ApiResponse<ScenicV2DTO> createScenic(@RequestBody @Valid CreateScenicRequest request) {
log.info("新增景区, name: {}, mpId: {}", request.getName(), request.getMpId());
try {
ScenicV2DTO scenic = scenicIntegrationService.createScenic(request);
return ApiResponse.success(scenic);
} catch (Exception e) {
log.error("新增景区失败, name: {}", request.getName(), e);
return ApiResponse.fail("新增景区失败: " + e.getMessage());
}
}
/**
* 修改景区
*/
@PutMapping("/{scenicId}")
public ApiResponse<ScenicV2DTO> updateScenic(@PathVariable Long scenicId,
@RequestBody @Valid UpdateScenicRequest request) {
log.info("修改景区, scenicId: {}", scenicId);
try {
ScenicV2DTO scenic = scenicIntegrationService.updateScenic(scenicId, request);
return ApiResponse.success(scenic);
} catch (Exception e) {
log.error("修改景区失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("修改景区失败: " + e.getMessage());
}
}
/**
* 删除景区
*/
@DeleteMapping("/{scenicId}")
public ApiResponse<Void> deleteScenic(@PathVariable Long scenicId) {
log.info("删除景区, scenicId: {}", scenicId);
try {
scenicIntegrationService.deleteScenic(scenicId);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("删除景区失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("删除景区失败: " + e.getMessage());
}
}
/**
* 景区列表查询(默认1000条)
* 只支持根据状态筛选
*/
@GetMapping("/list")
public ApiResponse<ScenicV2ListResponse> listScenicsByStatus(@RequestParam(required = false) Integer status) {
log.info("查询景区列表, status: {}", status);
try {
// 默认查询1000条数据,第1页
ScenicV2ListResponse scenics = scenicIntegrationService.listScenics(1, 1000, status, null);
return ApiResponse.success(scenics);
} catch (Exception e) {
log.error("查询景区列表失败, status: {}", status, e);
return ApiResponse.fail("查询景区列表失败: " + e.getMessage());
}
}
// ========== 景区配置管理 ==========
/**
* 获取景区及其配置信息
*/
@GetMapping("/{scenicId}/with-config")
public ApiResponse<ScenicV2WithConfigDTO> getScenicWithConfig(@PathVariable Long scenicId) {
log.info("获取景区配置信息, scenicId: {}", scenicId);
try {
ScenicV2WithConfigDTO scenic = scenicIntegrationService.getScenicWithConfig(scenicId);
return ApiResponse.success(scenic);
} catch (Exception e) {
log.error("获取景区配置信息失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("获取景区配置信息失败: " + e.getMessage());
}
}
/**
* 获取景区扁平化配置
*/
@GetMapping("/{scenicId}/flat-config")
public ApiResponse<Map<String, Object>> getScenicFlatConfig(@PathVariable Long scenicId) {
log.info("获取景区扁平化配置, scenicId: {}", scenicId);
try {
Map<String, Object> config = scenicIntegrationService.getScenicFlatConfig(scenicId);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("获取景区扁平化配置失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("获取景区扁平化配置失败: " + e.getMessage());
}
}
/**
* 获取景区配置列表
*/
@GetMapping("/{scenicId}/config")
public ApiResponse<List<ScenicConfigV2DTO>> listConfigs(@PathVariable Long scenicId) {
log.info("获取景区配置列表, scenicId: {}", scenicId);
try {
List<ScenicConfigV2DTO> configs = scenicConfigIntegrationService.listConfigs(scenicId);
return ApiResponse.success(configs);
} catch (Exception e) {
log.error("获取景区配置列表失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("获取景区配置列表失败: " + e.getMessage());
}
}
/**
* 根据配置键获取配置
*/
@GetMapping("/{scenicId}/config/{configKey}")
public ApiResponse<ScenicConfigV2DTO> getConfigByKey(@PathVariable Long scenicId,
@PathVariable String configKey) {
log.info("根据键获取景区配置, scenicId: {}, configKey: {}", scenicId, configKey);
try {
ScenicConfigV2DTO config = scenicConfigIntegrationService.getConfigByKey(scenicId, configKey);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("根据键获取景区配置失败, scenicId: {}, configKey: {}", scenicId, configKey, e);
return ApiResponse.fail("获取配置失败: " + e.getMessage());
}
}
/**
* 创建景区配置
*/
@PostMapping("/{scenicId}/config")
public ApiResponse<ScenicConfigV2DTO> createConfig(@PathVariable Long scenicId,
@RequestBody @Valid CreateConfigRequest request) {
log.info("创建景区配置, scenicId: {}, configKey: {}", scenicId, request.getConfigKey());
try {
ScenicConfigV2DTO config = scenicConfigIntegrationService.createConfig(scenicId, request);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("创建景区配置失败, scenicId: {}, configKey: {}", scenicId, request.getConfigKey(), e);
return ApiResponse.fail("创建配置失败: " + e.getMessage());
}
}
/**
* 更新景区配置
*/
@PutMapping("/{scenicId}/config/{configId}")
public ApiResponse<ScenicConfigV2DTO> updateConfig(@PathVariable Long scenicId,
@PathVariable String configId,
@RequestBody @Valid UpdateConfigRequest request) {
log.info("更新景区配置, scenicId: {}, configId: {}", scenicId, configId);
try {
ScenicConfigV2DTO config = scenicConfigIntegrationService.updateConfig(scenicId, configId, request);
return ApiResponse.success(config);
} catch (Exception e) {
log.error("更新景区配置失败, scenicId: {}, configId: {}", scenicId, configId, e);
return ApiResponse.fail("更新配置失败: " + e.getMessage());
}
}
/**
* 删除景区配置
*/
@DeleteMapping("/{scenicId}/config/{configId}")
public ApiResponse<Void> deleteConfig(@PathVariable Long scenicId, @PathVariable String configId) {
log.info("删除景区配置, scenicId: {}, configId: {}", scenicId, configId);
try {
scenicConfigIntegrationService.deleteConfig(scenicId, configId);
return ApiResponse.success(null);
} catch (Exception e) {
log.error("删除景区配置失败, scenicId: {}, configId: {}", scenicId, configId, e);
return ApiResponse.fail("删除配置失败: " + e.getMessage());
}
}
/**
* 批量更新景区配置
*/
@PutMapping("/{scenicId}/config/batch")
public ApiResponse<BatchUpdateResponse> batchUpdateConfigs(@PathVariable Long scenicId,
@RequestBody @Valid BatchConfigRequest request) {
log.info("批量更新景区配置, scenicId: {}, configs count: {}", scenicId, request.getConfigs().size());
try {
BatchUpdateResponse response = scenicConfigIntegrationService.batchUpdateConfigs(scenicId, request);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("批量更新景区配置失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("批量更新配置失败: " + e.getMessage());
}
}
/**
* 扁平化批量更新景区配置
*/
@PutMapping("/{scenicId}/flat-config")
public ApiResponse<BatchUpdateResponse> batchFlatUpdateConfigs(@PathVariable Long scenicId,
@RequestBody Map<String, Object> configs) {
log.info("扁平化批量更新景区配置, scenicId: {}, configs count: {}", scenicId, configs.size());
try {
BatchUpdateResponse response = scenicConfigIntegrationService.batchFlatUpdateConfigs(scenicId, configs);
return ApiResponse.success(response);
} catch (Exception e) {
log.error("扁平化批量更新景区配置失败, scenicId: {}", scenicId, e);
return ApiResponse.fail("扁平化批量更新配置失败: " + e.getMessage());
}
}
}