Browse Source

feat(api): 新增小程序/APP充电及订单支付接口

- 实现充电站查询功能,支持距离、价格及空闲状态排序
- 提供充电站、充电桩、充电订单详情接口
- 新增开始充电与停止充电接口,预留硬件对接逻辑
- 实现用户充值档位查询及订单创建
- 添加支付发起与支付回调接口,待完善微信支付集成
- 支持订单列表查询、取消及退款功能
- 集成第三方企业接口,支持加密签名及用户登录逻辑预留
- 优化实体类,新增字段和别名映射便于接口数据处理
- 增强时间段和价格计算逻辑,支持跨天时间判断
- 统一Token处理,刷新登录状态与用户信息缓存
- 接口实现采用事务管理保证数据一致性
SheepHy 2 days ago
parent
commit
b12d008854

+ 427 - 0
src/main/java/com/zsElectric/boot/app/api/ChargeApiController.java

@@ -0,0 +1,427 @@
+package com.zsElectric.boot.app.api;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.zsElectric.boot.app.model.entity.*;
+import com.zsElectric.boot.app.service.*;
+import com.zsElectric.boot.core.web.Result;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * 充电API接口 - 面向小程序/APP
+ * 包含充电站查询、充电桩控制等核心功能
+ */
+@Slf4j
+@RestController
+@RequestMapping("/chargeApi")
+@RequiredArgsConstructor
+public class ChargeApiController {
+
+    private final ChargeOrderInfoService chargeOrderInfoService;
+    private final ChargeStationService chargeStationService;
+    private final ChargeDeviceService chargeDeviceService;
+    private final StationTimePriceService stationTimePriceService;
+    private final UserAccountService userAccountService;
+    private final EcUserAccountService ecUserAccountService;
+    private final EcInfoService ecInfoService;
+    private final NewUserDiscountService newUserDiscountService;
+    private final FirmStationTimePriceService firmStationTimePriceService;
+    private final RedisTemplate<String, Object> redisTemplate;
+
+    private final String TOKEN_PREFIX = "user:token:";
+
+    /**
+     * 查询用电量统计
+     * TODO: 需要实现具体的统计逻辑
+     */
+    @PostMapping("/queryUsedAmount")
+    public Result<?> queryUsedAmount(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            String startDate = data.get("startDate") != null ? data.get("startDate").toString() : null;
+            String endDate = data.get("endDate") != null ? data.get("endDate").toString() : null;
+
+            // TODO: 实现用电量统计逻辑
+            Map<String, Object> result = new HashMap<>();
+            result.put("totalAmount", BigDecimal.ZERO);
+            result.put("totalMoney", BigDecimal.ZERO);
+
+            return Result.success(result);
+        } catch (Exception e) {
+            log.error("查询用电量失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 查询充电站列表(带距离、价格、空闲状态等信息)
+     */
+    @PostMapping("/getStations")
+    public Result<?> getStationsByLoc(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            UserInfo cacheUser = getUserFromToken(request);
+            
+            // 排序方式:0-距离 1-空闲 2-电费
+            Integer order = data.get("order") != null ? Integer.valueOf(data.get("order").toString()) : 0;
+            String key = data.get("key") != null ? data.get("key").toString() : null;
+            String latStr = data.get("lat") != null ? data.get("lat").toString() : "";
+            String lngStr = data.get("lng") != null ? data.get("lng").toString() : "";
+
+            // 查询所有上架的充电站
+            List<ChargeStation> stationList = chargeStationService.lambdaQuery()
+                    .eq(ChargeStation::getShowStatus, 1)
+                    .list();
+
+            // 如果有搜索关键字,过滤充电站
+            if (StrUtil.isNotBlank(key)) {
+                stationList = stationList.stream()
+                        .filter(s -> s.getStationName() != null && s.getStationName().contains(key))
+                        .collect(Collectors.toList());
+            }
+
+            List<Map<String, Object>> resultList = new ArrayList<>();
+
+            for (ChargeStation station : stationList) {
+                Map<String, Object> stationMap = new HashMap<>();
+                stationMap.put("id", station.getId());
+                stationMap.put("stationName", station.getStationName());
+                stationMap.put("address", station.getAddress());
+                stationMap.put("lat", station.getLat());
+                stationMap.put("lng", station.getLng());
+
+                // 计算距离
+                if (StrUtil.isNotBlank(latStr) && StrUtil.isNotBlank(lngStr)) {
+                    double distance = calculateDistance(
+                            Double.parseDouble(lngStr),
+                            Double.parseDouble(latStr),
+                            Double.parseDouble(station.getLng()),
+                            Double.parseDouble(station.getLat())
+                    );
+                    stationMap.put("range", distance);
+                    stationMap.put("rangeShow", formatDistance(distance));
+                } else {
+                    stationMap.put("range", 0);
+                    stationMap.put("rangeShow", "0m");
+                }
+
+                // 统计充电桩信息
+                List<ChargeDevice> devices = chargeDeviceService.lambdaQuery()
+                        .eq(ChargeDevice::getStationId, station.getId())
+                        .list();
+
+                int totalFast = 0, emptyFast = 0, totalSlow = 0, emptySlow = 0;
+                for (ChargeDevice device : devices) {
+                    if (device.getPower().compareTo(new BigDecimal("15")) <= 0) {
+                        totalSlow++;
+                        if (device.getDeviceStatus() == 1) emptySlow++;
+                    } else {
+                        totalFast++;
+                        if (device.getDeviceStatus() == 1) emptyFast++;
+                    }
+                }
+
+                stationMap.put("totalFast", totalFast);
+                stationMap.put("emptyFast", emptyFast);
+                stationMap.put("totalSlow", totalSlow);
+                stationMap.put("emptySlow", emptySlow);
+                stationMap.put("totalEmpty", emptyFast + emptySlow);
+
+                // 查询当前时段价格
+                List<StationTimePrice> timePrices = stationTimePriceService.lambdaQuery()
+                        .eq(StationTimePrice::getStationId, station.getId())
+                        .list();
+
+                BigDecimal nowPrice = BigDecimal.ZERO;
+                String priceShow = "";
+                
+                for (StationTimePrice timePrice : timePrices) {
+                    if (isCurrentTimeInRange(timePrice.getTime())) {
+                        nowPrice = timePrice.getPrice();
+                        String timeType = switch (timePrice.getTimeType()) {
+                            case 1 -> "谷 ";
+                            case 2 -> "平 ";
+                            case 3 -> "峰 ";
+                            default -> "";
+                        };
+                        priceShow = timeType + timePrice.getTime();
+
+                        // 如果用户已登录,检查企业专享价
+                        if (cacheUser != null && cacheUser.getFirmId() != null) {
+                            FirmStationTimePrice firmPrice = firmStationTimePriceService.lambdaQuery()
+                                    .eq(FirmStationTimePrice::getFirmId, cacheUser.getFirmId())
+                                    .eq(FirmStationTimePrice::getStationId, station.getId())
+                                    .eq(FirmStationTimePrice::getStartTime, timePrice.getStartTime())
+                                    .eq(FirmStationTimePrice::getEndTime, timePrice.getEndTime())
+                                    .one();
+                            
+                            if (firmPrice != null) {
+                                // 计算企业专享总价格
+                                BigDecimal firmElec = firmPrice.getElecPrice() != null ? firmPrice.getElecPrice() : BigDecimal.ZERO;
+                                BigDecimal firmService = firmPrice.getServicePrice() != null ? firmPrice.getServicePrice() : BigDecimal.ZERO;
+                                nowPrice = firmElec.add(firmService);
+                            }
+                        }
+                        break;
+                    }
+                }
+
+                stationMap.put("nowPrice", nowPrice);
+                stationMap.put("priceShow", priceShow);
+
+                resultList.add(stationMap);
+            }
+
+            // 排序
+            switch (order) {
+                case 0: // 按距离排序
+                    resultList.sort(Comparator.comparing(m -> ((Number) m.get("range")).doubleValue()));
+                    break;
+                case 1: // 按空闲数量排序
+                    resultList.sort(Comparator.comparing(m -> ((Number) m.get("totalEmpty")).intValue(), Comparator.reverseOrder()));
+                    break;
+                case 2: // 按电费排序
+                    resultList.sort(Comparator.comparing(m -> ((BigDecimal) m.get("nowPrice"))));
+                    break;
+            }
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("stations", resultList);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询充电站失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 获取充电站详情
+     */
+    @PostMapping("/getStationInfo")
+    public Result<?> getStationInfo(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Long stationId = Long.valueOf(data.get("stationId").toString());
+            ChargeStation station = chargeStationService.getById(stationId);
+
+            if (station == null) {
+                return Result.failed("充电站不存在");
+            }
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("station", station);
+
+            // 查询充电桩列表
+            List<ChargeDevice> devices = chargeDeviceService.lambdaQuery()
+                    .eq(ChargeDevice::getStationId, stationId)
+                    .list();
+            result.put("devices", devices);
+
+            // 查询价格时段
+            List<StationTimePrice> timePrices = stationTimePriceService.lambdaQuery()
+                    .eq(StationTimePrice::getStationId, stationId)
+                    .orderByAsc(StationTimePrice::getTime)
+                    .list();
+            result.put("timePrices", timePrices);
+
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询充电站详情失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 获取充电桩详情
+     */
+    @PostMapping("/getDeviceInfo")
+    public Result<?> getDeviceInfo(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Long deviceId = Long.valueOf(data.get("deviceId").toString());
+            ChargeDevice device = chargeDeviceService.getById(deviceId);
+
+            if (device == null) {
+                return Result.failed("充电桩不存在");
+            }
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("device", device);
+
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询充电桩详情失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 开始充电
+     * TODO: 需要对接充电桩硬件接口
+     */
+    @PostMapping("/startCharge")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> startCharge(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        try {
+            Long deviceId = Long.valueOf(data.get("deviceId").toString());
+            
+            // TODO: 实现充电逻辑
+            // 1. 检查充电桩状态
+            // 2. 检查用户余额
+            // 3. 创建充电订单
+            // 4. 调用硬件接口启动充电
+            
+            log.warn("开始充电功能待实现,设备ID: {}", deviceId);
+            return Result.failed("充电功能正在开发中");
+
+        } catch (Exception e) {
+            log.error("开始充电失败", e);
+            return Result.failed("充电失败");
+        }
+    }
+
+    /**
+     * 停止充电
+     * TODO: 需要对接充电桩硬件接口
+     */
+    @PostMapping("/stopCharge")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> stopCharge(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        try {
+            Long orderId = Long.valueOf(data.get("orderId").toString());
+            
+            // TODO: 实现停止充电逻辑
+            // 1. 查询充电订单
+            // 2. 调用硬件接口停止充电
+            // 3. 结算订单
+            // 4. 扣费
+            
+            log.warn("停止充电功能待实现,订单ID: {}", orderId);
+            return Result.failed("停止充电功能正在开发中");
+
+        } catch (Exception e) {
+            log.error("停止充电失败", e);
+            return Result.failed("停止失败");
+        }
+    }
+
+    /**
+     * 查询充电订单列表
+     */
+    @PostMapping("/getChargeOrders")
+    public Result<?> getChargeOrders(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        try {
+            List<ChargeOrderInfo> orders = chargeOrderInfoService.lambdaQuery()
+                    .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                    .orderByDesc(ChargeOrderInfo::getCreateTime)
+                    .list();
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("orders", orders);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询充电订单失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 判断当前时间是否在时间段内
+     */
+    private boolean isCurrentTimeInRange(String timeRange) {
+        try {
+            String[] times = timeRange.split("-");
+            if (times.length != 2) {
+                return false;
+            }
+
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
+            LocalTime now = LocalTime.now();
+            LocalTime start = LocalTime.parse(times[0].trim(), formatter);
+            LocalTime end = LocalTime.parse(times[1].trim(), formatter);
+
+            if (start.isBefore(end)) {
+                return !now.isBefore(start) && !now.isAfter(end);
+            } else {
+                // 跨天的情况
+                return !now.isBefore(start) || !now.isAfter(end);
+            }
+        } catch (Exception e) {
+            log.error("解析时间范围失败: {}", timeRange, e);
+            return false;
+        }
+    }
+
+    /**
+     * 计算两点之间的距离(米)
+     * 使用Haversine公式
+     */
+    private double calculateDistance(double lng1, double lat1, double lng2, double lat2) {
+        double earthRadius = 6371000; // 地球半径(米)
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLng = Math.toRadians(lng2 - lng1);
+        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
+                        Math.sin(dLng / 2) * Math.sin(dLng / 2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+        return earthRadius * c;
+    }
+
+    /**
+     * 格式化距离显示
+     */
+    private String formatDistance(double meters) {
+        if (meters > 1000) {
+            BigDecimal km = BigDecimal.valueOf(meters / 1000).setScale(2, RoundingMode.HALF_UP);
+            return km + "km";
+        } else {
+            return (int) meters + "m";
+        }
+    }
+
+    /**
+     * 从请求头获取token并从缓存中获取用户信息
+     */
+    private UserInfo getUserFromToken(HttpServletRequest request) {
+        String token = request.getHeader("token");
+        if (StrUtil.isBlank(token)) {
+            return null;
+        }
+
+        Object obj = redisTemplate.opsForValue().get(TOKEN_PREFIX + token);
+        if (obj instanceof UserInfo) {
+            // 刷新token过期时间
+            redisTemplate.expire(TOKEN_PREFIX + token, 30, TimeUnit.MINUTES);
+            return (UserInfo) obj;
+        }
+        return null;
+    }
+}

+ 295 - 0
src/main/java/com/zsElectric/boot/app/api/OrderApiController.java

@@ -0,0 +1,295 @@
+package com.zsElectric.boot.app.api;
+
+import cn.hutool.core.util.StrUtil;
+import com.zsElectric.boot.app.model.entity.ChargeOrderInfo;
+import com.zsElectric.boot.app.model.entity.RechargeLevel;
+import com.zsElectric.boot.app.model.entity.UserInfo;
+import com.zsElectric.boot.app.model.entity.UserOrderInfo;
+import com.zsElectric.boot.app.service.ChargeOrderInfoService;
+import com.zsElectric.boot.app.service.RechargeLevelService;
+import com.zsElectric.boot.app.service.UserInfoService;
+import com.zsElectric.boot.app.service.UserOrderInfoService;
+import com.zsElectric.boot.core.web.Result;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 订单支付API接口 - 面向小程序/APP
+ */
+@Slf4j
+@RestController
+@RequestMapping("/orderApi")
+@RequiredArgsConstructor
+public class OrderApiController {
+
+    private final RechargeLevelService rechargeLevelService;
+    private final UserOrderInfoService userOrderInfoService;
+    private final ChargeOrderInfoService chargeOrderInfoService;
+    private final UserInfoService userInfoService;
+    private final RedisTemplate<String, Object> redisTemplate;
+
+    private final String TOKEN_PREFIX = "user:token:";
+
+    /**
+     * 获取充值档位列表
+     */
+    @PostMapping("/getReChargeLevel")
+    public Result<?> getReChargeLevel() {
+        List<RechargeLevel> levels = rechargeLevelService.lambdaQuery()
+                .eq(RechargeLevel::getLevelStatus, 1)
+                .orderByAsc(RechargeLevel::getLevelMoney)
+                .list();
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("levels", levels);
+        return Result.success(result);
+    }
+
+    /**
+     * 创建订单
+     */
+    @PostMapping("/addOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> addOrder(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        Long levelId = Long.valueOf(data.get("levelId").toString());
+        RechargeLevel rechargeLevel = rechargeLevelService.getById(levelId);
+        
+        if (rechargeLevel == null || rechargeLevel.getLevelStatus() != 1) {
+            return Result.failed("充值档位不可用");
+        }
+
+        // 查询是否有待补缴的订单
+        long owedOrderCount = chargeOrderInfoService.lambdaQuery()
+                .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                .eq(ChargeOrderInfo::getMaspStatus, 1)
+                .count();
+
+        if (owedOrderCount > 0) {
+            ChargeOrderInfo owedOrder = chargeOrderInfoService.lambdaQuery()
+                    .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                    .eq(ChargeOrderInfo::getMaspStatus, 1)
+                    .one();
+            
+            if (owedOrder != null) {
+                BigDecimal owedAmount = owedOrder.getMaspAmount().add(owedOrder.getMaspRealAmount());
+                if (rechargeLevel.getLevelMoney().compareTo(owedAmount) < 0) {
+                    return Result.failed("金额必须大于补缴金额");
+                }
+            }
+        }
+
+        // 创建订单
+        UserOrderInfo orderInfo = new UserOrderInfo();
+        orderInfo.setUserId(cacheUser.getId());
+        orderInfo.setOrderMoney(rechargeLevel.getLevelMoney());
+        orderInfo.setLastMoney(rechargeLevel.getLevelMoney());
+        orderInfo.setLevelId(rechargeLevel.getId());
+        orderInfo.setOrderType(1);
+
+        boolean saved = userOrderInfoService.save(orderInfo);
+        if (!saved) {
+            return Result.failed("下单失败,请重试");
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("orderId", orderInfo.getId());
+        return Result.success(result);
+    }
+
+    /**
+     * 发起支付
+     * TODO: 需要配置微信支付参数
+     */
+    @PostMapping("/payOrder")
+    public Result<?> payOrder(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        Long orderId = Long.valueOf(data.get("orderId").toString());
+        UserOrderInfo order = userOrderInfoService.getById(orderId);
+        
+        if (order == null || order.getOrderStatus() != 1) {
+            return Result.failed("订单状态异常");
+        }
+
+        // TODO: 实现微信支付逻辑
+        // 1. 生成订单号
+        // 2. 调用微信支付接口
+        // 3. 返回支付参数给前端
+        
+        log.warn("支付功能待实现,订单ID: {}", orderId);
+        return Result.failed("支付功能正在开发中");
+    }
+
+    /**
+     * 支付回调
+     * TODO: 需要实现微信支付回调验签逻辑
+     */
+    @PostMapping("/orderNotify")
+    public void orderNotify(HttpServletRequest request, HttpServletResponse response) {
+        String resXml = "error";
+        
+        try {
+            // TODO: 实现支付回调逻辑
+            // 1. 读取微信回调数据
+            // 2. 验签
+            // 3. 处理订单支付成功逻辑
+            // 4. 更新订单状态
+            // 5. 为用户充值
+            
+            log.warn("支付回调功能待实现");
+            resXml = "success";
+            
+        } catch (Exception e) {
+            log.error("支付回调异常", e);
+            resXml = "error";
+        }
+
+        try {
+            response.getWriter().write(resXml);
+        } catch (IOException e) {
+            log.error("响应写入失败", e);
+        }
+    }
+
+    /**
+     * 取消订单
+     */
+    @PostMapping("/cancelOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> cancelOrder(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        Long orderId = Long.valueOf(data.get("orderId").toString());
+        UserOrderInfo order = userOrderInfoService.getById(orderId);
+        
+        if (order == null || order.getOrderStatus() != 1) {
+            return Result.failed("订单状态异常");
+        }
+
+        // 更新订单状态为已取消
+        UserOrderInfo updateOrder = new UserOrderInfo();
+        updateOrder.setId(order.getId());
+        updateOrder.setOrderStatus(3);
+        
+        boolean updated = userOrderInfoService.updateById(updateOrder);
+        return Result.judge(updated);
+    }
+
+    /**
+     * 获取订单列表
+     */
+    @PostMapping("/getOrderList")
+    public Result<?> getOrderList(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        Integer pageNum = data.get("pageNum") != null ? Integer.valueOf(data.get("pageNum").toString()) : 1;
+        Integer pageSize = data.get("pageSize") != null ? Integer.valueOf(data.get("pageSize").toString()) : 10;
+
+        // 查询订单列表(不包括已取消的)
+        List<UserOrderInfo> orderList = userOrderInfoService.lambdaQuery()
+                .eq(UserOrderInfo::getUserId, cacheUser.getId())
+                .ne(UserOrderInfo::getOrderStatus, -1)
+                .orderByDesc(UserOrderInfo::getCreateTime)
+                .list();
+
+        // 补充欠款金额信息
+        for (UserOrderInfo orderInfo : orderList) {
+            if (orderInfo.getChargeOrderId() != null) {
+                ChargeOrderInfo chargeOrder = chargeOrderInfoService.getById(orderInfo.getChargeOrderId());
+                if (chargeOrder != null) {
+                    orderInfo.setZtBackMoney(chargeOrder.getMaspAmount());
+                }
+            }
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("orderList", orderList);
+        result.put("total", orderList.size());
+        return Result.success(result);
+    }
+
+    /**
+     * 退款
+     */
+    @PostMapping("/refund")
+    @Transactional(rollbackFor = Exception.class)
+    public synchronized Result<?> refund(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        // 判断当前是否正在充电
+        long chargingCount = chargeOrderInfoService.lambdaQuery()
+                .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                .in(ChargeOrderInfo::getStatus, 0, 1, 2)
+                .isNull(ChargeOrderInfo::getEcId)
+                .count();
+
+        if (chargingCount > 0) {
+            return Result.failed("你当前有正在充电的订单,请等待结算完成后再退款");
+        }
+
+        // 查询是否有待补缴的订单
+        long owedCount = chargeOrderInfoService.lambdaQuery()
+                .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                .eq(ChargeOrderInfo::getMaspStatus, 1)
+                .count();
+
+        if (owedCount > 0) {
+            return Result.failed("你有一笔超充的订单,请结算后再退款");
+        }
+
+        // 执行退款
+        boolean refunded = userInfoService.refund(cacheUser, "用户自行退款");
+        if (refunded) {
+            return Result.success("退款申请已提交");
+        }
+
+        return Result.failed("退款失败");
+    }
+
+    /**
+     * 从请求头获取token并从缓存中获取用户信息
+     */
+    private UserInfo getUserFromToken(HttpServletRequest request) {
+        String token = request.getHeader("token");
+        if (StrUtil.isBlank(token)) {
+            return null;
+        }
+
+        Object obj = redisTemplate.opsForValue().get(TOKEN_PREFIX + token);
+        if (obj instanceof UserInfo) {
+            // 刷新token过期时间
+            redisTemplate.expire(TOKEN_PREFIX + token, 30, TimeUnit.MINUTES);
+            return (UserInfo) obj;
+        }
+        return null;
+    }
+}

+ 359 - 0
src/main/java/com/zsElectric/boot/app/api/ThirdPartyApiController.java

@@ -0,0 +1,359 @@
+package com.zsElectric.boot.app.api;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zsElectric.boot.app.model.entity.*;
+import com.zsElectric.boot.app.service.*;
+import com.zsElectric.boot.core.web.Result;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * 第三方对接API接口 - 面向企业第三方集成
+ * TODO: 需要完善加解密和签名验证逻辑
+ */
+@Slf4j
+@RestController
+@RequestMapping("/thirdPartyApi")
+@RequiredArgsConstructor
+public class ThirdPartyApiController {
+
+    private final ThirdPartyInfoService thirdPartyInfoService;
+    private final RechargeLevelService rechargeLevelService;
+    private final UserInfoService userInfoService;
+    private final UserOrderInfoService userOrderInfoService;
+    private final UserAccountService userAccountService;
+    private final ChargeStationService chargeStationService;
+    private final ChargeDeviceService chargeDeviceService;
+    private final StationTimePriceService stationTimePriceService;
+    private final ChargeOrderInfoService chargeOrderInfoService;
+    private final RedisTemplate<String, Object> redisTemplate;
+    private final ObjectMapper objectMapper;
+
+    private final String TOKEN_PREFIX = "third:token:";
+
+    /**
+     * 第三方充电券购买
+     * TODO: 需要实现加密解密和签名验证
+     */
+    @PostMapping("/addOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> addOrder(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            // TODO: 验证签名
+            Map<String, String> validResult = validateSign(data, "appId,levelId,phone,orderNo,payTime,totalMoney,timestamp");
+            if (validResult == null) {
+                return Result.failed("签名验证失败");
+            }
+
+            String levelId = data.get("levelId").toString();
+            RechargeLevel rechargeLevel = rechargeLevelService.getById(Long.valueOf(levelId));
+            
+            if (rechargeLevel == null || rechargeLevel.getLevelStatus() != 1) {
+                return Result.failed("充值档位不可用");
+            }
+
+            String phone = data.get("phone").toString();
+            Long thirdPartyId = Long.valueOf(validResult.get("thirdPartyInfoId"));
+
+            // 查询或创建用户
+            UserInfo userInfo = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getPhone, phone)
+                    .eq(UserInfo::getGroupId, thirdPartyId)
+                    .one();
+
+            if (userInfo == null) {
+                userInfo = new UserInfo();
+                userInfo.setPhone(phone);
+                userInfo.setGroupId(thirdPartyId);
+                userInfoService.save(userInfo);
+
+                // 创建账户
+                UserAccount userAccount = new UserAccount();
+                userAccount.setUserId(userInfo.getId());
+                userAccountService.save(userAccount);
+            }
+
+            // 创建订单
+            UserOrderInfo orderInfo = new UserOrderInfo();
+            orderInfo.setUserId(userInfo.getId());
+            orderInfo.setOrderMoney(rechargeLevel.getLevelMoney());
+            orderInfo.setLastMoney(rechargeLevel.getLevelMoney());
+            orderInfo.setLevelId(rechargeLevel.getId());
+            orderInfo.setOrderType(2);
+            orderInfo.setAppId(data.get("appId").toString());
+            orderInfo.setOrderStatus(1);
+            orderInfo.setOutTradeNo(data.get("orderNo").toString());
+            
+            userOrderInfoService.save(orderInfo);
+
+            // TODO: 调用支付成功逻辑
+            // boolean payStatus = userOrderInfoService.successPay(...)
+
+            Map<String, Object> resultData = new HashMap<>();
+            resultData.put("orderId", orderInfo.getId());
+
+            // TODO: 使用AES加密返回数据
+            String encryptedData = encryptData(objectMapper.writeValueAsString(resultData), validResult.get("authCode"));
+            
+            Map<String, Object> result = new HashMap<>();
+            result.put("data", encryptedData);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("第三方下单失败", e);
+            return Result.failed("下单失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 充电券列表查询
+     */
+    @PostMapping("/rechargeList")
+    public Result<?> rechargeList(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Map<String, String> validResult = validateSign(data, "appId,timestamp");
+            if (validResult == null) {
+                return Result.failed("签名验证失败");
+            }
+
+            List<RechargeLevel> levels = rechargeLevelService.lambdaQuery()
+                    .eq(RechargeLevel::getLevelStatus, 1)
+                    .orderByAsc(RechargeLevel::getLevelMoney)
+                    .list();
+
+            Map<String, Object> resultData = new HashMap<>();
+            resultData.put("levels", levels);
+
+            // TODO: 使用AES加密返回数据
+            String encryptedData = encryptData(objectMapper.writeValueAsString(resultData), validResult.get("authCode"));
+            
+            Map<String, Object> result = new HashMap<>();
+            result.put("data", encryptedData);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询充值档位失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 用户充电券列表查询
+     */
+    @PostMapping("/discountList")
+    public Result<?> discountList(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Map<String, String> validResult = validateSign(data, "appId,timestamp,phone");
+            if (validResult == null) {
+                return Result.failed("签名验证失败");
+            }
+
+            String phone = data.get("phone").toString();
+            Long thirdPartyId = Long.valueOf(validResult.get("thirdPartyInfoId"));
+
+            UserInfo userInfo = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getPhone, phone)
+                    .eq(UserInfo::getGroupId, thirdPartyId)
+                    .one();
+
+            if (userInfo == null) {
+                return Result.failed("用户手机号错误");
+            }
+
+            List<UserOrderInfo> orders = userOrderInfoService.lambdaQuery()
+                    .eq(UserOrderInfo::getUserId, userInfo.getId())
+                    .eq(UserOrderInfo::getOrderStatus, 2)
+                    .list();
+
+            Map<String, Object> resultData = new HashMap<>();
+            resultData.put("discounts", orders);
+
+            // TODO: 使用AES加密返回数据
+            String encryptedData = encryptData(objectMapper.writeValueAsString(resultData), validResult.get("authCode"));
+            
+            Map<String, Object> result = new HashMap<>();
+            result.put("data", encryptedData);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("查询用户订单失败", e);
+            return Result.failed("查询失败");
+        }
+    }
+
+    /**
+     * 手机号登录
+     */
+    @PostMapping("/phoneLogin")
+    public Result<?> phoneLogin(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Map<String, String> validResult = validateSign(data, "appId,timestamp,phone");
+            if (validResult == null) {
+                return Result.failed("签名验证失败");
+            }
+
+            String phone = data.get("phone").toString();
+            Long thirdPartyId = Long.valueOf(validResult.get("thirdPartyInfoId"));
+
+            UserInfo userInfo = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getPhone, phone)
+                    .eq(UserInfo::getGroupId, thirdPartyId)
+                    .one();
+
+            if (userInfo == null) {
+                return Result.failed("用户手机号错误");
+            }
+
+            // 生成token
+            String token = UUID.randomUUID().toString().replace("-", "");
+            redisTemplate.opsForValue().set(TOKEN_PREFIX + token, userInfo, 30, TimeUnit.MINUTES);
+
+            Map<String, Object> resultData = new HashMap<>();
+            resultData.put("token", token);
+
+            // TODO: 使用AES加密返回数据
+            String encryptedData = encryptData(objectMapper.writeValueAsString(resultData), validResult.get("authCode"));
+            
+            Map<String, Object> result = new HashMap<>();
+            result.put("data", encryptedData);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("第三方登录失败", e);
+            return Result.failed("登录失败");
+        }
+    }
+
+    /**
+     * 退款
+     */
+    @PostMapping("/refund")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> refund(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        try {
+            Map<String, String> validResult = validateSign(data, "appId,timestamp,phone");
+            if (validResult == null) {
+                return Result.failed("签名验证失败");
+            }
+
+            String phone = data.get("phone").toString();
+            Long thirdPartyId = Long.valueOf(validResult.get("thirdPartyInfoId"));
+
+            UserInfo userInfo = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getPhone, phone)
+                    .eq(UserInfo::getGroupId, thirdPartyId)
+                    .one();
+
+            if (userInfo == null) {
+                return Result.failed("用户手机号错误");
+            }
+
+            // 判断当前是否正在充电
+            long chargingCount = chargeOrderInfoService.lambdaQuery()
+                    .eq(ChargeOrderInfo::getUserId, userInfo.getId())
+                    .in(ChargeOrderInfo::getStatus, 0, 1, 2)
+                    .isNull(ChargeOrderInfo::getEcId)
+                    .count();
+
+            if (chargingCount > 0) {
+                return Result.failed("你当前有正在充电的订单,请等待结算完成后再退款");
+            }
+
+            // 查询是否有待补缴的订单
+            long owedCount = chargeOrderInfoService.lambdaQuery()
+                    .eq(ChargeOrderInfo::getUserId, userInfo.getId())
+                    .eq(ChargeOrderInfo::getMaspStatus, 1)
+                    .count();
+
+            if (owedCount > 0) {
+                return Result.failed("你有一笔超充的订单,请结算后再退款");
+            }
+
+            // 执行退款
+            boolean refunded = userInfoService.refund(userInfo, "第三方平台退款");
+            return Result.judge(refunded);
+
+        } catch (Exception e) {
+            log.error("退款失败", e);
+            return Result.failed("退款失败");
+        }
+    }
+
+    /**
+     * 验证签名
+     * TODO: 实现完整的签名验证逻辑
+     */
+    private Map<String, String> validateSign(Map<String, Object> data, String requiredKeys) {
+        try {
+            String appId = data.get("appId") != null ? data.get("appId").toString() : null;
+            if (StrUtil.isBlank(appId)) {
+                return null;
+            }
+
+            // 查询第三方信息
+            ThirdPartyInfo thirdPartyInfo = thirdPartyInfoService.lambdaQuery()
+                    .eq(ThirdPartyInfo::getAppId, appId)
+                    .one();
+
+            if (thirdPartyInfo == null) {
+                return null;
+            }
+
+            // TODO: 实现签名验证逻辑
+            // 1. 提取sign参数
+            // 2. 移除sign后对剩余参数排序
+            // 3. 拼接字符串
+            // 4. 使用authCode进行签名
+            // 5. 对比签名是否一致
+
+            Map<String, String> result = new HashMap<>();
+            result.put("thirdPartyInfoId", thirdPartyInfo.getId().toString());
+            result.put("authCode", thirdPartyInfo.getAuthCode());
+            return result;
+
+        } catch (Exception e) {
+            log.error("验证签名失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 加密数据
+     * TODO: 实现AES加密
+     */
+    private String encryptData(String data, String key) {
+        try {
+            // TODO: 使用AES加密
+            // return AESUtil.encrypt(data, key);
+            return data; // 临时返回明文
+        } catch (Exception e) {
+            log.error("加密失败", e);
+            return data;
+        }
+    }
+
+    /**
+     * 解密数据
+     * TODO: 实现AES解密
+     */
+    private String decryptData(String encryptedData, String key) {
+        try {
+            // TODO: 使用AES解密
+            // return AESUtil.decrypt(encryptedData, key);
+            return encryptedData; // 临时返回原文
+        } catch (Exception e) {
+            log.error("解密失败", e);
+            return encryptedData;
+        }
+    }
+}

+ 468 - 0
src/main/java/com/zsElectric/boot/app/api/UserApiController.java

@@ -0,0 +1,468 @@
+package com.zsElectric.boot.app.api;
+
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zsElectric.boot.app.model.entity.*;
+import com.zsElectric.boot.app.service.*;
+import com.zsElectric.boot.core.web.Result;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 用户API接口 - 面向小程序/APP
+ */
+@Slf4j
+@RestController
+@RequestMapping("/userApi")
+@RequiredArgsConstructor
+public class UserApiController {
+
+    private final UserInfoService userInfoService;
+    private final UserAccountService userAccountService;
+    private final BannerInfoService bannerInfoService;
+    private final UserFeedbackService userFeedbackService;
+    private final NewUserDiscountService newUserDiscountService;
+    private final ChargeOrderInfoService chargeOrderInfoService;
+    private final UserFirmService userFirmService;
+    private final FirmInfoService firmInfoService;
+    private final AdvertisingService advertisingService;
+    private final RedisTemplate<String, Object> redisTemplate;
+
+    private final OkHttpClient okHttpClient = new OkHttpClient();
+    private final ObjectMapper objectMapper = new ObjectMapper();
+    private final String TOKEN_PREFIX = "user:token:";
+
+    @Value("${wx.miniapp.app-id:}")
+    private String wxAppid;
+
+    @Value("${wx.miniapp.app-secret:}")
+    private String wxAppSecret;
+
+    /**
+     * 新用户活动信息查询
+     */
+    @PostMapping("/checkNewUser")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> checkNewUser(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        List<NewUserDiscount> list = newUserDiscountService.lambdaQuery()
+                .eq(NewUserDiscount::getStatus, 1)
+                .le(NewUserDiscount::getBeginTime, LocalDateTime.now())
+                .ge(NewUserDiscount::getEndTime, LocalDateTime.now())
+                .list();
+
+        if (list == null || list.isEmpty()) {
+            return Result.success("暂无新用户活动");
+        }
+
+        NewUserDiscount discountInfo = list.get(0);
+
+        long orderCount = chargeOrderInfoService.lambdaQuery()
+                .eq(ChargeOrderInfo::getUserId, cacheUser.getId())
+                .count();
+
+        if (orderCount > 0) {
+            return Result.success("不是新用户");
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("discountInfo", discountInfo);
+        return Result.success(result);
+    }
+
+    /**
+     * 微信小程序登录
+     */
+    @PostMapping("/login")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> login(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+
+        // 检查是否已登录
+        if (cacheUser != null && cacheUser.getId() != null) {
+            String token = request.getHeader("token");
+            if (token == null) {
+                return Result.failed("token不能为空");
+            }
+
+            if (data.get("checkStatus") != null) {
+                UserInfo userInfo = userInfoService.getById(cacheUser.getId());
+                saveUserToCache(token, userInfo);
+                Map<String, Object> result = new HashMap<>();
+                result.put("userInfo", userInfo);
+                result.put("token", token);
+                return Result.success(result);
+            }
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("userInfo", cacheUser);
+            result.put("token", token);
+            return Result.success(result);
+        }
+
+        String code = (String) data.get("code");
+        log.info("[微信登录]code:{}", code);
+        log.info("[微信登录]wxAppid:{}", wxAppid);
+
+        try {
+            // 调用微信接口获取openid
+            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxAppid +
+                    "&secret=" + wxAppSecret +
+                    "&grant_type=authorization_code&js_code=" + code;
+            String body = okHttpClient.newCall(new Request.Builder().url(url).get().build())
+                    .execute().body().string();
+
+            log.info("[微信登录]回复报文:{}", body);
+            JsonNode jsonNode = objectMapper.readTree(body);
+
+            String openid = jsonNode.has("openid") ? jsonNode.get("openid").asText() : null;
+            if (openid == null) {
+                log.error("[微信登录]失败,回复报文:{}", body);
+                return Result.failed("登录失败,请稍后再试");
+            }
+
+            // 查询或创建用户
+            UserInfo userInfo = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getWechat, openid)
+                    .one();
+
+            if (userInfo == null) {
+                userInfo = new UserInfo();
+                userInfo.setWechat(openid);
+                userInfoService.save(userInfo);
+
+                // 创建账户
+                UserAccount userAccount = new UserAccount();
+                userAccount.setUserId(userInfo.getId());
+                userAccountService.save(userAccount);
+            }
+
+            // 生成token并保存到缓存
+            String loginToken = UUID.randomUUID().toString().replace("-", "");
+            saveUserToCache(loginToken, userInfo);
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("userInfo", userInfo);
+            result.put("token", loginToken);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("[微信登录]异常", e);
+            return Result.failed("登录失败,请稍后再试");
+        }
+    }
+
+    /**
+     * 获取手机号
+     */
+    @PostMapping("/getPhone")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> getPhone(@RequestBody Map<String, Object> data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        String code = (String) data.get("code");
+
+        try {
+            // 获取access_token
+            String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +
+                    wxAppid + "&secret=" + wxAppSecret;
+            String tokenBody = okHttpClient.newCall(new Request.Builder().url(tokenUrl).get().build())
+                    .execute().body().string();
+
+            log.info("[获取token]回复报文:{}", tokenBody);
+            JsonNode tokenNode = objectMapper.readTree(tokenBody);
+            String accessToken = tokenNode.has("access_token") ? tokenNode.get("access_token").asText() : null;
+
+            if (accessToken == null) {
+                log.error("[获取token]失败,回复报文:{}", tokenBody);
+                return Result.failed("获取失败,请稍后再试");
+            }
+
+            // 获取手机号
+            Map<String, Object> phoneParams = new HashMap<>();
+            phoneParams.put("code", code);
+            okhttp3.RequestBody requestBody = okhttp3.RequestBody.create(
+                    MediaType.parse("application/json"), objectMapper.writeValueAsString(phoneParams));
+
+            String phoneUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
+            String phoneBody = okHttpClient.newCall(new Request.Builder().url(phoneUrl).post(requestBody).build())
+                    .execute().body().string();
+
+            log.info("[获取手机号]回复报文:{}", phoneBody);
+            JsonNode phoneNode = objectMapper.readTree(phoneBody);
+            Integer errcode = phoneNode.has("errcode") ? phoneNode.get("errcode").asInt() : -1;
+
+            if (errcode != 0) {
+                log.error("[获取手机号]失败,回复报文:{}", phoneBody);
+                return Result.failed("获取失败,请稍后再试");
+            }
+
+            JsonNode phoneInfo = phoneNode.get("phone_info");
+            String phone = phoneInfo.has("phoneNumber") ? phoneInfo.get("phoneNumber").asText() : null;
+
+            // 检查手机号是否已存在
+            UserInfo existUser = userInfoService.lambdaQuery()
+                    .eq(UserInfo::getPhone, phone)
+                    .ne(UserInfo::getGroupId, -1L)
+                    .one();
+
+            if (existUser != null) {
+                // 删除原账户的微信绑定
+                UserInfo oldUser = new UserInfo();
+                oldUser.setId(cacheUser.getId());
+                oldUser.setWechat(cacheUser.getId() + "_" + cacheUser.getWechat());
+                userInfoService.updateById(oldUser);
+
+                // 更新现有用户的微信id
+                existUser.setWechat(cacheUser.getWechat());
+                userInfoService.updateById(existUser);
+
+                String token = request.getHeader("token");
+                saveUserToCache(token, existUser);
+
+                Map<String, Object> result = new HashMap<>();
+                result.put("userInfo", existUser);
+                return Result.success(result);
+            }
+
+            // 更新当前用户的手机号
+            UserInfo updateUser = new UserInfo();
+            updateUser.setId(cacheUser.getId());
+            updateUser.setPhone(phone);
+            userInfoService.updateById(updateUser);
+
+            UserInfo userInfo = userInfoService.getById(cacheUser.getId());
+            String token = request.getHeader("token");
+            saveUserToCache(token, userInfo);
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("userInfo", userInfo);
+            return Result.success(result);
+
+        } catch (Exception e) {
+            log.error("[获取手机号]异常", e);
+            return Result.failed("获取失败,请稍后再试");
+        }
+    }
+
+    /**
+     * 获取用户账户信息
+     */
+    @PostMapping("/getUserAccount")
+    public Result<?> getUserAccount(HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        UserInfo user = userInfoService.getById(cacheUser.getId());
+        if (user == null) {
+            return Result.failed("未查询到用户信息");
+        }
+
+        if (ObjectUtil.isNotEmpty(user.getFirmId())) {
+            FirmInfo firmInfo = firmInfoService.getById(user.getFirmId());
+            if (ObjectUtil.isNotEmpty(firmInfo)) {
+                user.setFirmInfoName(firmInfo.getName());
+                user.setFirmType(firmInfo.getStatus());
+            }
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("accountInfo", user);
+        return Result.success(result);
+    }
+
+    /**
+     * 获取Banner列表
+     */
+    @PostMapping("/getBanners")
+    public Result<?> getBanners() {
+        List<BannerInfo> banners = bannerInfoService.lambdaQuery()
+                .eq(BannerInfo::getStatus, 1)
+                .orderByAsc(BannerInfo::getSort)
+                .list();
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("banners", banners);
+        return Result.success(result);
+    }
+
+    /**
+     * 获取广告位
+     */
+    @PostMapping("/getAdvertising")
+    public Result<?> getAdvertising() {
+        List<Advertising> banners = advertisingService.lambdaQuery()
+                .eq(Advertising::getStatus, 1)
+                .orderByAsc(Advertising::getSort)
+                .list();
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("banners", banners);
+        return Result.success(result);
+    }
+
+    /**
+     * 新增用户反馈
+     */
+    @PostMapping("/addUserFeedback")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<?> addUserFeedback(@RequestBody UserFeedback data, HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        data.setUserId(cacheUser.getId());
+        boolean saved = userFeedbackService.save(data);
+        if (!saved) {
+            return Result.failed("提交失败");
+        }
+
+        return Result.success();
+    }
+
+    /**
+     * 查看用户反馈
+     */
+    @PostMapping("/getMyFeekBack")
+    public Result<?> getMyFeekBack(HttpServletRequest request) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        List<UserFeedback> list = userFeedbackService.lambdaQuery()
+                .eq(UserFeedback::getUserId, cacheUser.getId())
+                .orderByDesc(UserFeedback::getCreateTime)
+                .list();
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("list", list);
+        return Result.success(result);
+    }
+
+    /**
+     * 上传文件
+     */
+    @PostMapping("/upFile")
+    public Result<?> upFile(@RequestParam("file") MultipartFile file) {
+        try {
+            // TODO: 实现文件上传逻辑,使用ossProperties配置
+            String fileUrl = "/uploads/" + file.getOriginalFilename();
+            Map<String, Object> result = new HashMap<>();
+            result.put("fileUrl", fileUrl);
+            return Result.success(result);
+        } catch (Exception e) {
+            log.error("文件上传失败", e);
+            return Result.failed("文件上传失败");
+        }
+    }
+
+    /**
+     * 获取邀请员工的二维码
+     */
+    @GetMapping("/get-invite-qr")
+    public void getInviteQr(HttpServletRequest request, HttpServletResponse response) {
+        try {
+            UserInfo cacheUser = getUserFromToken(request);
+            if (cacheUser == null) {
+                return;
+            }
+
+            UserFirm firm = userFirmService.lambdaQuery()
+                    .eq(UserFirm::getUserId, cacheUser.getId())
+                    .one();
+            if (ObjectUtil.isEmpty(firm)) {
+                return;
+            }
+
+            if (firm.getUserType() == 2) {
+                return;
+            }
+
+            String content = "https://cd.api.zswlgz.com/deviceid?frimId=" + firm.getFirmId();
+            QrCodeUtil.generate(content, 300, 300, ImgUtil.IMAGE_TYPE_PNG, response.getOutputStream());
+        } catch (Exception e) {
+            log.error("生成二维码失败", e);
+        }
+    }
+
+    /**
+     * 邀请员工加入企业
+     */
+    @PostMapping("/add-firm-user")
+    public Result<?> addFirmUser(HttpServletRequest request, @RequestParam("firmId") Long firmId) {
+        UserInfo cacheUser = getUserFromToken(request);
+        if (cacheUser == null) {
+            return Result.failed("登录已过期");
+        }
+
+        UserFirm userFirm = new UserFirm();
+        userFirm.setUserId(cacheUser.getId());
+        userFirm.setFirmId(firmId);
+        userFirm.setUserType(2L);
+
+        try {
+            boolean saved = userFirmService.save(userFirm);
+            if (saved) {
+                FirmInfo firmInfo = firmInfoService.getById(firmId);
+                return Result.success("你已经成功加入" + firmInfo.getName() + ",现在充电享受企业专享价");
+            }
+        } catch (Exception e) {
+            return Result.failed(e.getMessage());
+        }
+
+        return Result.failed("加入失败");
+    }
+
+    /**
+     * 从请求头获取token并从缓存中获取用户信息
+     */
+    private UserInfo getUserFromToken(HttpServletRequest request) {
+        String token = request.getHeader("token");
+        if (token == null) {
+            return null;
+        }
+
+        Object obj = redisTemplate.opsForValue().get(TOKEN_PREFIX + token);
+        if (obj instanceof UserInfo) {
+            // 刷新token过期时间
+            redisTemplate.expire(TOKEN_PREFIX + token, 30, TimeUnit.MINUTES);
+            return (UserInfo) obj;
+        }
+        return null;
+    }
+
+    /**
+     * 保存用户信息到缓存
+     */
+    private void saveUserToCache(String token, UserInfo userInfo) {
+        redisTemplate.opsForValue().set(TOKEN_PREFIX + token, userInfo, 30, TimeUnit.MINUTES);
+    }
+}

+ 13 - 0
src/main/java/com/zsElectric/boot/app/model/entity/ChargeStation.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -23,11 +24,23 @@ public class ChargeStation extends BaseEntity {
      */
     private String name;
 
+    /**
+     * 充电站名称(字段别名)
+     */
+    @TableField("name")
+    private String stationName;
+
     /**
      * 充电站地址
      */
     private String addr;
 
+    /**
+     * 充电站地址(字段别名)
+     */
+    @TableField("addr")
+    private String address;
+
     /**
      * 图片1
      */

+ 50 - 0
src/main/java/com/zsElectric/boot/app/model/entity/FirmStationTimePrice.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -53,6 +54,55 @@ public class FirmStationTimePrice extends BaseEntity {
      */
     private Long status;
 
+    /**
+     * 时间段(HH:mm-HH:mm)
+     */
+    @TableField(exist = false)
+    private String time;
+
+    /**
+     * 企业专享价(电费+服务费)
+     */
+    @TableField(exist = false)
+    private BigDecimal firmPrice;
+
+    /**
+     * 获取时间段
+     */
+    public String getTime() {
+        if (startTime != null && endTime != null) {
+            return startTime + "-" + endTime;
+        }
+        return time;
+    }
+
+    public void setTime(String time) {
+        this.time = time;
+        if (time != null && time.contains("-")) {
+            String[] parts = time.split("-");
+            if (parts.length == 2) {
+                this.startTime = parts[0].trim();
+                this.endTime = parts[1].trim();
+            }
+        }
+    }
+
+    /**
+     * 获取企业专享价
+     */
+    public BigDecimal getFirmPrice() {
+        if (elecPrice == null && servicePrice == null) {
+            return firmPrice != null ? firmPrice : BigDecimal.ZERO;
+        }
+        BigDecimal elec = elecPrice != null ? elecPrice : BigDecimal.ZERO;
+        BigDecimal service = servicePrice != null ? servicePrice : BigDecimal.ZERO;
+        return elec.add(service);
+    }
+
+    public void setFirmPrice(BigDecimal firmPrice) {
+        this.firmPrice = firmPrice;
+    }
+
     /**
      * 创建人ID
      */

+ 11 - 0
src/main/java/com/zsElectric/boot/app/model/entity/NewUserDiscount.java

@@ -6,6 +6,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 
 /**
  * 新用户优惠实体
@@ -38,6 +39,16 @@ public class NewUserDiscount extends BaseEntity {
      */
     private Long status;
 
+    /**
+     * 开始时间
+     */
+    private LocalDateTime beginTime;
+
+    /**
+     * 结束时间
+     */
+    private LocalDateTime endTime;
+
     /**
      * 备注
      */

+ 38 - 0
src/main/java/com/zsElectric/boot/app/model/entity/RechargeLevel.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -43,6 +44,43 @@ public class RechargeLevel extends BaseEntity {
      */
     private Long status;
 
+    /**
+     * 档位状态:0禁用 1启用(字段别名)
+     */
+    @TableField(exist = false)
+    private Long levelStatus;
+
+    /**
+     * 档位总金额(充值+赠送)
+     */
+    @TableField(exist = false)
+    private BigDecimal levelMoney;
+
+    /**
+     * 计算档位总金额
+     */
+    public Long getLevelStatus() {
+        return status;
+    }
+
+    public void setLevelStatus(Long levelStatus) {
+        this.status = levelStatus;
+    }
+
+    public BigDecimal getLevelMoney() {
+        if (rechargeMoney == null) {
+            return giveMoney != null ? giveMoney : BigDecimal.ZERO;
+        }
+        if (giveMoney == null) {
+            return rechargeMoney;
+        }
+        return rechargeMoney.add(giveMoney);
+    }
+
+    public void setLevelMoney(BigDecimal levelMoney) {
+        this.levelMoney = levelMoney;
+    }
+
     /**
      * 创建人ID
      */

+ 55 - 0
src/main/java/com/zsElectric/boot/app/model/entity/StationTimePrice.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -48,6 +49,60 @@ public class StationTimePrice extends BaseEntity {
      */
     private Long status;
 
+    /**
+     * 时间段(HH:mm-HH:mm)
+     */
+    @TableField(exist = false)
+    private String time;
+
+    /**
+     * 时间段类型:1谷 2平 3峰
+     */
+    private Integer timeType;
+
+    /**
+     * 总价格(电费+服务费)
+     */
+    @TableField(exist = false)
+    private BigDecimal price;
+
+    /**
+     * 获取时间段
+     */
+    public String getTime() {
+        if (startTime != null && endTime != null) {
+            return startTime + "-" + endTime;
+        }
+        return time;
+    }
+
+    public void setTime(String time) {
+        this.time = time;
+        if (time != null && time.contains("-")) {
+            String[] parts = time.split("-");
+            if (parts.length == 2) {
+                this.startTime = parts[0].trim();
+                this.endTime = parts[1].trim();
+            }
+        }
+    }
+
+    /**
+     * 获取总价格
+     */
+    public BigDecimal getPrice() {
+        if (elecPrice == null && servicePrice == null) {
+            return price != null ? price : BigDecimal.ZERO;
+        }
+        BigDecimal elec = elecPrice != null ? elecPrice : BigDecimal.ZERO;
+        BigDecimal service = servicePrice != null ? servicePrice : BigDecimal.ZERO;
+        return elec.add(service);
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
     /**
      * 创建人ID
      */

+ 10 - 0
src/main/java/com/zsElectric/boot/app/model/entity/ThirdPartyInfo.java

@@ -46,6 +46,16 @@ public class ThirdPartyInfo extends BaseEntity {
      */
     private Long status;
 
+    /**
+     * 应用ID
+     */
+    private String appId;
+
+    /**
+     * 认证密钥
+     */
+    private String authCode;
+
     /**
      * 备注
      */

+ 7 - 0
src/main/java/com/zsElectric/boot/app/model/entity/UserInfo.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -73,6 +74,12 @@ public class UserInfo extends BaseEntity {
      */
     private BigDecimal amountOwed;
 
+    /**
+     * 所属企业名称(临时字段,不存储到数据库)
+     */
+    @TableField(exist = false)
+    private String firmInfoName;
+
     /**
      * 创建人ID
      */

+ 42 - 0
src/main/java/com/zsElectric/boot/app/model/entity/UserOrderInfo.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.app.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.zsElectric.boot.common.base.BaseEntity;
 import lombok.Getter;
@@ -63,6 +64,47 @@ public class UserOrderInfo extends BaseEntity {
      */
     private String payTime;
 
+    /**
+     * 订单状态:1待支付 2已支付 3已取消
+     */
+    private Integer orderStatus;
+
+    /**
+     * 充值档位ID
+     */
+    private Long levelId;
+
+    /**
+     * 订单类型:1个人充值 2第三方充值
+     */
+    private Integer orderType;
+
+    /**
+     * 第三方应用ID
+     */
+    private String appId;
+
+    /**
+     * 第三方订单号
+     */
+    private String outTradeNo;
+
+    /**
+     * 剩余金额
+     */
+    private BigDecimal lastMoney;
+
+    /**
+     * 关联的充电订单ID
+     */
+    private Long chargeOrderId;
+
+    /**
+     * 欠款金额(临时字段)
+     */
+    @TableField(exist = false)
+    private BigDecimal ztBackMoney;
+
     /**
      * 创建人ID
      */