puzhibing
2026-09-29 a70433b2ee5bb37823ab73422a01251343cb5f58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package com.ruoyi.account.controller;
 
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.account.api.dto.ChargingCardAllocateDTO;
import com.ruoyi.account.api.dto.ChargingCardAuthDTO;
import com.ruoyi.account.api.dto.ChargingCardDeductDTO;
import com.ruoyi.account.api.dto.ChargingCardExcelDTO;
import com.ruoyi.account.api.dto.ChargingCardQueryDTO;
import com.ruoyi.account.api.dto.ChargingCardSaveDTO;
import com.ruoyi.account.api.dto.ChargingCardStatusDTO;
import com.ruoyi.account.api.model.TChargingCard;
import com.ruoyi.account.api.vo.ChargingCardAllocateVO;
import com.ruoyi.account.api.vo.ChargingCardDeductVO;
import com.ruoyi.account.service.TChargingCardService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.security.annotation.Logical;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
 
@Api(tags = "卡片管理")
@RestController
@RequestMapping("/t-charging-card")
public class TChargingCardController extends BaseController {
 
    @Autowired
    private TChargingCardService chargingCardService;
 
    @ApiOperation(value = "分页查询卡片列表")
    @RequiresPermissions(value = {"/chargingCard/list"}, logical = Logical.OR)
    @PostMapping("/page")
    public R<IPage<TChargingCard>> page(@RequestBody ChargingCardQueryDTO query) {
        return R.ok(chargingCardService.selectCardPage(query));
    }
 
    @ApiOperation(value = "新增卡片")
    @RequiresPermissions(value = {"/chargingCard/add"}, logical = Logical.OR)
    @PostMapping
    public R<Boolean> add(@RequestBody ChargingCardSaveDTO dto) {
        return R.ok(chargingCardService.saveCard(dto));
    }
 
    @ApiOperation(value = "编辑卡片")
    @RequiresPermissions(value = {"/chargingCard/edit"}, logical = Logical.OR)
    @PutMapping
    public R<Boolean> edit(@RequestBody ChargingCardSaveDTO dto) {
        return R.ok(chargingCardService.updateCard(dto));
    }
 
    @ApiOperation(value = "删除卡片")
    @RequiresPermissions(value = {"/chargingCard/delete"}, logical = Logical.OR)
    @DeleteMapping
    public R<Boolean> delete(@RequestBody List<Long> ids) {
        return R.ok(chargingCardService.deleteCards(ids));
    }
 
    @ApiOperation(value = "批量解绑车队(清空卡片车队归属,返回实际解绑数量)")
    @RequiresPermissions(value = {"/chargingCard/unbind"}, logical = Logical.OR)
    @PutMapping("/unbind-fleet")
    public R<Integer> unbindFleet(@RequestBody List<Long> ids) {
        return R.ok(chargingCardService.unbindFleet(ids));
    }
 
    @ApiOperation(value = "更新卡片启用状态")
    @RequiresPermissions(value = {"/chargingCard/status"}, logical = Logical.OR)
    @PutMapping("/status")
    public R<Boolean> status(@RequestBody ChargingCardStatusDTO dto) {
        return R.ok(chargingCardService.updateStatus(dto));
    }
 
    @ApiOperation(value = "额度分配概览(公司总账户余额、可分配余额)")
    @RequiresPermissions(value = {"/chargingCard/allocate"}, logical = Logical.OR)
    @GetMapping("/allocate-overview")
    public R<ChargingCardAllocateVO> allocateOverview(@RequestParam("companyId") Integer companyId) {
        return R.ok(chargingCardService.getAllocateOverview(companyId));
    }
 
    @ApiOperation(value = "卡片额度分配(公司可用余额划入卡片余额)")
    @RequiresPermissions(value = {"/chargingCard/allocate"}, logical = Logical.OR)
    @PostMapping("/allocate")
    public R<ChargingCardAllocateVO> allocate(@RequestBody ChargingCardAllocateDTO dto) {
        return R.ok(chargingCardService.allocateQuota(dto));
    }
 
    @ApiOperation(value = "导出卡片")
    @RequiresPermissions(value = {"/chargingCard/export"}, logical = Logical.OR)
    @PutMapping("/export")
    public void export(HttpServletResponse response, @RequestBody ChargingCardQueryDTO query) {
        ExcelUtil<ChargingCardExcelDTO> util = new ExcelUtil<>(ChargingCardExcelDTO.class);
        util.exportExcel(response, chargingCardService.selectExportList(query), "卡片数据");
    }
 
