Prechádzať zdrojové kódy

金牛:ipad审核功能

dengweize 1 týždeň pred
rodič
commit
d921978c54

+ 326 - 0
fs-admin/src/main/java/com/fs/qw/controller/IpadAllocationRecordsController.java

@@ -0,0 +1,326 @@
+package com.fs.qw.controller;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.IpadAllocationDetails;
+import com.fs.qw.domain.IpadAllocationRecords;
+import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.mapper.IpadAllocationRecordsMapper;
+import com.fs.qw.param.ServerParam;
+import com.fs.qw.service.IIpadAllocationRecordsService;
+import com.fs.qw.service.IQwIpadServerService;
+import com.fs.qw.utils.HMACAuth;
+import com.fs.qw.vo.IpadAllocationRecordsVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 分配记录Controller
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@RestController
+@RequestMapping("/qw/records")
+@Slf4j
+public class IpadAllocationRecordsController extends BaseController {
+    @Autowired
+    private IIpadAllocationRecordsService ipadAllocationRecordsService;
+    @Autowired
+    private IQwIpadServerService serverService;
+
+
+    @Autowired
+    private IpadAllocationRecordsMapper ipadAllocationRecordsMapper;
+    @Value("${ipad.url}")
+    private String ipadServerUrl;
+
+    /**
+     * 查询分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(IpadAllocationRecords ipadAllocationRecords) {
+        startPage();
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:export')")
+    @Log(title = "分配记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IpadAllocationRecords ipadAllocationRecords) {
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        ExcelUtil<IpadAllocationRecords> util = new ExcelUtil<IpadAllocationRecords>(IpadAllocationRecords.class);
+        return util.exportExcel(list, "分配记录数据");
+    }
+
+    /**
+     * 获取分配记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(ipadAllocationRecordsService.selectIpadAllocationRecordsById(id));
+    }
+
+    /**
+     * 新增分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:add')")
+    @Log(title = "分配记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.insertIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 修改分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:edit')")
+    @Log(title = "分配记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.updateIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 删除分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:remove')")
+    @Log(title = "分配记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(ipadAllocationRecordsService.deleteIpadAllocationRecordsByIds(ids));
+    }
+
+    //根据记录id查询他的服务器详情
+    @GetMapping("/server/{id}")
+    public AjaxResult getServerInfo(@PathVariable("id") Long id) {
+        IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsService.selectIpadAllocationRecordsById(id);
+        if (ipadAllocationRecords == null) {
+            return AjaxResult.error("记录不存在");
+        }
+        List<IpadAllocationDetails> detailsList = JSON.parseArray(ipadAllocationRecords.getServerJson(), IpadAllocationDetails.class);
+        return AjaxResult.success(detailsList);
+    }
+
+    @Value("${ipad.companyId:13}")
+    private Long companyId;
+    //发起申请ipad服务器
+    @GetMapping("/apply")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult apply(Integer applyCount,String area) throws Exception {
+        //校验count是否为正整数
+        if (applyCount == null || applyCount <= 0) {
+            return AjaxResult.error("申请数量必须为正整数");
+        }
+        //校验area是否为空
+        if (area == null || area.isEmpty()) {
+            return AjaxResult.error("区域不能为空");
+        }
+
+        //插入数据库申请表
+        IpadAllocationRecords ipadAllocationRecords = new IpadAllocationRecords();
+        ipadAllocationRecords.setCompanyId(13L);
+        ipadAllocationRecords.setApplyQuantity(applyCount);
+        ipadAllocationRecords.setSubmitTime(LocalDateTime.now());
+        ipadAllocationRecords.setRegion(area);
+        ipadAllocationRecordsMapper.insert(ipadAllocationRecords);
+        //发起http请求
+        //调用ipad服务器申请接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("allocationId", ipadAllocationRecords.getId());//携带id过去,以后查询结果
+        param.put("companyId", companyId);//公司id自己去配置文件改自己公司的id去腕表找
+        param.put("region", area);//区域
+        param.put("applyQuantity", applyCount);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/addRecords");
+        log.info("发起请求,申请参数:{},url:{}", paramJson, ipadServerUrl + "/ipad/records/addRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器申请,申请数量:{},申请id:{},申请结果:{}", applyCount, ipadAllocationRecords.getId(), result);
+        //code不为200,回滚数据库
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+        if (response == null || (Integer) response.get("code") != 200) {
+            ipadAllocationRecordsMapper.deleteById(ipadAllocationRecords.getId());
+            throw new Exception("申请失败");
+        }
+        return AjaxResult.success("申请成功");
+    }
+
+    //批量更新分配记录状态
+    @PostMapping("/batchUpdate")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult batchUpdate(@RequestBody Long[] ids) throws Exception {
+        //校验ids是否为空
+        if (ids == null || ids.length == 0) {
+            return AjaxResult.error("ids不能为空");
+        }
+        //发起http请求
+        //调用ipad服务器更新接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("ids", ids);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/updateRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+
+        log.info("发起ipad服务器更新状态,更新数量:{},拉取结果:{}", ids.length, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200
+        if (response != null && (Integer) response.get("code") == 200) {
+            //获取data字段
+            Object data = response.get("data");
+
+            //将data转换为List<IpadAllocationRecordsVO>
+            List<IpadAllocationRecordsVO> recordsList = JSON.parseArray(JSON.toJSONString(data), IpadAllocationRecordsVO.class);
+
+            for (IpadAllocationRecordsVO vo : recordsList) {
+                IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsMapper.selectById(vo.getId());
+                if (!ipadAllocationRecords.getAuditStatus().equals(0)) {
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                    log.info("分配记录id:{},状态已更新,无需重复更新", vo.getId());
+                    continue;
+                }
+                log.info("更新分配记录,记录id:{},更新状态:{},分配数量:{},审核时间:{},拒绝原因:{},公司名称:{}",
+                        vo.getId(), vo.getAuditStatus(), vo.getAllocatedQuantity(), vo.getReviewTime(), vo.getRejectionReason(), vo.getCompanyName());
+                if (ipadAllocationRecords != null) {
+                    ipadAllocationRecords.setAuditStatus(vo.getAuditStatus());
+                    ipadAllocationRecords.setUpdatedTime(LocalDateTime.now());
+                    ipadAllocationRecords.setAllocatedQuantity(vo.getAllocatedQuantity());
+                    ipadAllocationRecords.setReviewTime(vo.getReviewTime());
+                    ipadAllocationRecords.setRejectionReason(vo.getRejectionReason());
+                    ipadAllocationRecords.setCompanyName(vo.getCompanyName());
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecords.setRegion(vo.getRegion());
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                }
+                List<IpadAllocationDetails> detailsList = vo.getDetailsList();
+                for (IpadAllocationDetails details : detailsList) {
+                    //去查询是否有相同端口和ip的服务器,有则去更新total_count和count都加上allocatedSeats,没有则添加一条服务器记录。
+                    Integer allocatedSeats = details.getAllocatedSeats();
+                    QwIpadServer server = serverService.selectIpAndPort(details.getIpAddress(), details.getPort());
+                    if (server != null) {
+                        server.setTotalCount(server.getTotalCount() + allocatedSeats);
+                        server.setCount(server.getCount() + allocatedSeats);
+                        server.setUpdateTime(DateUtils.getNowDate());
+//                        server.setRecordId(details.getAllocationId());//后面的审核记录会覆盖之前的审核记录id,这里存的是最新的审核记录id
+                        serverService.updateById(server);
+                    } else {
+                        //添加一条服务器记录
+                        QwIpadServer newServer = new QwIpadServer();
+//                        newServer.setRecordId(details.getAllocationId());
+                        newServer.setIp(details.getIpAddress());
+                        newServer.setPort(String.valueOf(details.getPort()));
+                        newServer.setTotalCount(Long.valueOf(allocatedSeats));
+                        newServer.setCount(Long.valueOf(allocatedSeats));
+                        newServer.setAddressId("520000000000");
+                        newServer.setUrl(details.getAccessUrl());
+                        newServer.setCreateTime(DateUtils.getNowDate());
+                        serverService.getBaseMapper().insert(newServer);
+                    }
+                }
+            }
+
+            //返回成功结果
+            return AjaxResult.success("更新成功", recordsList);
+        } else {
+            //返回错误结果
+            String errorMsg = response != null ? (String) response.get("msg") : "更新失败";
+            return AjaxResult.error(errorMsg);
+        }
+    }
+
+    //释放已申请的ipad服务器
+    //释放哪条记录的那台服务器多少台
+    @PostMapping("/release")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult release(@RequestBody ServerParam serverParam) throws Exception {
+        //校验参数是否为空
+        if (serverParam == null) {
+            return AjaxResult.error("serverParam不能为空");
+        }
+
+        QwIpadServer server = serverService.selectIpAndPort(serverParam.getIpAddress(), Long.valueOf(serverParam.getPort()));
+        if (server == null) {
+            log.info("服务器地址:{},端口:{},未查询到服务器记录,无法释放", serverParam.getIpAddress(), serverParam.getPort());
+            return AjaxResult.error("未查询到服务器记录,无法释放");
+        }
+        if (serverParam.getReleaseCount() > server.getCount()) {
+            log.info("服务器id:{},释放数量:{},剩余数量:{},释放数量大于剩余数量,无法释放", server.getId(), serverParam.getReleaseCount(), server.getCount());
+            return AjaxResult.error("释放数量大于剩余数量,无法释放");
+        }
+        IpadAllocationRecords record = ipadAllocationRecordsMapper.selectById(serverParam.getRecordId());
+        if (record == null) {
+            log.info("服务器id:{},释放数量:{},申请记录为空,无法释放", server.getId(), serverParam.getReleaseCount());
+            return AjaxResult.error("申请记录为空,无法释放");
+        }
+        record.setAllocatedQuantity(record.getAllocatedQuantity() - serverParam.getReleaseCount());
+//        record.setApplyQuantity(record.getApplyQuantity() - serverParam.getReleaseCount());
+
+        server.setCount(server.getCount() - serverParam.getReleaseCount());
+        server.setTotalCount(server.getTotalCount() - serverParam.getReleaseCount());
+        ipadAllocationRecordsMapper.updateById(record);
+        serverService.updateById(server);
+
+        ServerParam build = ServerParam.builder()
+                .ipadServerId(serverParam.getIpadServerId())
+                .recordId(serverParam.getRecordId())
+                .releaseCount(serverParam.getReleaseCount())
+                .ipAddress(serverParam.getIpAddress())
+                .port(serverParam.getPort())
+                .build();
+
+        //发起http请求
+        String body = JSON.toJSONString(build);
+
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/release");
+        post.body(body);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器释放状态,释放数量:{},拉取结果:{}", body, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200,不是回滚事务
+        if (!response.get("code").equals(200)) {
+            String errorMsg = response != null ? (String) response.get("msg") : "释放失败";
+            throw new Exception(errorMsg);
+        }
+        return AjaxResult.success("释放成功");
+    }
+}

+ 72 - 0
fs-service/src/main/java/com/fs/qw/domain/IpadAllocationDetails.java

@@ -0,0 +1,72 @@
+package com.fs.qw.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 分配记录详情对象 ipad_allocation_details
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+@Data
+public class IpadAllocationDetails
+{
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    /** 记录ID */
+    private Long id;
+
+    /** 分配记录ID */
+    @Excel(name = "分配记录ID")
+    private Long allocationId;
+
+    /** IPAD记录ID */
+    @Excel(name = "IPAD记录ID")
+    private Long ipadRecordId;
+
+    /** IP地址 */
+    @Excel(name = "IP地址")
+    private String ipAddress;
+
+    /** 端口号 */
+    @Excel(name = "端口号")
+    private Long port;
+
+    /** 访问地址 */
+    @Excel(name = "访问地址")
+    private String accessUrl;
+
+    /** 地区 */
+    @Excel(name = "地区")
+    private String region;
+
+    /** 分配坐席数量 */
+    @Excel(name = "分配坐席数量")
+    private Integer allocatedSeats;
+
+    /** 分配状态: 1-有效, 0-已释放 */
+    @Excel(name = "分配状态: 1-有效, 0-已释放")
+    private Long allocationStatus;
+
+    /** 分配时间 */
+//    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "分配时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private LocalDateTime allocatedTime;
+
+    /** 释放时间 */
+//    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "释放时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private LocalDateTime releaseTime;
+
+    /** 创建时间 */
+//    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private LocalDateTime createdTime;
+
+}

