物流处理 完成了顺丰api对接

This commit is contained in:
2025-07-21 23:39:30 +08:00
parent ca0ec753c7
commit b1914b7edc
23 changed files with 1581 additions and 4 deletions

View File

@@ -0,0 +1,107 @@
package com.ruoyi.oa.controller;
import java.util.List;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import com.ruoyi.oa.domain.bo.OaExpressBo;
import com.ruoyi.oa.service.IOaExpressService;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 物流预览
*
* @author hdka
* @date 2025-07-20
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/oa/express")
public class OaExpressController extends BaseController {
private final IOaExpressService iOaExpressService;
/**
* 查询物流预览列表
*/
@GetMapping("/list")
public TableDataInfo<OaExpressVo> list(OaExpressBo bo, PageQuery pageQuery) {
return iOaExpressService.queryPageList(bo, pageQuery);
}
/**
* 导出物流预览列表
*/
@Log(title = "物流预览", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OaExpressBo bo, HttpServletResponse response) {
List<OaExpressVo> list = iOaExpressService.queryList(bo);
ExcelUtil.exportExcel(list, "物流预览", OaExpressVo.class, response);
}
/**
* 获取物流预览详细信息
*
* @param expressId 主键
*/
@GetMapping("/{expressId}")
public R<OaExpressVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long expressId) {
return R.ok(iOaExpressService.queryById(expressId));
}
/**
* 新增物流预览
*/
@Log(title = "物流预览", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody OaExpressBo bo) {
return toAjax(iOaExpressService.insertByBo(bo));
}
/**
* 修改物流预览
*/
@Log(title = "物流预览", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OaExpressBo bo) {
return toAjax(iOaExpressService.updateByBo(bo));
}
/**
* 删除物流预览
*
* @param expressIds 主键串
*/
@Log(title = "物流预览", businessType = BusinessType.DELETE)
@DeleteMapping("/{expressIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] expressIds) {
return toAjax(iOaExpressService.deleteWithValidByIds(Arrays.asList(expressIds), true));
}
@GetMapping("/refresh/{expressIds}")
public R<Void> getRefreshExpress(@PathVariable Long[] expressIds) {
return toAjax(iOaExpressService.getRefreshExpress(Arrays.asList(expressIds)));
}
}

View File

@@ -0,0 +1,101 @@
package com.ruoyi.oa.controller;
import java.util.List;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.oa.domain.vo.OaExpressQuestionVo;
import com.ruoyi.oa.domain.bo.OaExpressQuestionBo;
import com.ruoyi.oa.service.IOaExpressQuestionService;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 快递问题
*
* @author hdka
* @date 2025-07-21
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/oa/expressQuestion")
public class OaExpressQuestionController extends BaseController {
private final IOaExpressQuestionService iOaExpressQuestionService;
/**
* 查询快递问题列表
*/
@GetMapping("/list")
public TableDataInfo<OaExpressQuestionVo> list(OaExpressQuestionBo bo, PageQuery pageQuery) {
return iOaExpressQuestionService.queryPageList(bo, pageQuery);
}
/**
* 导出快递问题列表
*/
@Log(title = "快递问题", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OaExpressQuestionBo bo, HttpServletResponse response) {
List<OaExpressQuestionVo> list = iOaExpressQuestionService.queryList(bo);
ExcelUtil.exportExcel(list, "快递问题", OaExpressQuestionVo.class, response);
}
/**
* 获取快递问题详细信息
*
* @param questionId 主键
*/
@GetMapping("/{questionId}")
public R<OaExpressQuestionVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long questionId) {
return R.ok(iOaExpressQuestionService.queryById(questionId));
}
/**
* 新增快递问题
*/
@Log(title = "快递问题", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody OaExpressQuestionBo bo) {
return toAjax(iOaExpressQuestionService.insertByBo(bo));
}
/**
* 修改快递问题
*/
@Log(title = "快递问题", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OaExpressQuestionBo bo) {
return toAjax(iOaExpressQuestionService.updateByBo(bo));
}
/**
* 删除快递问题
*
* @param questionIds 主键串
*/
@Log(title = "快递问题", businessType = BusinessType.DELETE)
@DeleteMapping("/{questionIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] questionIds) {
return toAjax(iOaExpressQuestionService.deleteWithValidByIds(Arrays.asList(questionIds), true));
}
}

