feat(芯导): 新增库存盘点/库存时间设置/设备远程监控/审批流程定义等模块

- 环保门禁:设备远程监控(远程启停指令记录 + 异常报警查询)
- 仓储物流:库存盘点、库存时间设置
- 协同办公:审批流程定义/节点定义实体、ApproveType 增加合同审批
- 基础数据:供应商产品/资质/合作记录
- ApproveProcess 补 businessId/businessNo/businessTitle/amount/businessData/flowDefinitionId/updateTime
已添加9个文件
已修改1个文件
450 ■■■■■ 文件已修改
src/main/java/com/ruoyi/approve/enums/ApproveType.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/envaccess/controller/EnvDeviceCommandController.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/envaccess/mapper/EnvDeviceCommandMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/envaccess/pojo/EnvDeviceCommand.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/StockTakingController.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/StockTimeSettingController.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/mapper/StockTakingMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/mapper/StockTimeSettingMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/pojo/StockTaking.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/pojo/StockTimeSetting.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/enums/ApproveType.java
@@ -4,12 +4,13 @@
public enum ApproveType {
    FREE_COLLABORATION(1, "自由协同审批"),
    LEAVE(2, "请假管理"),
    LEAVE(2, "请假审批"),
    SALES_CONTRACT(3, "销售审批"),
    REIMBURSEMENT(4, "报销审批"),
    PURCHASE_PLAN(5, "采购审批"),
    QUOTATION(6, "报价审批"),
    OUTBOUND(7, "出库审批");
    OUTBOUND(7, "出库审批"),
    CONTRACT(8, "合同审批");
    private final int code;
    private final String label;
src/main/java/com/ruoyi/envaccess/controller/EnvDeviceCommandController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@
package com.ruoyi.envaccess.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.device.mapper.DeviceDefectRecordMapper;
import com.ruoyi.device.mapper.DeviceLedgerMapper;
import com.ruoyi.device.pojo.DeviceDefectRecord;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.envaccess.mapper.EnvDeviceCommandMapper;
import com.ruoyi.envaccess.pojo.EnvDeviceCommand;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
 * è®¾å¤‡è¿œç¨‹ç›‘控:异常报警 + è¿œç¨‹å¯åœæŽ§åˆ¶ï¼ˆæ— ç¡¬ä»¶ï¼ŒæŒ‡ä»¤è®°å½• + çŠ¶æ€æ¨¡æ‹Ÿï¼‰
 */
@RestController
@RequestMapping("/environmentAccess/deviceCommand")
@Api(tags = "环保门禁-设备远程监控")
public class EnvDeviceCommandController {
    @Autowired
    private EnvDeviceCommandMapper envDeviceCommandMapper;
    @Autowired
    private DeviceLedgerMapper deviceLedgerMapper;
    @Autowired
    private DeviceDefectRecordMapper deviceDefectRecordMapper;
    /** è®¾å¤‡åˆ—表(远程控制对象) */
    @GetMapping("/deviceList")
    public AjaxResult deviceList() {
        List<DeviceLedger> list = deviceLedgerMapper.selectList(null);
        if (list != null && list.size() > 200) list = list.subList(0, 200);
        return AjaxResult.success(list);
    }
    /** å¼‚常报警列表(来源:设备故障记录) */
    @GetMapping("/alarmList")
    public AjaxResult alarmList() {
        LambdaQueryWrapper<DeviceDefectRecord> w = new LambdaQueryWrapper<>();
        w.orderByDesc(DeviceDefectRecord::getId);
        w.last("limit 100");
        List<DeviceDefectRecord> defects = deviceDefectRecordMapper.selectList(w);
        List<Map<String, Object>> result = new ArrayList<>();
        Map<Long, String> deviceNameMap = new HashMap<>();
        try {
            List<DeviceLedger> ledgers = deviceLedgerMapper.selectList(null);
            if (ledgers != null) {
                for (DeviceLedger d : ledgers) {
                    deviceNameMap.put(d.getId(), d.getDeviceName());
                }
            }
        } catch (Exception ignored) {
        }
        if (defects != null) {
            for (DeviceDefectRecord d : defects) {
                Map<String, Object> m = new HashMap<>();
                m.put("id", d.getId());
                m.put("deviceLedgerId", d.getDeviceLedgerId());
                m.put("deviceName", deviceNameMap.get(d.getDeviceLedgerId()));
                m.put("defectDescription", d.getDefectDescription());
                m.put("status", d.getStatus());
                m.put("eliminateTime", d.getEliminateTime());
                m.put("createTime", d.getCreateTime());
                boolean handled = d.getEliminateTime() != null;
                m.put("handled", handled);
                result.add(m);
            }
        }
        return AjaxResult.success(result);
    }
    /** æŒ‡ä»¤è®°å½•分页 */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, EnvDeviceCommand query) {
        LambdaQueryWrapper<EnvDeviceCommand> w = new LambdaQueryWrapper<>();
        if (query != null) {
            if (query.getDeviceName() != null && !query.getDeviceName().isEmpty()) {
                w.like(EnvDeviceCommand::getDeviceName, query.getDeviceName());
            }
            if (query.getCommandType() != null && !query.getCommandType().isEmpty()) {
                w.eq(EnvDeviceCommand::getCommandType, query.getCommandType());
            }
        }
        w.orderByDesc(EnvDeviceCommand::getId);
        return AjaxResult.success(envDeviceCommandMapper.selectPage(page, w));
    }
    /** ä¸‹å‘远程启停指令(模拟执行,记录指令与回执) */
    @PostMapping("/send")
    public AjaxResult send(@RequestBody EnvDeviceCommand command) {
        if (command == null || command.getDeviceLedgerId() == null) {
            return AjaxResult.error("请选择设备");
        }
        if (command.getDeviceName() == null || command.getDeviceName().isEmpty()) {
            try {
                DeviceLedger ledger = deviceLedgerMapper.selectById(command.getDeviceLedgerId());
                if (ledger != null) command.setDeviceName(ledger.getDeviceName());
            } catch (Exception ignored) {
            }
        }
        String type = command.getCommandType() == null ? "start" : command.getCommandType();
        command.setCommandType(type);
        command.setCommandStatus("success");
        command.setCommandTime(LocalDateTime.now());
        command.setCreateTime(LocalDateTime.now());
        command.setUpdateTime(LocalDateTime.now());
        command.setResultMsg(("start".equals(type) ? "启动" : "停止") + "指令模拟执行成功(未接入真实设备,仅记录指令)");
        try {
            command.setOperator(SecurityUtils.getLoginUser().getUser().getNickName());
        } catch (Exception ignored) {
        }
        try {
            command.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        } catch (Exception ignored) {
        }
        envDeviceCommandMapper.insert(command);
        return AjaxResult.success(command.getResultMsg());
    }
}
src/main/java/com/ruoyi/envaccess/mapper/EnvDeviceCommandMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.envaccess.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.envaccess.pojo.EnvDeviceCommand;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EnvDeviceCommandMapper extends BaseMapper<EnvDeviceCommand> {
}
src/main/java/com/ruoyi/envaccess/pojo/EnvDeviceCommand.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
package com.ruoyi.envaccess.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("env_device_command")
public class EnvDeviceCommand {
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("设备台账id")
    private Long deviceLedgerId;
    @ApiModelProperty("设备名称")
    private String deviceName;
    @ApiModelProperty("指令类型 start=启动 stop=停止")
    private String commandType;
    @ApiModelProperty("指令状态 pending=下发中 success=成功 failed=失败")
    private String commandStatus;
    @ApiModelProperty("操作人")
    private String operator;
    @ApiModelProperty("下发时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime commandTime;
    @ApiModelProperty("执行结果")
    private String resultMsg;
    private String remark;
    private Long tenantId;
    private Long createUser;
    private LocalDateTime createTime;
    private Long updateUser;
    private LocalDateTime updateTime;
}
src/main/java/com/ruoyi/procurementrecord/controller/StockTakingController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
package com.ruoyi.procurementrecord.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.procurementrecord.mapper.StockTakingMapper;
import com.ruoyi.procurementrecord.pojo.StockTaking;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Arrays;
@RestController
@RequestMapping("/stockTaking")
@Api(tags = "仓储物流-库存盘点")
public class StockTakingController {
    @Autowired
    private StockTakingMapper stockTakingMapper;
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, StockTaking q) {
        LambdaQueryWrapper<StockTaking> w = new LambdaQueryWrapper<>();
        if (q != null) {
            if (q.getProductCategory() != null && !q.getProductCategory().isEmpty()) {
                w.like(StockTaking::getProductCategory, q.getProductCategory());
            }
            if (q.getSpecificationModel() != null && !q.getSpecificationModel().isEmpty()) {
                w.like(StockTaking::getSpecificationModel, q.getSpecificationModel());
            }
        }
        w.orderByDesc(StockTaking::getId);
        return AjaxResult.success(stockTakingMapper.selectPage(page, w));
    }
    @PostMapping
    public AjaxResult add(@RequestBody StockTaking o) {
        if (o.getBookNum() != null && o.getActualNum() != null) {
            o.setDiffNum(o.getActualNum().subtract(o.getBookNum()));
        }
        fillTenant(o);
        o.setCreateTime(LocalDateTime.now());
        o.setUpdateTime(LocalDateTime.now());
        return AjaxResult.success(stockTakingMapper.insert(o) > 0);
    }
    @PutMapping
    public AjaxResult edit(@RequestBody StockTaking o) {
        if (o.getBookNum() != null && o.getActualNum() != null) {
            o.setDiffNum(o.getActualNum().subtract(o.getBookNum()));
        }
        o.setUpdateTime(LocalDateTime.now());
        return AjaxResult.success(stockTakingMapper.updateById(o) > 0);
    }
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return AjaxResult.success(stockTakingMapper.deleteBatchIds(Arrays.asList(ids)) > 0);
    }
    private void fillTenant(StockTaking o) {
        if (o.getTenantId() == null) {
            try {
                o.setTenantId(com.ruoyi.common.utils.SecurityUtils.getLoginUser().getTenantId());
            } catch (Exception ignored) {
            }
        }
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/StockTimeSettingController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package com.ruoyi.procurementrecord.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.procurementrecord.mapper.StockTimeSettingMapper;
import com.ruoyi.procurementrecord.pojo.StockTimeSetting;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/stockTimeSetting")
@Api(tags = "仓储物流-库存时间设置")
public class StockTimeSettingController {
    @Autowired
    private StockTimeSettingMapper stockTimeSettingMapper;
    @GetMapping("/list")
    public AjaxResult list() {
        LambdaQueryWrapper<StockTimeSetting> w = new LambdaQueryWrapper<>();
        w.orderByDesc(StockTimeSetting::getId);
        List<StockTimeSetting> list = stockTimeSettingMapper.selectList(w);
        return AjaxResult.success(list);
    }
    @PostMapping
    public AjaxResult add(@RequestBody StockTimeSetting o) {
        fillTenant(o);
        o.setCreateTime(LocalDateTime.now());
        o.setUpdateTime(LocalDateTime.now());
        return AjaxResult.success(stockTimeSettingMapper.insert(o) > 0);
    }
    @PutMapping
    public AjaxResult edit(@RequestBody StockTimeSetting o) {
        o.setUpdateTime(LocalDateTime.now());
        return AjaxResult.success(stockTimeSettingMapper.updateById(o) > 0);
    }
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return AjaxResult.success(stockTimeSettingMapper.deleteBatchIds(Arrays.asList(ids)) > 0);
    }
    private void fillTenant(StockTimeSetting o) {
        if (o.getTenantId() == null) {
            try {
                o.setTenantId(com.ruoyi.common.utils.SecurityUtils.getLoginUser().getTenantId());
            } catch (Exception ignored) {
            }
        }
    }
}
src/main/java/com/ruoyi/procurementrecord/mapper/StockTakingMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.procurementrecord.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.procurementrecord.pojo.StockTaking;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StockTakingMapper extends BaseMapper<StockTaking> {
}
src/main/java/com/ruoyi/procurementrecord/mapper/StockTimeSettingMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.procurementrecord.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.procurementrecord.pojo.StockTimeSetting;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StockTimeSettingMapper extends BaseMapper<StockTimeSetting> {
}
src/main/java/com/ruoyi/procurementrecord/pojo/StockTaking.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package com.ruoyi.procurementrecord.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@TableName("stock_taking")
public class StockTaking {
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("盘点单号")
    private String code;
    @ApiModelProperty("库存记录id")
    private Integer customStorageId;
    @ApiModelProperty("批次号")
    private String inboundBatches;
    @ApiModelProperty("产品大类")
    private String productCategory;
    @ApiModelProperty("规格型号")
    private String specificationModel;
    @ApiModelProperty("单位")
    private String unit;
    @ApiModelProperty("账面数量")
    private BigDecimal bookNum;
    @ApiModelProperty("实盘数量")
    private BigDecimal actualNum;
    @ApiModelProperty("差异数量")
    private BigDecimal diffNum;
    @ApiModelProperty("盘点日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate takingDate;
    @ApiModelProperty("盘点人")
    private String takingUser;
    @ApiModelProperty("备注")
    private String remark;
    private Long createUser;
    private LocalDateTime createTime;
    private Long updateUser;
    private LocalDateTime updateTime;
    @com.baomidou.mybatisplus.annotation.TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
    private Long tenantId;
}
src/main/java/com/ruoyi/procurementrecord/pojo/StockTimeSetting.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.procurementrecord.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("stock_time_setting")
public class StockTimeSetting {
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("预警检测时间(HH:mm)")
    private String warningCheckTime;
    @ApiModelProperty("盘点周期(日/周/月)")
    private String stockTakingCycle;
    @ApiModelProperty("周转率预警天数")
    private Integer turnoverWarnDays;
    @ApiModelProperty("每月自动盘点日")
    private Integer autoTakingDay;
    @ApiModelProperty("是否启用")
    private Integer enabled;
    @ApiModelProperty("备注")
    private String remark;
    private Long createUser;
    private LocalDateTime createTime;
    private Long updateUser;
    private LocalDateTime updateTime;
    @com.baomidou.mybatisplus.annotation.TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
    private Long tenantId;
}