+ 61 - 0
fs-service/src/main/java/com/fs/qw/domain/IpadAllocationRecords.java

@@ -0,0 +1,61 @@
+package com.fs.qw.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 分配记录对象 ipad_allocation_records
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@Data
+public class IpadAllocationRecords {
+
+    /** 主键ID */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 申请公司ID */
+    @Excel(name = "申请公司ID")
+    private Long companyId;
+
+    /** 申请公司名字 */
+    @Excel(name = "申请公司名字")
+    private String companyName;
+
+
+    /** 申请数量 */
+    @Excel(name = "申请数量")
+    private Integer applyQuantity;
+
+    /** 实际分配数量 */
+    @Excel(name = "实际分配数量")
+    private Integer allocatedQuantity;
+
+
+    private LocalDateTime submitTime;
+
+
+    private LocalDateTime reviewTime;
+
+    private Integer auditStatus;
+
+    /** 拒绝原因 */
+    @Excel(name = "拒绝原因")
+    private String rejectionReason;
+
+
+    private LocalDateTime createdTime;
+
+
+    private LocalDateTime updatedTime;
+
+    private String serverJson;
+
+    private String region;
+}

+ 63 - 0
fs-service/src/main/java/com/fs/qw/mapper/IpadAllocationRecordsMapper.java