View File

@@ -67,6 +67,16 @@ public class OaReportDetailController extends BaseController {
@PathVariable Long id) {
return R.ok(iOaReportDetailService.queryById(id));
}
/**
* 获取设计项目汇报详情详细信息
*
* @param projectId 主键
*/
@GetMapping("/project/{projectId}")
public R<List<OaReportDetailVo>> listReportDetailByProjectId(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
return R.ok(iOaReportDetailService.queryByProjectId(projectId));
}
/**
* 新增设计项目汇报详情

View File

@@ -0,0 +1,98 @@
package com.ruoyi.oa.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 物流预览对象 oa_express
*
* @author hdka
* @date 2025-07-20
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("oa_express")
public class OaExpress extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键id
*/
@TableId(value = "express_id")
private Long expressId;
/**
* 绑定项目
*/
private Long projectId;
/**
* 发货记录id
*/
private Long detailId;
/**
* 物流编号
*/
private String expressCode;
/**
* 数据状态0未确认1进行中2已完成
*/
private Long status;
/**
* 供应商姓名
*/
private String supplyName;
/**
* 供应商联系方式
*/
private String supplyPhone;
/**
* 负责人id
*/
private Long ownerId;
/**
* 负责人手机号(快递手机号)
*/
private String ownerPhone;
/**
* 计划到货时间
*/
private Date planDate;
/**
* 物流公司标识
*/
private String expressType;
/**
* 删除标志
*/
@TableLogic
private Long delFlag;
/**
* 备注
*/
private String remark;
/**
* 节点变化时间
*/
private Date lastUpdateTime;
/**
* 当前节点
*/
private String lastStatus;
}

View File

@@ -0,0 +1,62 @@
package com.ruoyi.oa.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 快递问题对象 oa_express_question
*
* @author hdka
* @date 2025-07-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("oa_express_question")
public class OaExpressQuestion extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键id
*/
@TableId(value = "question_id")
private Long questionId;
/**
* 关联快递
*/
private Long expressId;
/**
* 问题描述
*/
private String description;
/**
* 汇报时间
*/
private Date reportTime;
/**
* 汇报人
*/
private String reportBy;
/**
* 0未解决1已解决
*/
private Long status;
/**
* 删除标志
*/
@TableLogic
private Long delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,97 @@
package com.ruoyi.oa.domain.bo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 物流预览业务对象 oa_express
*
* @author hdka
* @date 2025-07-20
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class OaExpressBo extends BaseEntity {
/**
* 主键id
*/
private Long expressId;
/**
* 物流编号
*/
private String expressCode;
/**
* 数据状态0未确认1进行中2已完成
*/
private Long status;
/**
* 供应商姓名
*/
private String supplyName;
/**
* 供应商联系方式
*/
private String supplyPhone;
/**
* 负责人id
*/
private Long ownerId;
/**
* 负责人手机号(快递手机号)
*/
private String ownerPhone;
/**
* 计划到货时间
*/
private Date planDate;
/**
* 物流公司标识
*/
private String expressType;
/**
* 备注
*/
private String remark;
/**
* 绑定项目
*/
private Long projectId;
/**
* 发货记录id
*/
private Long detailId;
/**
* 节点变化时间
*/
private Date lastUpdateTime;
/**
* 当前节点
*/
private String lastStatus;
}

View File