    @ApiOperation(value = "下载卡片导入模板")
    @RequiresPermissions(value = {"/chargingCard/import"}, logical = Logical.OR)
    @GetMapping("/import-template")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<ChargingCardExcelDTO> util = new ExcelUtil<>(ChargingCardExcelDTO.class);
        util.importTemplateExcel(response, "卡片数据");
    }
 
    @ApiOperation(value = "导入卡片")
    @RequiresPermissions(value = {"/chargingCard/import"}, logical = Logical.OR)
    @PostMapping("/import")
    public R<String> importData(@RequestPart("file") MultipartFile file) throws Exception {
        ExcelUtil<ChargingCardExcelDTO> util = new ExcelUtil<>(ChargingCardExcelDTO.class);
        List<ChargingCardExcelDTO> cards = util.importExcel(file.getInputStream());
        return R.ok(chargingCardService.importCards(cards));
    }
 
    // ==================== 内部接口(刷卡充电链路,订单服务调用,V0.2 定稿) ====================
 
    @ApiOperation(value = "刷卡启动鉴权(内部):卡片配置密码时才校验密码")
    @PostMapping("/inner/verify-charging")
    public R<TChargingCard> verifyCharging(@RequestBody ChargingCardAuthDTO dto) {
        return R.ok(chargingCardService.verifyCardForCharging(dto));
    }
 
    @ApiOperation(value = "锁定卡片为充电中(内部):返回 false 表示同卡已有进行中订单")
    @PostMapping("/inner/lock-charging")
    public R<Boolean> lockForCharging(@RequestParam("cardId") Long cardId,
                                      @RequestParam("orderCode") String orderCode) {
        return R.ok(chargingCardService.lockCardForCharging(cardId, orderCode));
    }
 
    @ApiOperation(value = "解锁卡片(内部):订单终态后调用,带订单号比对")
    @PostMapping("/inner/unlock-charging")
    public R<Boolean> unlockForCharging(@RequestParam("cardId") Long cardId,
                                        @RequestParam("orderCode") String orderCode) {
        return R.ok(chargingCardService.unlockCardForCharging(cardId, orderCode));
    }
 
    @ApiOperation(value = "刷卡订单结算扣款(内部):订单号幂等、允许扣成负余额")
    @PostMapping("/inner/deduct-charging")
    public R<ChargingCardDeductVO> deductForCharging(@RequestBody ChargingCardDeductDTO dto) {
        return R.ok(chargingCardService.deductBalanceForCharging(dto));
    }
 
    @ApiOperation(value = "批量查询已存在充电扣款流水的订单号(内部)")
    @PostMapping("/inner/deducted-order-codes")
    public R<List<String>> listDeductedOrderCodes(@RequestBody List<String> orderCodes) {
        return R.ok(chargingCardService.listDeductedOrderCodes(orderCodes));
    }
 
    @ApiOperation(value = "按公司查询卡片列表(内部):公司详情-充电用户信息聚合使用")
    @GetMapping("/inner/list-by-company")
    public R<List<TChargingCard>> listByCompany(@RequestParam("companyId") Integer companyId) {
        return R.ok(chargingCardService.listByCompany(companyId));
    }
 
    @ApiOperation(value = "锁定卡片账户余额(内部):刷卡充电申请实扣冻结,余额不足返回失败")
    @PostMapping("/inner/lock-balance")
    public R<BigDecimal> lockBalance(@RequestParam("cardId") Long cardId,
                                     @RequestParam("amount") BigDecimal amount) {
        try {
            return R.ok(chargingCardService.lockBalance(cardId, amount));
        } catch (RuntimeException ex) {
            return R.fail(ex.getMessage());
        }
    }
 
    @ApiOperation(value = "结算卡片账户余额(内部):解锁锁定额并按实扣扣减,订单号幂等")
    @PostMapping("/inner/settle-charging")
    public R<ChargingCardDeductVO> settleForCharging(@RequestBody ChargingCardDeductDTO dto) {
        return R.ok(chargingCardService.settleBalanceForCharging(dto));
    }
 
    @ApiOperation(value = "释放卡片锁定金额(内部):未产生消费/订单回滚时使用")
    @PostMapping("/inner/unlock-balance")
    public R<BigDecimal> unlockBalance(@RequestParam("cardId") Long cardId,
                                       @RequestParam("amount") BigDecimal amount) {
        try {
            return R.ok(chargingCardService.unlockBalance(cardId, amount));
        } catch (RuntimeException ex) {
            return R.fail(ex.getMessage());
        }
    }
}