@@ -0,0 +1,63 @@
+package com.fs.qw.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.qw.domain.IpadAllocationRecords;
+
+import java.util.List;
+
+/**
+ * 分配记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+public interface IpadAllocationRecordsMapper extends BaseMapper<IpadAllocationRecords>{
+    /**
+     * 查询分配记录
+     *
+     * @param id 分配记录主键
+     * @return 分配记录
+     */
+    IpadAllocationRecords selectIpadAllocationRecordsById(Long id);
+
+    /**
+     * 查询分配记录列表
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 分配记录集合
+     */
+    List<IpadAllocationRecords> selectIpadAllocationRecordsList(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 新增分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    int insertIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 修改分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    int updateIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 删除分配记录
+     *
+     * @param id 分配记录主键
+     * @return 结果
+     */
+    int deleteIpadAllocationRecordsById(Long id);
+
+    /**
+     * 批量删除分配记录
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteIpadAllocationRecordsByIds(Long[] ids);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwIpadServerMapper.java

@@ -2,6 +2,7 @@ package com.fs.qw.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.qw.domain.QwIpadServer;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
@@ -74,4 +75,5 @@ public interface QwIpadServerMapper extends BaseMapper<QwIpadServer>{
     @Select("select sum(qis.total_count) as total_count ,sum(qis.count) as count from qw_ipad_server qis")
     QwIpadServer getPadInfo();
 
+    QwIpadServer selectIpAndPort(@Param("ipAddress") String ipAddress, @Param("port") Long port);
 }

+ 18 - 0
fs-service/src/main/java/com/fs/qw/param/ServerParam.java

@@ -0,0 +1,18 @@
+package com.fs.qw.param;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ServerParam {
+    private Long ipadServerId;
+    private Long recordId;
+    private Integer releaseCount;
+    private String ipAddress;
+    private String port;
+}

+ 62 - 0
fs-service/src/main/java/com/fs/qw/service/IIpadAllocationRecordsService.java

@@ -0,0 +1,62 @@
+package com.fs.qw.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.qw.domain.IpadAllocationRecords;
+
+import java.util.List;
+
+/**
+ * 分配记录Service接口
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+public interface IIpadAllocationRecordsService extends IService<IpadAllocationRecords> {
+    /**
+     * 查询分配记录
+     *
+     * @param id 分配记录主键
+     * @return 分配记录
+     */
+    IpadAllocationRecords selectIpadAllocationRecordsById(Long id);
+
+    /**
+     * 查询分配记录列表
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 分配记录集合
+     */
+    List<IpadAllocationRecords> selectIpadAllocationRecordsList(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 新增分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    int insertIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 修改分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    int updateIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords);
+
+    /**
+     * 批量删除分配记录
+     *
+     * @param ids 需要删除的分配记录主键集合
+     * @return 结果
+     */
+    int deleteIpadAllocationRecordsByIds(Long[] ids);
+
+    /**
+     * 删除分配记录信息
+     *
+     * @param id 分配记录主键
+     * @return 结果
+     */
+    int deleteIpadAllocationRecordsById(Long id);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/qw/service/IQwIpadServerService.java

@@ -69,4 +69,6 @@ public interface IQwIpadServerService extends IService<QwIpadServer>{
     Long selectQwIpadServerByOtherAddressId();
 
     QwIpadServer getPadInfo();
+
+    QwIpadServer selectIpAndPort(String ipAddress, Long port);
 }

+ 92 - 0
fs-service/src/main/java/com/fs/qw/service/impl/IpadAllocationRecordsServiceImpl.java

@@ -0,0 +1,92 @@
+package com.fs.qw.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.qw.domain.IpadAllocationRecords;
+import com.fs.qw.mapper.IpadAllocationRecordsMapper;
+import com.fs.qw.service.IIpadAllocationRecordsService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+/**
+ * 分配记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@Service
+public class IpadAllocationRecordsServiceImpl extends ServiceImpl<IpadAllocationRecordsMapper, IpadAllocationRecords> implements IIpadAllocationRecordsService {
+
+    /**
+     * 查询分配记录
+     *
+     * @param id 分配记录主键
+     * @return 分配记录
+     */
+    @Override
+    public IpadAllocationRecords selectIpadAllocationRecordsById(Long id)
+    {
+        return baseMapper.selectIpadAllocationRecordsById(id);
+    }
+
+    /**
+     * 查询分配记录列表
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 分配记录
+     */
+    @Override
+    public List<IpadAllocationRecords> selectIpadAllocationRecordsList(IpadAllocationRecords ipadAllocationRecords)
+    {
+        return baseMapper.selectIpadAllocationRecordsList(ipadAllocationRecords);
+    }
+
+    /**
+     * 新增分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    @Override
+    public int insertIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords)
+    {
+        return baseMapper.insertIpadAllocationRecords(ipadAllocationRecords);
+    }
+
+    /**
+     * 修改分配记录
+     *
+     * @param ipadAllocationRecords 分配记录
+     * @return 结果
+     */
+    @Override
+    public int updateIpadAllocationRecords(IpadAllocationRecords ipadAllocationRecords)
+    {
+        return baseMapper.updateIpadAllocationRecords(ipadAllocationRecords);
+    }
+
+    /**
+     * 批量删除分配记录
+     *
+     * @param ids 需要删除的分配记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteIpadAllocationRecordsByIds(Long[] ids)
+    {
+        return baseMapper.deleteIpadAllocationRecordsByIds(ids);
+    }
+
+    /**
+     * 删除分配记录信息
+     *
+     * @param id 分配记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteIpadAllocationRecordsById(Long id)
+    {
+        return baseMapper.deleteIpadAllocationRecordsById(id);
+    }
+}

+ 5 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwIpadServerServiceImpl.java

@@ -118,4 +118,9 @@ private QwIpadServerMapper qwIpadServerMapper;
     public QwIpadServer getPadInfo() {
         return qwIpadServerMapper.getPadInfo();
     }
+
+    @Override
+    public QwIpadServer selectIpAndPort(String ipAddress, Long port) {
+        return qwIpadServerMapper.selectIpAndPort(ipAddress, port);
+    }
 }

+ 71 - 0
fs-service/src/main/java/com/fs/qw/utils/HMACAuth.java

@@ -0,0 +1,71 @@
+package com.fs.qw.utils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+public class HMACAuth {
+    private static final String SECRET_KEY = "ipad-secret-key-!#$";
+    private static final String ALGORITHM = "HmacSHA256";
+    // 设置token过期时间为5分钟(单位:毫秒)
+    private static final long TOKEN_EXPIRATION_TIME = 1 * 60 * 1000;
+
+    public static String generateToken() throws Exception {
+        String timestamp = String.valueOf(System.currentTimeMillis());
+        Mac mac = Mac.getInstance(ALGORITHM);
+        SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+        mac.init(keySpec);
+        byte[] signature = mac.doFinal(timestamp.getBytes());
+        return timestamp + ":" + Base64.getEncoder().encodeToString(signature);
+    }
+
+    public static void validateToken(String token) throws Exception {
+        try {
+            String[] parts = token.split(":");
+            if (parts.length != 2) throw new Exception("格式错误");
+
+            String timestamp = parts[0];
+            String receivedSignature = parts[1];
+
+            // 检查token是否过期
+            long tokenTime = Long.parseLong(timestamp);
+            long currentTime = System.currentTimeMillis();
+            if (currentTime - tokenTime > TOKEN_EXPIRATION_TIME) {
+                throw new Exception("Token已过期");
+            }
+
+            // 重新计算签名
+            Mac mac = Mac.getInstance(ALGORITHM);
+            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+            mac.init(keySpec);
+            byte[] expectedSignature = mac.doFinal(timestamp.getBytes());
+            String expected = Base64.getEncoder().encodeToString(expectedSignature);
+
+            if (!expected.equals(receivedSignature)) {
+                throw new Exception("签名校验失败");
+            }
+
+        } catch (NumberFormatException e) {
+            throw new Exception("Token格式错误");
+        } catch (Exception e) {
+            throw new Exception("Token校验失败");
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+            String token = generateToken();
+            // 测试有效的token
+            System.out.println("Generated Token: " + token);
+            validateToken(token);
+            System.out.println("Token is valid.");
+
+            // 测试过期的token
+            String expiredToken = "1763774896180:Rd4jyhRi6NyA7hfPanmxhSWXN+WxCaeKphvnODfakos=";
+            validateToken(expiredToken);
+            System.out.println("Expired token is valid.");
+        } catch (Exception e) {
+            System.out.println("Error: " + e.getMessage());
+        }
+    }
+}

+ 12 - 0
fs-service/src/main/java/com/fs/qw/vo/IpadAllocationRecordsVO.java

@@ -0,0 +1,12 @@
+package com.fs.qw.vo;
+
+import com.fs.qw.domain.IpadAllocationDetails;
+import com.fs.qw.domain.IpadAllocationRecords;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class IpadAllocationRecordsVO extends IpadAllocationRecords {
+    List<IpadAllocationDetails> detailsList;
+}

+ 3 - 0
fs-service/src/main/resources/application-druid-jnmy-test.yml

@@ -156,5 +156,8 @@ openIM:
 im:
     type: OPENIM
 isNewWxMerchant: true
+ipad:
+    url: http://localhost:8999/dev-api
+    companyId: 13
 
 

+ 3 - 0
fs-service/src/main/resources/application-druid-jnmy.yml

@@ -160,5 +160,8 @@ im:
     type: OPENIM
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: true
+ipad:
+    url: https://manwatch.ylrzcloud.com/prod-api
+    companyId: 13
 
 

+ 103 - 0
fs-service/src/main/resources/mapper/qw/IpadAllocationRecordsMapper.xml

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.qw.mapper.IpadAllocationRecordsMapper">
+
+    <resultMap type="IpadAllocationRecords" id="IpadAllocationRecordsResult">
+        <result property="id"    column="id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyName"    column="company_name"    />
+        <result property="applyQuantity"    column="apply_quantity"    />
+        <result property="allocatedQuantity"    column="allocated_quantity"    />
+        <result property="submitTime"    column="submit_time"    />
+        <result property="reviewTime"    column="review_time"    />
+        <result property="auditStatus"    column="audit_status"    />
+        <result property="rejectionReason"    column="rejection_reason"    />
+        <result property="createdTime"    column="created_time"    />
+        <result property="updatedTime"    column="updated_time"    />
+    </resultMap>
+
+    <sql id="selectIpadAllocationRecordsVo">
+        select id, company_id, company_name, apply_quantity, allocated_quantity, submit_time, review_time, audit_status, rejection_reason, created_time, updated_time, server_json from ipad_allocation_records
+    </sql>
+
+    <select id="selectIpadAllocationRecordsList" parameterType="IpadAllocationRecords" resultMap="IpadAllocationRecordsResult">
+        <include refid="selectIpadAllocationRecordsVo"/>
+        <where>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyName != null  and companyName != ''"> and company_name like concat('%', #{companyName}, '%')</if>
+            <if test="applyQuantity != null "> and apply_quantity = #{applyQuantity}</if>
+            <if test="allocatedQuantity != null "> and allocated_quantity = #{allocatedQuantity}</if>
+            <if test="submitTime != null "> and submit_time = #{submitTime}</if>
+            <if test="reviewTime != null "> and review_time = #{reviewTime}</if>
+            <if test="auditStatus != null "> and audit_status = #{auditStatus}</if>
+            <if test="rejectionReason != null  and rejectionReason != ''"> and rejection_reason = #{rejectionReason}</if>
+            <if test="createdTime != null "> and created_time = #{createdTime}</if>
+            <if test="updatedTime != null "> and updated_time = #{updatedTime}</if>
+        </where>
+    </select>
+
+    <select id="selectIpadAllocationRecordsById" parameterType="Long" resultMap="IpadAllocationRecordsResult">
+        <include refid="selectIpadAllocationRecordsVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertIpadAllocationRecords" parameterType="IpadAllocationRecords">
+        insert into ipad_allocation_records
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyName != null">company_name,</if>
+            <if test="applyQuantity != null">apply_quantity,</if>
+            <if test="allocatedQuantity != null">allocated_quantity,</if>
+            <if test="submitTime != null">submit_time,</if>
+            <if test="reviewTime != null">review_time,</if>
+            <if test="auditStatus != null">audit_status,</if>
+            <if test="rejectionReason != null">rejection_reason,</if>
+            <if test="createdTime != null">created_time,</if>
+            <if test="updatedTime != null">updated_time,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyName != null">#{companyName},</if>
+            <if test="applyQuantity != null">#{applyQuantity},</if>
+            <if test="allocatedQuantity != null">#{allocatedQuantity},</if>
+            <if test="submitTime != null">#{submitTime},</if>
+            <if test="reviewTime != null">#{reviewTime},</if>
+            <if test="auditStatus != null">#{auditStatus},</if>
+            <if test="rejectionReason != null">#{rejectionReason},</if>
+            <if test="createdTime != null">#{createdTime},</if>
+            <if test="updatedTime != null">#{updatedTime},</if>
+        </trim>
+    </insert>
+
+    <update id="updateIpadAllocationRecords" parameterType="IpadAllocationRecords">
+        update ipad_allocation_records
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyName != null">company_name = #{companyName},</if>
+            <if test="applyQuantity != null">apply_quantity = #{applyQuantity},</if>
+            <if test="allocatedQuantity != null">allocated_quantity = #{allocatedQuantity},</if>
+            <if test="submitTime != null">submit_time = #{submitTime},</if>
+            <if test="reviewTime != null">review_time = #{reviewTime},</if>
+            <if test="auditStatus != null">audit_status = #{auditStatus},</if>
+            <if test="rejectionReason != null">rejection_reason = #{rejectionReason},</if>
+            <if test="createdTime != null">created_time = #{createdTime},</if>
+            <if test="updatedTime != null">updated_time = #{updatedTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteIpadAllocationRecordsById" parameterType="Long">
+        delete from ipad_allocation_records where id = #{id}
+    </delete>
+
+    <delete id="deleteIpadAllocationRecordsByIds" parameterType="String">
+        delete from ipad_allocation_records where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 4 - 0
fs-service/src/main/resources/mapper/qw/QwIpadServerMapper.xml

@@ -38,6 +38,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectQwIpadServerVo"/>
         where id = #{id}
     </select>
+    <select id="selectIpAndPort" resultType="com.fs.qw.domain.QwIpadServer">
+        select id, title, address_id, ip, port, url, total_count, count, create_time, update_time from qw_ipad_server
+        where ip = #{ipAddress} and port = #{port}
+    </select>
 
     <insert id="insertQwIpadServer" parameterType="QwIpadServer">
         insert into qw_ipad_server