Merge branch '0.8.X' of https://gitee.com/hdka/klp-oa into 0.8.X

This commit is contained in:
砂糖
2025-07-19 16:08:44 +08:00
10 changed files with 262 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="出入库单号" prop="stockIoCode">
<el-form-item label="出入库单号" prop="stockIoCode" style="min-width:200px;max-width:220px;">
<el-input
v-model="queryParams.stockIoCode"
placeholder="请输入出入库单号"
@@ -94,12 +94,16 @@
<el-table-column label="出入库单号" align="center" prop="stockIoCode" />
<el-table-column label="类型" align="center" prop="ioType">
<template slot-scope="scope">
<dict-tag :options="dict.type.stock_io_type" :value="scope.row.ioType"/>
<el-tag :type="getIoTypeTagType(scope.row.ioType)">
{{ getIoTypeLabel(scope.row.ioType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="业务类型" align="center" prop="bizType">
<template slot-scope="scope">
<dict-tag :options="dict.type.stock_biz_type" :value="scope.row.bizType"/>
<el-tag :type="getBizTypeTagType(scope.row.bizType)">
{{ getBizTypeLabel(scope.row.bizType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="单据状态" align="center" prop="status">
@@ -401,6 +405,35 @@ export default {
}
// 刷新列表
this.getList();
},
getIoTypeTagType(type) {
if (type === 'in') return 'success';
if (type === 'out') return 'primary';
if (type === 'transfer') return 'warning';
return '';
},
getIoTypeLabel(type) {
if (type === 'in') return '入库';
if (type === 'out') return '出库';
if (type === 'transfer') return '移库';
return type;
},
getBizTypeTagType(type) {
if (type === 'purchase') return 'success';
if (type === 'sales') return 'primary';
if (type === 'return') return 'warning';
if (type === 'relocation') return 'info';
return 'default';
},
getBizTypeLabel(type) {
const map = {
purchase: '采购',
sales: '销售',
return: '退货',
relocation: '调拨',
other: '其他'
};
return map[type] || type;
}
}
};

View File

@@ -3,8 +3,16 @@
<template v-if="stockIo && stockIo.stockIoId">
<!-- 主表信息 -->
<el-descriptions :title="'单号:' + (stockIo.stockIoCode || '-')" :column="2" border>
<el-descriptions-item label="类型">{{ stockIo.ioType }}</el-descriptions-item>
<el-descriptions-item label="业务类型">{{ stockIo.bizType }}</el-descriptions-item>
<el-descriptions-item label="类型">
<el-tag :type="getIoTypeTagType(stockIo.ioType)">
{{ getIoTypeLabel(stockIo.ioType) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="业务类型">
<el-tag :type="getBizTypeTagType(stockIo.bizType)">
{{ getBizTypeLabel(stockIo.bizType) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="stockIo.status === 2 ? 'success' : (stockIo.status === 1 ? 'warning' : 'info')">
{{ stockIo.status === 2 ? '已完成' : (stockIo.status === 0 ? '草稿' : '待审核') }}
@@ -63,12 +71,12 @@
<el-table v-loading="loading" :data="stockIoDetailList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="明细ID" align="center" prop="detailId"/>
<el-table-column label="库区/库位ID" align="center" prop="warehouseId" />
<el-table-column label="库区/库位" align="center" prop="warehouseName" />
<el-table-column
v-if="stockIo.ioType === 'transfer'"
label="源库区/库位ID"
label="源库区/库位"
align="center"
prop="fromWarehouseId"
prop="fromWarehouseName"
/>
<el-table-column label="物品类型" align="center" prop="itemType" />
<el-table-column label="物品ID" align="center" prop="itemId" />
@@ -469,6 +477,35 @@ export default {
console.error('刷新主表状态失败:', error);
});
}
},
getIoTypeTagType(type) {
if (type === 'in') return 'success';
if (type === 'out') return 'primary';
if (type === 'transfer') return 'warning';
return '';
},
getIoTypeLabel(type) {
if (type === 'in') return '入库';
if (type === 'out') return '出库';
if (type === 'transfer') return '移库';
return type;
},
getBizTypeLabel(type) {
const map = {
purchase: '采购',
sales: '销售',
return: '退货',
relocation: '调拨',
other: '其他'
};
return map[type] || type;
},
getBizTypeTagType(type) {
if (type === 'purchase') return 'success';
if (type === 'sales') return 'primary';
if (type === 'return') return 'warning';
if (type === 'relocation') return 'info';
return 'default';
}
}
}

View File

@@ -23,6 +23,7 @@ import com.klp.domain.vo.WmsStockIoVo;
import com.klp.domain.bo.WmsStockIoBo;
import com.klp.service.IWmsStockIoService;
import com.klp.common.core.page.TableDataInfo;
import com.klp.domain.bo.WmsStockIoWithDetailBo;
/**
* 出入库单主表
@@ -77,6 +78,15 @@ public class WmsStockIoController extends BaseController {
return toAjax(iWmsStockIoService.insertByBo(bo));
}
/**
* 批量新增主表和明细
*/
@PostMapping("/withDetail")
public R<Void> addWithDetail(@RequestBody WmsStockIoWithDetailBo bo) {
iWmsStockIoService.addWithDetail(bo);
return R.ok();
}
/**
* 修改出入库单主
*/
@@ -132,8 +142,9 @@ public class WmsStockIoController extends BaseController {
*/
@Log(title = "出入库单主", businessType = BusinessType.UPDATE)
@PostMapping("/updateStatus/{stockIoId}")
public R<Void> updateStatus(@NotNull(message = "主键不能为空") @PathVariable Long stockIoId,
public R<Void> updateStatus(@NotNull(message = "主键不能为空") @PathVariable Long stockIoId,
@RequestParam Integer status) {
return toAjax(iWmsStockIoService.updateStatus(stockIoId, status));
}
}

View File

@@ -0,0 +1,55 @@
package com.klp.domain.bo;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.math.BigDecimal;
/**
* 出入库单主+明细批量插入业务对象
*/
@Data
public class WmsStockIoWithDetailBo {
// 主表字段
/**
* 出入库单ID
*/
private Long stockIoId;
/**
* 出入库单号
*/
@NotBlank(message = "出入库单号不能为空", groups = { AddGroup.class, EditGroup.class })
private String stockIoCode;
/**
* 类型in=入库out=出库)
*/
@NotBlank(message = "类型in=入库out=出库)不能为空", groups = { AddGroup.class, EditGroup.class })
private String ioType;
/**
* 业务类型(采购、销售、退货、调拨等)
*/
@NotBlank(message = "业务类型(采购、销售、退货、调拨等)不能为空", groups = { AddGroup.class, EditGroup.class })
private String bizType;
/**
* 单据状态0=草稿1=已提交2=已审核3=已完成)
*/
@NotNull(message = "单据状态0=草稿1=已提交2=已审核3=已完成)不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer status;
/**
* 备注
*/
private String remark;
// ...如有其他主表字段可补充
// 明细列表
private List<WmsStockIoDetailBo> details;
}

View File

@@ -75,6 +75,15 @@ public class WmsStockIoDetailVo {
@ExcelProperty(value = "备注")
private String remark;
/**
* 库区/库位名称
*/
private String warehouseName;
/**
* 源库区/库位名称(移库用)
*/
private String fromWarehouseName;
/**
* 源库位ID移库时使用
*/

View File

@@ -3,13 +3,29 @@ package com.klp.mapper;
import com.klp.domain.WmsStockIoDetail;
import com.klp.domain.vo.WmsStockIoDetailVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
/**
* 出入库单明细Mapper接口
*
* VO带有库区/库位名称和源库区/库位名称
*
* @author Joshi
* @date 2025-07-18
*/
public interface WmsStockIoDetailMapper extends BaseMapperPlus<WmsStockIoDetailMapper, WmsStockIoDetail, WmsStockIoDetailVo> {
/**
* 联查库区/库位名称的明细列表返回Map
*/
List<Map<String, Object>> selectDetailWithWarehouseName(@Param("stockIoId") Long stockIoId);
/**
* 分页联查库区/库位名称的明细列表支持Wrapper动态条件返回Page<WmsStockIoDetailVo>
*/
Page<WmsStockIoDetailVo> selectVoPagePlus(Page<?> page, @Param("ew") Wrapper<WmsStockIoDetail> wrapper);
}

View File

@@ -4,6 +4,7 @@ import com.klp.domain.WmsStockIo;
import com.klp.domain.vo.WmsStockIoDetailVo;
import com.klp.domain.vo.WmsStockIoVo;
import com.klp.domain.bo.WmsStockIoBo;
import com.klp.domain.bo.WmsStockIoWithDetailBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
@@ -67,4 +68,9 @@ public interface IWmsStockIoService {
* 更新出入库单状态
*/
Boolean updateStatus(Long stockIoId, Integer status);
/**
* 批量新增主表和明细
*/
void addWithDetail(WmsStockIoWithDetailBo bo);
}

View File

@@ -51,7 +51,7 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
@Override
public TableDataInfo<WmsStockIoDetailVo> queryPageList(WmsStockIoDetailBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsStockIoDetail> lqw = buildQueryWrapper(bo);
Page<WmsStockIoDetailVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
Page<WmsStockIoDetailVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@@ -88,13 +88,13 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
if (stockIo != null && stockIo.getStatus() >= 2) {
throw new ServiceException("已审核的单据不能修改明细");
}
WmsStockIoDetail add = BeanUtil.toBean(bo, WmsStockIoDetail.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setDetailId(add.getDetailId());
// 检查主表状态,如果有明细且状态为草稿,则自动变为待审核
if (stockIo != null && stockIo.getStatus() == 0) {
// 检查是否有明细
@@ -102,7 +102,7 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
new LambdaQueryWrapper<WmsStockIoDetail>()
.eq(WmsStockIoDetail::getStockIoId, bo.getStockIoId())
);
if (detailCount > 0) {
// 自动更新状态为待审核
stockIo.setStatus(1);
@@ -124,7 +124,7 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
if (stockIo != null && stockIo.getStatus() >= 2) {
throw new ServiceException("已审核的单据不能修改明细");
}
WmsStockIoDetail update = BeanUtil.toBean(bo, WmsStockIoDetail.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
@@ -146,7 +146,7 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
// 获取要删除的明细对应的主表ID检查状态
List<WmsStockIoDetail> details = baseMapper.selectBatchIds(ids);
if (details != null && !details.isEmpty()) {
@@ -160,9 +160,9 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
// 按主表ID分组
Map<Long, List<WmsStockIoDetail>> stockIoIdMap = details.stream()
.collect(java.util.stream.Collectors.groupingBy(WmsStockIoDetail::getStockIoId));
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
if (flag) {
// 检查每个主表是否还有其他明细
for (Long stockIoId : stockIoIdMap.keySet()) {
@@ -170,7 +170,7 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
new LambdaQueryWrapper<WmsStockIoDetail>()
.eq(WmsStockIoDetail::getStockIoId, stockIoId)
);
// 如果没有明细了,状态回退为草稿
if (remainingCount == 0) {
WmsStockIo stockIo = stockIoMapper.selectById(stockIoId);
@@ -182,10 +182,10 @@ public class WmsStockIoDetailServiceImpl implements IWmsStockIoDetailService {
}
}
}
return flag;
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -29,6 +29,8 @@ import java.util.List;
import java.util.Map;
import java.util.Collection;
import com.klp.common.exception.ServiceException;
import com.klp.domain.bo.WmsStockIoWithDetailBo;
import com.klp.domain.bo.WmsStockIoDetailBo;
/**
* 出入库单主Service业务层处理
@@ -123,6 +125,25 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 批量新增主表和明细
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void addWithDetail(WmsStockIoWithDetailBo bo) {
// 插入主表
WmsStockIo stockIo = BeanUtil.toBean(bo, WmsStockIo.class);
baseMapper.insert(stockIo);
// 插入明细
if (bo.getDetails() != null && !bo.getDetails().isEmpty()) {
for (WmsStockIoDetailBo detailBo : bo.getDetails()) {
WmsStockIoDetail detail = BeanUtil.toBean(detailBo, WmsStockIoDetail.class);
detail.setStockIoId(stockIo.getStockIoId());
stockIoDetailMapper.insert(detail);
}
}
}
/**
* 审核出入库/移库单,变更库存,含库存校验
*/

View File

@@ -22,5 +22,59 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="fromWarehouseId" column="from_warehouse_id"/>
</resultMap>
<!-- 联查库区/库位名称的明细列表SQL直接返回Map -->
<select id="selectDetailWithWarehouseName" resultType="map">
SELECT
d.detail_id,
d.stock_io_id,
d.warehouse_id,
d.item_type,
d.item_id,
d.quantity,
d.unit,
d.batch_no,
d.remark,
d.del_flag,
d.create_time,
d.create_by,
d.update_time,
d.update_by,
d.from_warehouse_id,
w1.warehouse_name AS warehouseName,
w2.warehouse_name AS fromWarehouseName
FROM wms_stock_io_detail d
LEFT JOIN wms_warehouse w1 ON d.warehouse_id = w1.warehouse_id
LEFT JOIN wms_warehouse w2 ON d.from_warehouse_id = w2.warehouse_id
<where>
<if test="stockIoId != null">d.stock_io_id = #{stockIoId}</if>
<!-- 其他条件可补充 -->
</where>
</select>
<!-- 分页联查库区/库位名称的明细列表SQL支持Wrapper动态条件返回Page<WmsStockIoDetailVo> -->
<select id="selectVoPagePlus" resultType="com.klp.domain.vo.WmsStockIoDetailVo">
SELECT
d.detail_id,
d.stock_io_id,
d.warehouse_id,
d.item_type,
d.item_id,
d.quantity,
d.unit,
d.batch_no,
d.remark,
d.del_flag,
d.create_time,
d.create_by,
d.update_time,
d.update_by,
d.from_warehouse_id,
w1.warehouse_name AS warehouseName,
w2.warehouse_name AS fromWarehouseName
FROM wms_stock_io_detail d
LEFT JOIN wms_warehouse w1 ON d.warehouse_id = w1.warehouse_id
LEFT JOIN wms_warehouse w2 ON d.from_warehouse_id = w2.warehouse_id
${ew.customSqlSegment}
</select>
</mapper>