@@ -0,0 +1,63 @@
package com.ruoyi.oa.domain.bo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 快递问题业务对象 oa_express_question
*
* @author hdka
* @date 2025-07-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class OaExpressQuestionBo extends BaseEntity {
/**
* 主键id
*/
private Long questionId;
/**
* 关联快递
*/
private Long expressId;
/**
* 问题描述
*/
private String description;
/**
* 汇报时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reportTime;
/**
* 汇报人
*/
private String reportBy;
/**
* 0未解决1已解决
*/
private Long status;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,74 @@
package com.ruoyi.oa.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import lombok.Data;
import java.util.Date;
/**
* 快递问题视图对象 oa_express_question
*
* @author hdka
* @date 2025-07-21
*/
@Data
@ExcelIgnoreUnannotated
public class OaExpressQuestionVo {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long questionId;
/**
* 关联快递
*/
@ExcelProperty(value = "关联快递")
private Long expressId;
/**
* 问题描述
*/
@ExcelProperty(value = "问题描述")
private String description;
/**
* 汇报时间
*/
@ExcelProperty(value = "汇报时间")
private Date reportTime;
/**
* 汇报人
*/
@ExcelProperty(value = "汇报人")
private String reportBy;
/**
* 0未解决1已解决
*/
@ExcelProperty(value = "状态")
private Long status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 快递单号
*/
private String expressCode;
}

View File

@@ -0,0 +1,140 @@
package com.ruoyi.oa.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import lombok.Data;
import java.util.Date;
/**
* 物流预览视图对象 oa_express
*
* @author hdka
* @date 2025-07-20
*/
@Data
@ExcelIgnoreUnannotated
public class OaExpressVo {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long expressId;
/**
* 物流编号
*/
@ExcelProperty(value = "物流编号")
private String expressCode;
/**
* 数据状态0未确认1进行中2已完成
*/
@ExcelProperty(value = "数据状态0未确认1进行中2已完成")
private Long status;
/**
* 供应商姓名
*/
@ExcelProperty(value = "供应商姓名")
private String supplyName;
/**
* 供应商联系方式
*/
@ExcelProperty(value = "供应商联系方式")
private String supplyPhone;
/**
* 负责人id
*/
private Long ownerId;
/**
* 负责人id
*/
@ExcelProperty(value = "负责人")
private String ownerName;
/**
* 负责人手机号(快递手机号)
*/
@ExcelProperty(value = "负责人手机号", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "快=递手机号")
private String ownerPhone;
/**
* 计划到货时间
*/
@ExcelProperty(value = "计划到货时间")
private Date planDate;
/**
* 物流公司标识
*/
@ExcelProperty(value = "物流公司标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "oa_express_type")
private String expressType;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 接收时间
*/
private Date acceptTime;
/**
* 物流状态
*/
private String firstStatusName;
/**
* 绑定项目
*/
private Long projectId;
/**
* 发货记录id
*/
private Long detailId;
/**
* 发货记录细节
*/
private String detailName;
/**
* 项目名称
*/
private String projectName;
/**
* 节点变化时间
*/
private Date lastUpdateTime;
/**
* 当前节点
*/
private String lastStatus;
/**
* 更新时间
*/
private Date updateTime;
}

View File

@@ -0,0 +1,23 @@
package com.ruoyi.oa.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.oa.domain.OaExpress;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
/**
* 物流预览Mapper接口
*
* @author hdka
* @date 2025-07-20
*/
public interface OaExpressMapper extends BaseMapperPlus<OaExpressMapper, OaExpress, OaExpressVo> {
Page<OaExpressVo> selectVoPagePlus(@Param("build") Page<Object> build, @Param(Constants.WRAPPER) LambdaQueryWrapper<OaExpress> lqw);
OaExpressVo selectVoByIdPlus(@Param("expressId") Long expressId);
}

View File

@@ -0,0 +1,20 @@
package com.ruoyi.oa.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.oa.domain.OaExpressQuestion;
import com.ruoyi.oa.domain.vo.OaExpressQuestionVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
/**
* 快递问题Mapper接口
*
* @author hdka
* @date 2025-07-21
*/
public interface OaExpressQuestionMapper extends BaseMapperPlus<OaExpressQuestionMapper, OaExpressQuestion, OaExpressQuestionVo> {
Page<OaExpressQuestionVo> selectVoPagePlus(@Param("build") Page<Object> build, @Param(Constants.WRAPPER) LambdaQueryWrapper<OaExpressQuestion> lqw);
}

View File

@@ -5,6 +5,8 @@ import com.ruoyi.oa.domain.vo.OaReportDetailVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 设计项目汇报详情Mapper接口
*
@@ -17,4 +19,7 @@ public interface OaReportDetailMapper extends BaseMapperPlus<OaReportDetailMappe
OaReportDetailVo selectVoByIdPlus(Long id);
List<OaReportDetailVo> queryByProjectId(Long projectId);
}

View File

@@ -0,0 +1,49 @@
package com.ruoyi.oa.service;
import com.ruoyi.oa.domain.OaExpressQuestion;
import com.ruoyi.oa.domain.vo.OaExpressQuestionVo;
import com.ruoyi.oa.domain.bo.OaExpressQuestionBo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 快递问题Service接口
*
* @author hdka
* @date 2025-07-21
*/
public interface IOaExpressQuestionService {
/**
* 查询快递问题
*/
OaExpressQuestionVo queryById(Long questionId);
/**
* 查询快递问题列表
*/
TableDataInfo<OaExpressQuestionVo> queryPageList(OaExpressQuestionBo bo, PageQuery pageQuery);
/**
* 查询快递问题列表
*/
List<OaExpressQuestionVo> queryList(OaExpressQuestionBo bo);
/**
* 新增快递问题
*/
Boolean insertByBo(OaExpressQuestionBo bo);
/**
* 修改快递问题
*/
Boolean updateByBo(OaExpressQuestionBo bo);
/**
* 校验并批量删除快递问题信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,57 @@
package com.ruoyi.oa.service;
import com.ruoyi.oa.domain.OaExpress;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import com.ruoyi.oa.domain.bo.OaExpressBo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 物流预览Service接口
*
* @author hdka
* @date 2025-07-20
*/
public interface IOaExpressService {
/**
* 查询物流预览
*/
OaExpressVo queryById(Long expressId);
/**
* 查询物流预览列表
*/
TableDataInfo<OaExpressVo> queryPageList(OaExpressBo bo, PageQuery pageQuery);
/**
* 查询物流预览列表
*/
List<OaExpressVo> queryList(OaExpressBo bo);
/**
* 新增物流预览
*/
Boolean insertByBo(OaExpressBo bo);
/**
* 修改物流预览
*/
Boolean updateByBo(OaExpressBo bo);
/**
* 校验并批量删除物流预览信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 及时更新选中的状态
* @param list
* @return
*/
Boolean getRefreshExpress(List<Long> list);
}

View File

@@ -6,6 +6,7 @@ import com.ruoyi.oa.domain.bo.OaReportDetailBo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import javax.validation.constraints.NotNull;
import java.util.Collection;
import java.util.List;
@@ -46,4 +47,12 @@ public interface IOaReportDetailService {
* 校验并批量删除设计项目汇报详情信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据项目查询细节
* @param projectId
* @return
*/
List<OaReportDetailVo> queryByProjectId(@NotNull(message = "主键不能为空") Long projectId);
}

View File

@@ -0,0 +1,115 @@
package com.ruoyi.oa.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.OaExpressQuestionBo;
import com.ruoyi.oa.domain.vo.OaExpressQuestionVo;
import com.ruoyi.oa.domain.OaExpressQuestion;
import com.ruoyi.oa.mapper.OaExpressQuestionMapper;
import com.ruoyi.oa.service.IOaExpressQuestionService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 快递问题Service业务层处理
*
* @author hdka
* @date 2025-07-21
*/
@RequiredArgsConstructor
@Service
public class OaExpressQuestionServiceImpl implements IOaExpressQuestionService {
private final OaExpressQuestionMapper baseMapper;
/**
* 查询快递问题
*/
@Override
public OaExpressQuestionVo queryById(Long questionId){
return baseMapper.selectVoById(questionId);
}
/**
* 查询快递问题列表
*/
@Override
public TableDataInfo<OaExpressQuestionVo> queryPageList(OaExpressQuestionBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<OaExpressQuestion> lqw = buildQueryWrapper(bo);
Page<OaExpressQuestionVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询快递问题列表
*/
@Override
public List<OaExpressQuestionVo> queryList(OaExpressQuestionBo bo) {
LambdaQueryWrapper<OaExpressQuestion> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<OaExpressQuestion> buildQueryWrapper(OaExpressQuestionBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<OaExpressQuestion> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getExpressId() != null, OaExpressQuestion::getExpressId, bo.getExpressId());
lqw.eq(StringUtils.isNotBlank(bo.getDescription()), OaExpressQuestion::getDescription, bo.getDescription());
lqw.eq(bo.getReportTime() != null, OaExpressQuestion::getReportTime, bo.getReportTime());
lqw.eq(StringUtils.isNotBlank(bo.getReportBy()), OaExpressQuestion::getReportBy, bo.getReportBy());
lqw.eq(bo.getStatus() != null, OaExpressQuestion::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增快递问题
*/
@Override
public Boolean insertByBo(OaExpressQuestionBo bo) {
OaExpressQuestion add = BeanUtil.toBean(bo, OaExpressQuestion.class);
validEntityBeforeSave(add);
add.setReportBy(LoginHelper.getNickName());
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setQuestionId(add.getQuestionId());
}
return flag;
}
/**
* 修改快递问题
*/
@Override
public Boolean updateByBo(OaExpressQuestionBo bo) {
OaExpressQuestion update = BeanUtil.toBean(bo, OaExpressQuestion.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(OaExpressQuestion entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除快递问题
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,150 @@
package com.ruoyi.oa.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.oa.utils.SfRouteQueryUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.OaExpressBo;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import com.ruoyi.oa.domain.OaExpress;
import com.ruoyi.oa.mapper.OaExpressMapper;
import com.ruoyi.oa.service.IOaExpressService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* 物流预览Service业务层处理
*
* @author hdka
* @date 2025-07-20
*/
@RequiredArgsConstructor
@Service
public class OaExpressServiceImpl implements IOaExpressService {
private final OaExpressMapper baseMapper;
/**
* 查询物流预览
*/
@Override
public OaExpressVo queryById(Long expressId){
return baseMapper.selectVoByIdPlus(expressId);
}
/**
* 查询物流预览列表
*/
@Override
public TableDataInfo<OaExpressVo> queryPageList(OaExpressBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<OaExpress> lqw = buildQueryWrapper(bo);
Page<OaExpressVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询物流预览列表
*/
@Override
public List<OaExpressVo> queryList(OaExpressBo bo) {
LambdaQueryWrapper<OaExpress> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<OaExpress> buildQueryWrapper(OaExpressBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<OaExpress> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getExpressCode()), OaExpress::getExpressCode, bo.getExpressCode());
lqw.eq(bo.getStatus() != null, OaExpress::getStatus, bo.getStatus());
lqw.like(StringUtils.isNotBlank(bo.getSupplyName()), OaExpress::getSupplyName, bo.getSupplyName());
lqw.eq(StringUtils.isNotBlank(bo.getSupplyPhone()), OaExpress::getSupplyPhone, bo.getSupplyPhone());
lqw.eq(bo.getOwnerId() != null, OaExpress::getOwnerId, bo.getOwnerId());
lqw.eq(StringUtils.isNotBlank(bo.getOwnerPhone()), OaExpress::getOwnerPhone, bo.getOwnerPhone());
lqw.eq(bo.getPlanDate() != null, OaExpress::getPlanDate, bo.getPlanDate());
lqw.eq(bo.getProjectId() != null, OaExpress::getProjectId, bo.getProjectId());
lqw.eq(StringUtils.isNotBlank(bo.getExpressType()), OaExpress::getExpressType, bo.getExpressType());
return lqw;
}
/**
* 新增物流预览
*/
@Override
public Boolean insertByBo(OaExpressBo bo) {
OaExpress add = BeanUtil.toBean(bo, OaExpress.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setExpressId(add.getExpressId());
}
return flag;
}
/**
* 修改物流预览
*/
@Override
public Boolean updateByBo(OaExpressBo bo) {
OaExpress update = BeanUtil.toBean(bo, OaExpress.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(OaExpress entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除物流预览
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 获取所有需要刷新的快递ID示例所有类型为SF且状态为1的快递单
*/
public List<Long> getAllSfExpressIdsToRefresh() {
LambdaQueryWrapper<OaExpress> lqw = Wrappers.lambdaQuery();
lqw.eq(OaExpress::getExpressType, "SF");
lqw.eq(OaExpress::getStatus, 1L);
List<OaExpress> list = baseMapper.selectList(lqw);
return list.stream().map(OaExpress::getExpressId).collect(Collectors.toList());
}
@Override
public Boolean getRefreshExpress(List<Long> expressIds) {
for (Long expressId : expressIds) {
OaExpressVo oaExpressVo = baseMapper.selectVoById(expressId);
String expressType = oaExpressVo.getExpressType();
if (expressType.equals("SF") && oaExpressVo.getStatus() ==1L) {
// 校验为顺丰则进入此位置更新状态
String result = SfRouteQueryUtil.queryRoute(oaExpressVo.getExpressCode(), oaExpressVo.getOwnerPhone() != null ? oaExpressVo.getOwnerPhone() : oaExpressVo.getSupplyPhone());
OaExpressVo oaExpressVo1 = SfRouteQueryUtil.parseData(result);
if (oaExpressVo1 != null) {
oaExpressVo.setLastUpdateTime(oaExpressVo1.getAcceptTime());
oaExpressVo.setLastStatus(oaExpressVo1.getFirstStatusName());
}
}
OaExpress add = BeanUtil.toBean(oaExpressVo, OaExpress.class);
baseMapper.updateById(add);;
}
return true;
}
}

View File

@@ -15,10 +15,7 @@ import com.ruoyi.oa.domain.OaReportDetail;
import com.ruoyi.oa.mapper.OaReportDetailMapper;
import com.ruoyi.oa.service.IOaReportDetailService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.*;
/**
* 设计项目汇报详情Service业务层处理
@@ -151,4 +148,9 @@ public class OaReportDetailServiceImpl implements IOaReportDetailService {
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public List<OaReportDetailVo> queryByProjectId(Long projectId) {
return baseMapper.queryByProjectId(projectId);
}
}

View File

@@ -0,0 +1,23 @@
package com.ruoyi.oa.task;
import com.ruoyi.oa.service.impl.OaExpressServiceImpl;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
@Component
public class OaExpressRefreshTask {
@Resource
private OaExpressServiceImpl oaExpressService;
// 每20分钟执行一次
@Scheduled(cron = "0 0/20 * * * ?")
public void refreshExpress() {
List<Long> expressIds = oaExpressService.getAllSfExpressIdsToRefresh();
if (expressIds != null && !expressIds.isEmpty()) {
oaExpressService.getRefreshExpress(expressIds);
}
}
}

View File

@@ -0,0 +1,224 @@
package com.ruoyi.oa.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.oa.domain.OaExpress;
import com.ruoyi.oa.domain.vo.OaExpressVo;
import sun.misc.BASE64Encoder;
import com.ruoyi.common.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.List;
import java.util.Arrays;
import java.util.Date;
/**
* 顺丰路由地址查询工具
*/
public class SfRouteQueryUtil {
// 顺丰开放平台 partnerID
private static final String PARTNER_ID = "YIX65G10";
// 顺丰开放平台接口地址
private static final String API_URL = "https://bspgw.sf-express.com/std/service";
// 顺丰开放平台 checkWord
private static final String CHECK_WORD = "PkJL4cpEQIUuV1goWvhIznqthletmddX";
// 顺丰OAuth认证
private static final String OAUTH_URL = "https://sfapi.sf-express.com/oauth2/accessToken";
private static final String GRANT_TYPE = "password";
/**
* 查询顺丰路由
* @param mailNo 顺丰运单号
* @return 查询结果JSON
*/
public static String queryRoute(String mailNo,String phoneNumber) {
List<String> mailNos = Arrays.asList(mailNo);
try {
// 1. 构造业务数据msgData
JSONObject msgData = new JSONObject();
msgData.put("language", "zh-CN");
msgData.put("trackingType", "1"); // 1:运单号 2:订单号
msgData.put("methodType", "1"); // 1:标准路由
msgData.put("trackingNumber", mailNos);
msgData.put("checkPhoneNo", StringUtils.right(phoneNumber, 4));
String msgDataStr = msgData.toJSONString();
System.out.println(msgDataStr);
// 2. 公共参数
String requestID = UUID.randomUUID().toString().replaceAll("-", "");
String serviceCode = "EXP_RECE_SEARCH_ROUTES";
String timestamp = String.valueOf(System.currentTimeMillis());
// String msgDigest = genSign(msgDataStr, timestamp, CHECK_WORD);
// System.out.println(msgDigest);
String accessToken = oAuth();
System.out.println(accessToken);
// 3. 拼接表单参数
StringBuilder formParams = new StringBuilder();
formParams.append("partnerID=").append(URLEncoder.encode(PARTNER_ID, "UTF-8"));
formParams.append("&requestID=").append(URLEncoder.encode(requestID, "UTF-8"));
formParams.append("&serviceCode=").append(URLEncoder.encode(serviceCode, "UTF-8"));
formParams.append("&timestamp=").append(URLEncoder.encode(timestamp, "UTF-8"));
formParams.append("&accessToken=").append(URLEncoder.encode(accessToken, "UTF-8"));
formParams.append("&msgData=").append(URLEncoder.encode(msgDataStr, "UTF-8"));
String formBody = formParams.toString();
System.out.println(formBody);
// 4. 发送POST请求
return doPost(API_URL, formBody);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 顺丰msgDigest生成方式Base64(MD5(URLEncode(msgData+timestamp+partnerId+checkWord)))
*/
private static String genSign(String msgData, String timestamp, String checkWord) throws Exception {
String toVerifyText = msgData + timestamp + checkWord;
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(toVerifyText.getBytes("UTF-8"));
byte[] digest = md5.digest();
return Base64.getEncoder().encodeToString(digest);
}
/**
* 顺丰OAUTH2
*/
private static String oAuth() throws Exception {
StringBuilder formParams = new StringBuilder();
formParams.append("partnerID=").append(URLEncoder.encode(PARTNER_ID, "UTF-8"));
formParams.append("&secret=").append(URLEncoder.encode(CHECK_WORD, "UTF-8"));
formParams.append("&grantType=").append(URLEncoder.encode(GRANT_TYPE, "UTF-8"));
String oauthResponse = doPost(OAUTH_URL, formParams.toString());
JSONObject jsonObject = JSON.parseObject(oauthResponse);
return jsonObject.getString("accessToken");
}
/**
* 发送POST请求表单格式
*/
private static String doPost(String urlStr, String formBody) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(formBody.getBytes(StandardCharsets.UTF_8));
}
int code = conn.getResponseCode();
if (code == 200) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
} else {
throw new RuntimeException("HTTP请求失败状态码" + code);
}
}
public static OaExpressVo parseData(String result) {
if (StringUtils.isBlank(result)) {
return null;
}
try {
// 1. 解析最外层的JSON
JSONObject outerJson = JSON.parseObject(result);
if (outerJson == null) {
return null;
}
// 2. 获取apiResultData字符串并再次解析
String apiResultDataStr = outerJson.getString("apiResultData");
if (StringUtils.isBlank(apiResultDataStr)) {
return null;
}
JSONObject innerJson = JSON.parseObject(apiResultDataStr);
if (innerJson == null) {
return null;
}
// 3. 提取所需数据
JSONObject msgData = innerJson.getJSONObject("msgData");
if (msgData == null) {
return null;
}
JSONArray routeResps = msgData.getJSONArray("routeResps");
if (routeResps == null || routeResps.isEmpty()) {
return null;
}
JSONObject firstRouteResp = routeResps.getJSONObject(0);
if (firstRouteResp == null) {
return null;
}
JSONArray routes = firstRouteResp.getJSONArray("routes");
if (routes == null || routes.isEmpty()) {
return null;
}
JSONObject lastRoute = routes.getJSONObject(routes.size() - 1);
if (lastRoute == null) {
return null;
}
String acceptTime = lastRoute.getString("acceptTime");
String firstStatusName = lastRoute.getString("firstStatusName");
OaExpressVo oaExpressVo = new OaExpressVo();
// 转换日期并设置如果日期格式不正确则设置为null
if (StringUtils.isNotBlank(acceptTime)) {
try {
Date date = DateUtils.parseDate(acceptTime);
oaExpressVo.setAcceptTime(date);
} catch (Exception e) {
oaExpressVo.setAcceptTime(null);
}
}
oaExpressVo.setFirstStatusName(firstStatusName);
System.out.println(acceptTime);
System.out.println(firstStatusName);
return oaExpressVo;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* main方法测试
*/
public static void main(String[] args) {
String mailNo = "SF0282456509537";
String result = queryRoute(mailNo,"18012017423");
System.out.println(result);
OaExpressVo oaExpress = parseData(result);
}
}

View File

@@ -0,0 +1,86 @@
<?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.ruoyi.oa.mapper.OaExpressMapper">
<resultMap type="com.ruoyi.oa.domain.OaExpress" id="OaExpressResult">
<result property="expressId" column="express_id"/>
<result property="expressCode" column="express_code"/>
<result property="status" column="status"/>
<result property="supplyName" column="supply_name"/>
<result property="supplyPhone" column="supply_phone"/>
<result property="ownerId" column="owner_id"/>
<result property="ownerPhone" column="owner_phone"/>
<result property="planDate" column="plan_date"/>
<result property="expressType" column="express_type"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectVoPagePlus" resultType="com.ruoyi.oa.domain.vo.OaExpressVo">
select oe.express_id,
oe.project_id,
oe.detail_id,
oe.express_code,
oe.status,
oe.supply_name,
oe.supply_phone,
oe.owner_id,
oe.owner_phone,
oe.plan_date,
oe.express_type,
oe.create_by,
oe.create_time,
oe.update_by,
oe.update_time,
oe.last_status,
oe.last_update_time,
oe.del_flag,
oe.remark,
su.nick_name as ownerName,
sop.project_name,
ord.report_detail as detailName
from oa_express oe
left join sys_user su on su.user_id = oe.owner_id
left join sys_oa_project sop on sop.project_id = oe.project_id
left join oa_report_detail ord on ord.detail_id = oe.detail_id
${ew.getCustomSqlSegment}
</select>
<select id="selectVoByIdPlus" resultType="com.ruoyi.oa.domain.vo.OaExpressVo">
select oe.express_id,
oe.project_id,
oe.detail_id,
oe.express_code,
oe.status,
oe.supply_name,
oe.supply_phone,
oe.owner_id,
oe.owner_phone,
oe.plan_date,
oe.express_type,
oe.create_by,
oe.create_time,
oe.update_by,
oe.update_time,
oe.last_status,
oe.last_update_time,
oe.del_flag,
oe.remark,
su.nick_name as ownerName,
sop.project_name,
ord.report_detail as detailName
from oa_express oe
left join sys_user su on su.user_id = oe.owner_id
left join sys_oa_project sop on sop.project_id = oe.project_id
left join oa_report_detail ord on ord.detail_id = oe.detail_id
where express_id = #{expressId}
</select>
</mapper>

View File

@@ -0,0 +1,42 @@
<?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.ruoyi.oa.mapper.OaExpressQuestionMapper">
<resultMap type="com.ruoyi.oa.domain.OaExpressQuestion" id="OaExpressQuestionResult">
<result property="questionId" column="question_id"/>
<result property="expressId" column="express_id"/>
<result property="description" column="description"/>
<result property="reportTime" column="report_time"/>
<result property="reportBy" column="report_by"/>
<result property="status" column="status"/>
<result property="createTime" column="create_time"/>
<result property="createBy" column="create_by"/>
<result property="updateTime" column="update_time"/>
<result property="updateBy" column="update_by"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectVoPagePlus" resultType="com.ruoyi.oa.domain.vo.OaExpressQuestionVo">
select oeq.question_id,
oeq.express_id,
oeq.description,
oeq.report_time,
oeq.report_by,
oeq.status,
oeq.create_time,
oeq.create_by,
oeq.update_time,
oeq.update_by,
oeq.del_flag,
oeq.remark,
oe.express_code
from oa_express_question oeq
left join oa_express oe on oe.express_id = oeq.express_id
${ew.getCustomSqlSegment}
</select>
</mapper>

View File

@@ -44,4 +44,24 @@
</select>
<select id="queryByProjectId" resultType="com.ruoyi.oa.domain.vo.OaReportDetailVo">
select ord.detail_id,
ord.summary_id,
ord.device_code,
ord.category,
ord.device_description,
ord.report_detail,
ord.oss_ids,
ord.create_by,
ord.create_time,
ord.update_by,
ord.update_time,
ord.del_flag,
ord.remark
from oa_report_detail ord
left join oa_report_summary ors on ors.summary_id = ord.summary_id
where project_id = #{projectId}
</select>
</mapper>