产品入库,半成品委外单
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package com.gear.mat.controller;
|
||||
|
||||
import com.gear.common.annotation.Log;
|
||||
import com.gear.common.annotation.RepeatSubmit;
|
||||
import com.gear.common.core.controller.BaseController;
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.domain.R;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.common.core.validate.AddGroup;
|
||||
import com.gear.common.core.validate.EditGroup;
|
||||
import com.gear.common.enums.BusinessType;
|
||||
import com.gear.common.utils.poi.ExcelUtil;
|
||||
import com.gear.mat.domain.bo.MatProductInDetailBo;
|
||||
import com.gear.mat.domain.vo.MatProductInDetailVo;
|
||||
import com.gear.mat.service.IMatProductInDetailService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mat/productInDetail")
|
||||
public class MatProductInDetailController extends BaseController {
|
||||
|
||||
private final IMatProductInDetailService iMatProductInDetailService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MatProductInDetailVo> list(MatProductInDetailBo bo, PageQuery pageQuery) {
|
||||
return iMatProductInDetailService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "产品入库单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(MatProductInDetailBo bo, HttpServletResponse response) {
|
||||
List<MatProductInDetailVo> list = iMatProductInDetailService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "产品入库单", MatProductInDetailVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{detailId}")
|
||||
public R<MatProductInDetailVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long detailId) {
|
||||
return R.ok(iMatProductInDetailService.queryById(detailId));
|
||||
}
|
||||
|
||||
@Log(title = "产品入库单", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody MatProductInDetailBo bo) {
|
||||
return toAjax(iMatProductInDetailService.insertByBoWithInventory(bo));
|
||||
}
|
||||
|
||||
@Log(title = "产品入库单", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody MatProductInDetailBo bo) {
|
||||
return toAjax(iMatProductInDetailService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "产品入库单", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{detailIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] detailIds) {
|
||||
return toAjax(iMatProductInDetailService.deleteWithValidByIdsWithInventory(Arrays.asList(detailIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.gear.mat.controller;
|
||||
|
||||
import com.gear.common.annotation.Log;
|
||||
import com.gear.common.annotation.RepeatSubmit;
|
||||
import com.gear.common.core.controller.BaseController;
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.domain.R;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.common.core.validate.AddGroup;
|
||||
import com.gear.common.enums.BusinessType;
|
||||
import com.gear.common.utils.poi.ExcelUtil;
|
||||
import com.gear.mat.domain.bo.MatProductOutsourceOrderBo;
|
||||
import com.gear.mat.domain.vo.MatProductOutsourceOrderVo;
|
||||
import com.gear.mat.service.IMatProductOutsourceOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mat/productOutsourceOrder")
|
||||
public class MatProductOutsourceOrderController extends BaseController {
|
||||
|
||||
private final IMatProductOutsourceOrderService iMatProductOutsourceOrderService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MatProductOutsourceOrderVo> list(MatProductOutsourceOrderBo bo, PageQuery pageQuery) {
|
||||
return iMatProductOutsourceOrderService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "半成品委外单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(MatProductOutsourceOrderBo bo, HttpServletResponse response) {
|
||||
List<MatProductOutsourceOrderVo> list = iMatProductOutsourceOrderService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "半成品委外单", MatProductOutsourceOrderVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{orderId}")
|
||||
public R<MatProductOutsourceOrderVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
return R.ok(iMatProductOutsourceOrderService.queryById(orderId));
|
||||
}
|
||||
|
||||
@Log(title = "半成品委外单", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody MatProductOutsourceOrderBo bo) {
|
||||
return toAjax(iMatProductOutsourceOrderService.insertByBoWithInventory(bo));
|
||||
}
|
||||
|
||||
@Log(title = "半成品委外单", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{orderIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] orderIds) {
|
||||
return toAjax(iMatProductOutsourceOrderService.deleteWithValidByIdsWithInventory(Arrays.asList(orderIds), true));
|
||||
}
|
||||
|
||||
@Log(title = "半成品委外单", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/receive/{orderId}")
|
||||
public R<Void> receive(@NotNull(message = "主键不能为空") @PathVariable Long orderId,
|
||||
@RequestBody ReceiveReq req) {
|
||||
BigDecimal qty = req == null ? null : req.getReceiveQty();
|
||||
Date time = req == null ? null : req.getReceiveTime();
|
||||
String by = req == null ? null : req.getReceiveBy();
|
||||
return toAjax(iMatProductOutsourceOrderService.receive(orderId, qty, time, by));
|
||||
}
|
||||
|
||||
public static class ReceiveReq {
|
||||
private BigDecimal receiveQty;
|
||||
private Date receiveTime;
|
||||
private String receiveBy;
|
||||
|
||||
public BigDecimal getReceiveQty() {
|
||||
return receiveQty;
|
||||
}
|
||||
|
||||
public void setReceiveQty(BigDecimal receiveQty) {
|
||||
this.receiveQty = receiveQty;
|
||||
}
|
||||
|
||||
public Date getReceiveTime() {
|
||||
return receiveTime;
|
||||
}
|
||||
|
||||
public void setReceiveTime(Date receiveTime) {
|
||||
this.receiveTime = receiveTime;
|
||||
}
|
||||
|
||||
public String getReceiveBy() {
|
||||
return receiveBy;
|
||||
}
|
||||
|
||||
public void setReceiveBy(String receiveBy) {
|
||||
this.receiveBy = receiveBy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,12 @@ public class MatProduct extends BaseEntity {
|
||||
* 产品单价 可手动维护
|
||||
*/
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@TableField("product_type")
|
||||
private String productType;
|
||||
|
||||
@TableField("current_stock")
|
||||
private BigDecimal currentStock;
|
||||
/**
|
||||
* 删除标志(0=正常,1=已删除)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.gear.mat.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.gear.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("mat_product_in_detail")
|
||||
public class MatProductInDetail extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "detail_id")
|
||||
private Long detailId;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private BigDecimal inNum;
|
||||
|
||||
private Date inTime;
|
||||
|
||||
private String operator;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.gear.mat.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.gear.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("mat_product_outsource_order")
|
||||
public class MatProductOutsourceOrder extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "order_id")
|
||||
private Long orderId;
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private String productTypeSnapshot;
|
||||
|
||||
private Long customerId;
|
||||
|
||||
private String customerName;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private Date outTime;
|
||||
|
||||
private String operator;
|
||||
|
||||
private BigDecimal receivedQty;
|
||||
|
||||
private Integer receiveFlag;
|
||||
|
||||
private Date receiveTime;
|
||||
|
||||
private String receiveBy;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -47,6 +47,10 @@ public class MatProductBo extends BaseEntity {
|
||||
*/
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
private String productType;
|
||||
|
||||
private BigDecimal currentStock;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.gear.mat.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.gear.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MatProductInDetailBo extends BaseEntity {
|
||||
|
||||
private Long detailId;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private BigDecimal inNum;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date inTime;
|
||||
|
||||
private String operator;
|
||||
|
||||
private String remark;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date beginTime;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date endTime;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.gear.mat.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.gear.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MatProductOutsourceOrderBo extends BaseEntity {
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private Long customerId;
|
||||
|
||||
private String customerName;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private Integer receiveFlag;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date outTime;
|
||||
|
||||
private String operator;
|
||||
|
||||
private String remark;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date beginTime;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date endTime;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.gear.mat.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class MatProductInDetailVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty(value = "入库明细ID")
|
||||
private Long detailId;
|
||||
|
||||
@ExcelProperty(value = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
@ExcelProperty(value = "入库数量")
|
||||
private BigDecimal inNum;
|
||||
|
||||
@ExcelProperty(value = "入库时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date inTime;
|
||||
|
||||
@ExcelProperty(value = "操作人")
|
||||
private String operator;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty(value = "产品名称")
|
||||
private String productName;
|
||||
|
||||
@ExcelProperty(value = "产品规格")
|
||||
private String spec;
|
||||
|
||||
@ExcelProperty(value = "产品型号")
|
||||
private String model;
|
||||
|
||||
@ExcelProperty(value = "产品类型")
|
||||
private String productType;
|
||||
|
||||
@ExcelProperty(value = "当前库存")
|
||||
private BigDecimal currentStock;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.gear.mat.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class MatProductOutsourceOrderVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty(value = "委外单ID")
|
||||
private Long orderId;
|
||||
|
||||
@ExcelProperty(value = "委外单号")
|
||||
private String orderNo;
|
||||
|
||||
@ExcelProperty(value = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
@ExcelProperty(value = "产品名称")
|
||||
private String productName;
|
||||
|
||||
@ExcelProperty(value = "产品规格")
|
||||
private String spec;
|
||||
|
||||
@ExcelProperty(value = "产品型号")
|
||||
private String model;
|
||||
|
||||
@ExcelProperty(value = "产品类型")
|
||||
private String productTypeSnapshot;
|
||||
|
||||
@ExcelProperty(value = "委托公司ID")
|
||||
private Long customerId;
|
||||
|
||||
@ExcelProperty(value = "委托公司")
|
||||
private String customerName;
|
||||
|
||||
@ExcelProperty(value = "委派数量")
|
||||
private BigDecimal quantity;
|
||||
|
||||
@ExcelProperty(value = "已收回数量")
|
||||
private BigDecimal receivedQty;
|
||||
|
||||
@ExcelProperty(value = "收回标志")
|
||||
private Integer receiveFlag;
|
||||
|
||||
@ExcelProperty(value = "委外时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date outTime;
|
||||
|
||||
@ExcelProperty(value = "收回时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date receiveTime;
|
||||
|
||||
@ExcelProperty(value = "收回人")
|
||||
private String receiveBy;
|
||||
|
||||
@ExcelProperty(value = "操作人")
|
||||
private String operator;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -52,6 +52,12 @@ public class MatProductVo {
|
||||
@ExcelProperty(value = "产品单价 可手动维护")
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@ExcelProperty(value = "产品类型")
|
||||
private String productType;
|
||||
|
||||
@ExcelProperty(value = "库存")
|
||||
private BigDecimal currentStock;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
@@ -51,6 +51,12 @@ public class MatProductWithMaterialsVo {
|
||||
@ExcelProperty(value = "产品单价 可手动维护")
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@ExcelProperty(value = "产品类型")
|
||||
private String productType;
|
||||
|
||||
@ExcelProperty(value = "库存")
|
||||
private BigDecimal currentStock;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.gear.mat.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gear.common.core.mapper.BaseMapperPlus;
|
||||
import com.gear.mat.domain.MatProductInDetail;
|
||||
import com.gear.mat.domain.vo.MatProductInDetailVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface MatProductInDetailMapper extends BaseMapperPlus<MatProductInDetailMapper, MatProductInDetail, MatProductInDetailVo> {
|
||||
|
||||
Page<MatProductInDetailVo> selectVoPagePlus(Page<Object> page, @Param("ew") QueryWrapper<MatProductInDetail> qw);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.gear.mat.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gear.common.core.mapper.BaseMapperPlus;
|
||||
import com.gear.mat.domain.MatProductOutsourceOrder;
|
||||
import com.gear.mat.domain.vo.MatProductOutsourceOrderVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface MatProductOutsourceOrderMapper extends BaseMapperPlus<MatProductOutsourceOrderMapper, MatProductOutsourceOrder, MatProductOutsourceOrderVo> {
|
||||
|
||||
Page<MatProductOutsourceOrderVo> selectVoPagePlus(Page<Object> page, @Param("ew") QueryWrapper<MatProductOutsourceOrder> qw);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.gear.mat.service;
|
||||
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.mat.domain.bo.MatProductInDetailBo;
|
||||
import com.gear.mat.domain.vo.MatProductInDetailVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IMatProductInDetailService {
|
||||
|
||||
MatProductInDetailVo queryById(Long detailId);
|
||||
|
||||
TableDataInfo<MatProductInDetailVo> queryPageList(MatProductInDetailBo bo, PageQuery pageQuery);
|
||||
|
||||
List<MatProductInDetailVo> queryList(MatProductInDetailBo bo);
|
||||
|
||||
Boolean insertByBoWithInventory(MatProductInDetailBo bo);
|
||||
|
||||
Boolean updateByBo(MatProductInDetailBo bo);
|
||||
|
||||
Boolean deleteWithValidByIdsWithInventory(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.gear.mat.service;
|
||||
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.mat.domain.bo.MatProductOutsourceOrderBo;
|
||||
import com.gear.mat.domain.vo.MatProductOutsourceOrderVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IMatProductOutsourceOrderService {
|
||||
|
||||
MatProductOutsourceOrderVo queryById(Long orderId);
|
||||
|
||||
TableDataInfo<MatProductOutsourceOrderVo> queryPageList(MatProductOutsourceOrderBo bo, PageQuery pageQuery);
|
||||
|
||||
List<MatProductOutsourceOrderVo> queryList(MatProductOutsourceOrderBo bo);
|
||||
|
||||
Boolean insertByBoWithInventory(MatProductOutsourceOrderBo bo);
|
||||
|
||||
Boolean receive(Long orderId, java.math.BigDecimal receiveQty, java.util.Date receiveTime, String receiveBy);
|
||||
|
||||
Boolean deleteWithValidByIdsWithInventory(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.gear.mat.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.common.utils.StringUtils;
|
||||
import com.gear.mat.domain.MatProduct;
|
||||
import com.gear.mat.domain.MatProductInDetail;
|
||||
import com.gear.mat.domain.bo.MatProductInDetailBo;
|
||||
import com.gear.mat.domain.vo.MatProductInDetailVo;
|
||||
import com.gear.mat.mapper.MatProductInDetailMapper;
|
||||
import com.gear.mat.mapper.MatProductMapper;
|
||||
import com.gear.mat.service.IMatProductInDetailService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MatProductInDetailServiceImpl implements IMatProductInDetailService {
|
||||
|
||||
private final MatProductInDetailMapper baseMapper;
|
||||
private final MatProductMapper matProductMapper;
|
||||
|
||||
@Override
|
||||
public MatProductInDetailVo queryById(Long detailId) {
|
||||
return baseMapper.selectVoById(detailId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<MatProductInDetailVo> queryPageList(MatProductInDetailBo bo, PageQuery pageQuery) {
|
||||
QueryWrapper<MatProductInDetail> qw = buildQueryWrapperPlus(bo);
|
||||
Page<MatProductInDetailVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), qw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
private QueryWrapper<MatProductInDetail> buildQueryWrapperPlus(MatProductInDetailBo bo) {
|
||||
QueryWrapper<MatProductInDetail> qw = Wrappers.query();
|
||||
qw.eq(bo.getProductId() != null, "mpid.product_id", bo.getProductId());
|
||||
qw.eq(bo.getInNum() != null, "mpid.in_num", bo.getInNum());
|
||||
qw.ge(bo.getBeginTime() != null, "mpid.in_time", bo.getBeginTime());
|
||||
qw.le(bo.getEndTime() != null, "mpid.in_time", bo.getEndTime());
|
||||
qw.eq(StringUtils.isNotBlank(bo.getOperator()), "mpid.operator", bo.getOperator());
|
||||
qw.eq("mpid.del_flag", 0);
|
||||
qw.orderByDesc("mpid.in_time");
|
||||
return qw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MatProductInDetailVo> queryList(MatProductInDetailBo bo) {
|
||||
LambdaQueryWrapper<MatProductInDetail> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MatProductInDetail> buildQueryWrapper(MatProductInDetailBo bo) {
|
||||
LambdaQueryWrapper<MatProductInDetail> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getProductId() != null, MatProductInDetail::getProductId, bo.getProductId());
|
||||
lqw.eq(bo.getInNum() != null, MatProductInDetail::getInNum, bo.getInNum());
|
||||
lqw.eq(bo.getInTime() != null, MatProductInDetail::getInTime, bo.getInTime());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getOperator()), MatProductInDetail::getOperator, bo.getOperator());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBoWithInventory(MatProductInDetailBo bo) {
|
||||
if (bo.getProductId() == null) {
|
||||
throw new IllegalArgumentException("产品不能为空");
|
||||
}
|
||||
if (bo.getInNum() == null || bo.getInNum().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("入库数量必须大于0");
|
||||
}
|
||||
if (bo.getInTime() == null) {
|
||||
bo.setInTime(new Date());
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getOperator())) {
|
||||
bo.setOperator("-");
|
||||
}
|
||||
|
||||
MatProductInDetail add = BeanUtil.toBean(bo, MatProductInDetail.class);
|
||||
boolean ok = baseMapper.insert(add) > 0;
|
||||
if (!ok) {
|
||||
throw new IllegalStateException("入库记录保存失败");
|
||||
}
|
||||
bo.setDetailId(add.getDetailId());
|
||||
|
||||
updateProductStock(bo.getProductId(), bo.getInNum());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(MatProductInDetailBo bo) {
|
||||
MatProductInDetail update = BeanUtil.toBean(bo, MatProductInDetail.class);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIdsWithInventory(Collection<Long> ids, Boolean isValid) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return false;
|
||||
}
|
||||
List<MatProductInDetailVo> records = baseMapper.selectVoBatchIds(ids);
|
||||
if (records == null || records.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ok = baseMapper.deleteBatchIds(ids) > 0;
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (MatProductInDetailVo r : records) {
|
||||
if (r.getProductId() == null || r.getInNum() == null) {
|
||||
continue;
|
||||
}
|
||||
revertProductStock(r.getProductId(), r.getInNum());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateProductStock(Long productId, BigDecimal qty) {
|
||||
MatProduct product = matProductMapper.selectById(productId);
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("产品不存在,productId=" + productId);
|
||||
}
|
||||
BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock();
|
||||
BigDecimal next = current.add(qty);
|
||||
product.setCurrentStock(next);
|
||||
int affected = matProductMapper.updateById(product);
|
||||
if (affected <= 0) {
|
||||
throw new IllegalStateException("更新产品库存失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void revertProductStock(Long productId, BigDecimal qty) {
|
||||
MatProduct product = matProductMapper.selectById(productId);
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("产品不存在,productId=" + productId);
|
||||
}
|
||||
BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock();
|
||||
BigDecimal next = current.subtract(qty);
|
||||
if (next.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException("库存不足,无法撤回入库");
|
||||
}
|
||||
product.setCurrentStock(next);
|
||||
int affected = matProductMapper.updateById(product);
|
||||
if (affected <= 0) {
|
||||
throw new IllegalStateException("更新产品库存失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
package com.gear.mat.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gear.common.core.domain.PageQuery;
|
||||
import com.gear.common.core.page.TableDataInfo;
|
||||
import com.gear.common.utils.StringUtils;
|
||||
import com.gear.mat.domain.MatProduct;
|
||||
import com.gear.mat.domain.MatProductOutsourceOrder;
|
||||
import com.gear.mat.domain.bo.MatProductOutsourceOrderBo;
|
||||
import com.gear.mat.domain.vo.MatProductOutsourceOrderVo;
|
||||
import com.gear.mat.mapper.MatProductMapper;
|
||||
import com.gear.mat.mapper.MatProductOutsourceOrderMapper;
|
||||
import com.gear.mat.service.IMatProductOutsourceOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MatProductOutsourceOrderServiceImpl implements IMatProductOutsourceOrderService {
|
||||
|
||||
private static final String PRODUCT_TYPE_SEMI = "semi";
|
||||
|
||||
private final MatProductOutsourceOrderMapper baseMapper;
|
||||
private final MatProductMapper matProductMapper;
|
||||
|
||||
@Override
|
||||
public MatProductOutsourceOrderVo queryById(Long orderId) {
|
||||
return baseMapper.selectVoById(orderId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<MatProductOutsourceOrderVo> queryPageList(MatProductOutsourceOrderBo bo, PageQuery pageQuery) {
|
||||
QueryWrapper<MatProductOutsourceOrder> qw = buildQueryWrapperPlus(bo);
|
||||
Page<MatProductOutsourceOrderVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), qw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
private QueryWrapper<MatProductOutsourceOrder> buildQueryWrapperPlus(MatProductOutsourceOrderBo bo) {
|
||||
QueryWrapper<MatProductOutsourceOrder> qw = Wrappers.query();
|
||||
qw.eq(bo.getProductId() != null, "mo.product_id", bo.getProductId());
|
||||
qw.eq(bo.getCustomerId() != null, "mo.customer_id", bo.getCustomerId());
|
||||
qw.like(StringUtils.isNotBlank(bo.getCustomerName()), "mo.customer_name", bo.getCustomerName());
|
||||
qw.eq(StringUtils.isNotBlank(bo.getOperator()), "mo.operator", bo.getOperator());
|
||||
qw.ge(bo.getBeginTime() != null, "mo.out_time", bo.getBeginTime());
|
||||
qw.le(bo.getEndTime() != null, "mo.out_time", bo.getEndTime());
|
||||
qw.eq("mo.del_flag", 0);
|
||||
qw.orderByDesc("mo.out_time");
|
||||
return qw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MatProductOutsourceOrderVo> queryList(MatProductOutsourceOrderBo bo) {
|
||||
QueryWrapper<MatProductOutsourceOrder> qw = buildQueryWrapperPlus(bo);
|
||||
return baseMapper.selectVoList(qw);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBoWithInventory(MatProductOutsourceOrderBo bo) {
|
||||
if (bo.getProductId() == null) {
|
||||
throw new IllegalArgumentException("半成品不能为空");
|
||||
}
|
||||
if (bo.getQuantity() == null || bo.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("委派数量必须大于0");
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getCustomerName()) && bo.getCustomerId() == null) {
|
||||
throw new IllegalArgumentException("委托公司不能为空");
|
||||
}
|
||||
|
||||
MatProduct product = matProductMapper.selectById(bo.getProductId());
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("半成品不存在");
|
||||
}
|
||||
if (!PRODUCT_TYPE_SEMI.equals(product.getProductType())) {
|
||||
throw new IllegalArgumentException("只能委外半成品");
|
||||
}
|
||||
|
||||
BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock();
|
||||
if (current.compareTo(bo.getQuantity()) < 0) {
|
||||
throw new IllegalArgumentException("库存不足,无法委外出库");
|
||||
}
|
||||
|
||||
if (bo.getOutTime() == null) {
|
||||
bo.setOutTime(new Date());
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getOperator())) {
|
||||
bo.setOperator("-");
|
||||
}
|
||||
if (StringUtils.isBlank(bo.getOrderNo())) {
|
||||
bo.setOrderNo(generateOrderNo());
|
||||
}
|
||||
|
||||
MatProductOutsourceOrder add = BeanUtil.toBean(bo, MatProductOutsourceOrder.class);
|
||||
add.setProductTypeSnapshot(product.getProductType());
|
||||
add.setReceivedQty(BigDecimal.ZERO);
|
||||
add.setReceiveFlag(0);
|
||||
boolean ok = baseMapper.insert(add) > 0;
|
||||
if (!ok) {
|
||||
throw new IllegalStateException("委外单保存失败");
|
||||
}
|
||||
bo.setOrderId(add.getOrderId());
|
||||
|
||||
product.setCurrentStock(current.subtract(bo.getQuantity()));
|
||||
int affected = matProductMapper.updateById(product);
|
||||
if (affected <= 0) {
|
||||
throw new IllegalStateException("扣减库存失败");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean receive(Long orderId, BigDecimal receiveQty, Date receiveTime, String receiveBy) {
|
||||
if (orderId == null) {
|
||||
throw new IllegalArgumentException("委外单不能为空");
|
||||
}
|
||||
if (receiveQty == null || receiveQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("收回数量必须大于0");
|
||||
}
|
||||
MatProductOutsourceOrder order = baseMapper.selectById(orderId);
|
||||
if (order == null) {
|
||||
throw new IllegalArgumentException("委外单不存在");
|
||||
}
|
||||
if (order.getDelFlag() != null && order.getDelFlag() != 0) {
|
||||
throw new IllegalArgumentException("委外单已撤回");
|
||||
}
|
||||
if (!PRODUCT_TYPE_SEMI.equals(order.getProductTypeSnapshot())) {
|
||||
throw new IllegalArgumentException("只能收回半成品委外单");
|
||||
}
|
||||
BigDecimal total = order.getQuantity() == null ? BigDecimal.ZERO : order.getQuantity();
|
||||
BigDecimal received = order.getReceivedQty() == null ? BigDecimal.ZERO : order.getReceivedQty();
|
||||
BigDecimal remaining = total.subtract(received);
|
||||
if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new IllegalArgumentException("已全部收回");
|
||||
}
|
||||
if (receiveQty.compareTo(remaining) > 0) {
|
||||
throw new IllegalArgumentException("收回数量不能大于未收回数量");
|
||||
}
|
||||
|
||||
MatProduct product = matProductMapper.selectById(order.getProductId());
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("半成品不存在");
|
||||
}
|
||||
BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock();
|
||||
product.setCurrentStock(current.add(receiveQty));
|
||||
int affected = matProductMapper.updateById(product);
|
||||
if (affected <= 0) {
|
||||
throw new IllegalStateException("更新库存失败");
|
||||
}
|
||||
|
||||
BigDecimal nextReceived = received.add(receiveQty);
|
||||
order.setReceivedQty(nextReceived);
|
||||
order.setReceiveTime(receiveTime == null ? new Date() : receiveTime);
|
||||
order.setReceiveBy(StringUtils.isBlank(receiveBy) ? "-" : receiveBy);
|
||||
order.setReceiveFlag(nextReceived.compareTo(total) >= 0 ? 1 : 0);
|
||||
int updated = baseMapper.updateById(order);
|
||||
if (updated <= 0) {
|
||||
throw new IllegalStateException("更新委外单失败");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIdsWithInventory(Collection<Long> ids, Boolean isValid) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return false;
|
||||
}
|
||||
List<MatProductOutsourceOrder> records = baseMapper.selectBatchIds(ids);
|
||||
if (records == null || records.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (MatProductOutsourceOrder r : records) {
|
||||
if (r.getProductId() == null || r.getQuantity() == null) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal received = r.getReceivedQty() == null ? BigDecimal.ZERO : r.getReceivedQty();
|
||||
if (received.compareTo(BigDecimal.ZERO) > 0) {
|
||||
throw new IllegalArgumentException("已收回的委外单不可撤回");
|
||||
}
|
||||
revertStock(r.getProductId(), r.getQuantity());
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
private void revertStock(Long productId, BigDecimal qty) {
|
||||
MatProduct product = matProductMapper.selectById(productId);
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("半成品不存在");
|
||||
}
|
||||
BigDecimal current = product.getCurrentStock() == null ? BigDecimal.ZERO : product.getCurrentStock();
|
||||
product.setCurrentStock(current.add(qty));
|
||||
int affected = matProductMapper.updateById(product);
|
||||
if (affected <= 0) {
|
||||
throw new IllegalStateException("回滚库存失败");
|
||||
}
|
||||
}
|
||||
|
||||
private String generateOrderNo() {
|
||||
String ts = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
||||
int rnd = (int) (Math.random() * 9000) + 1000;
|
||||
return "WW" + ts + rnd;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.gear.mat.service.IMatProductMaterialRelationService;
|
||||
import com.gear.mat.domain.vo.MatMaterialVo;
|
||||
import com.gear.mat.domain.vo.MatProductMaterialRelationVo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
@@ -40,6 +41,9 @@ import java.util.ArrayList;
|
||||
@Service
|
||||
public class MatProductServiceImpl implements IMatProductService {
|
||||
|
||||
private static final String PRODUCT_TYPE_PRODUCT = "product";
|
||||
private static final String PRODUCT_TYPE_SEMI = "semi";
|
||||
|
||||
private final MatProductMapper baseMapper;
|
||||
private final IMatMaterialService matMaterialService;
|
||||
private final IMatProductMaterialRelationService productMaterialRelationService;
|
||||
@@ -73,12 +77,12 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MatProduct> buildQueryWrapper(MatProductBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<MatProduct> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getProductName()), MatProduct::getProductName, bo.getProductName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getSpec()), MatProduct::getSpec, bo.getSpec());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getModel()), MatProduct::getModel, bo.getModel());
|
||||
lqw.eq(bo.getUnitPrice() != null, MatProduct::getUnitPrice, bo.getUnitPrice());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getProductType()), MatProduct::getProductType, bo.getProductType());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@@ -113,6 +117,8 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
productWithMaterialsVo.setSpec(productVo.getSpec());
|
||||
productWithMaterialsVo.setModel(productVo.getModel());
|
||||
productWithMaterialsVo.setUnitPrice(productVo.getUnitPrice());
|
||||
productWithMaterialsVo.setProductType(productVo.getProductType());
|
||||
productWithMaterialsVo.setCurrentStock(productVo.getCurrentStock());
|
||||
productWithMaterialsVo.setRemark(productVo.getRemark());
|
||||
productWithMaterialsVo.setProductImages(productVo.getProductImages());
|
||||
productWithMaterialsVo.setProductPdfs(productVo.getProductPdfs());
|
||||
@@ -174,6 +180,8 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
public Boolean insertByBo(MatProductBo bo) {
|
||||
System.out.println("插入产品,productPdfs: " + bo.getProductPdfs());
|
||||
MatProduct add = BeanUtil.toBean(bo, MatProduct.class);
|
||||
add.setProductType(normalizeProductType(add.getProductType()));
|
||||
add.setCurrentStock(normalizeCurrentStock(add.getCurrentStock()));
|
||||
System.out.println("转换后,productPdfs: " + add.getProductPdfs());
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
@@ -190,6 +198,8 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
public Boolean updateByBo(MatProductBo bo) {
|
||||
System.out.println("修改产品,productPdfs: " + bo.getProductPdfs());
|
||||
MatProduct update = BeanUtil.toBean(bo, MatProduct.class);
|
||||
update.setProductType(normalizeProductType(update.getProductType()));
|
||||
update.setCurrentStock(normalizeCurrentStock(update.getCurrentStock()));
|
||||
System.out.println("转换后,productPdfs: " + update.getProductPdfs());
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
@@ -245,6 +255,8 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
data.setModel(model);
|
||||
data.setUnitPrice(row.getUnitPrice());
|
||||
data.setRemark(row.getRemark());
|
||||
data.setProductType(normalizeProductType(data.getProductType()));
|
||||
data.setCurrentStock(normalizeCurrentStock(data.getCurrentStock()));
|
||||
if (exist == null) {
|
||||
baseMapper.insert(data);
|
||||
} else {
|
||||
@@ -254,4 +266,22 @@ public class MatProductServiceImpl implements IMatProductService {
|
||||
}
|
||||
return "导入完成,成功 " + success + " 条,跳过 " + skipped + " 条";
|
||||
}
|
||||
|
||||
private String normalizeProductType(String productType) {
|
||||
String val = StringUtils.trim(productType);
|
||||
if (StringUtils.isBlank(val)) {
|
||||
return PRODUCT_TYPE_PRODUCT;
|
||||
}
|
||||
if (PRODUCT_TYPE_SEMI.equals(val)) {
|
||||
return PRODUCT_TYPE_SEMI;
|
||||
}
|
||||
if (PRODUCT_TYPE_PRODUCT.equals(val)) {
|
||||
return PRODUCT_TYPE_PRODUCT;
|
||||
}
|
||||
return PRODUCT_TYPE_PRODUCT;
|
||||
}
|
||||
|
||||
private BigDecimal normalizeCurrentStock(BigDecimal currentStock) {
|
||||
return currentStock == null ? BigDecimal.ZERO : currentStock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.gear.mat.mapper.MatProductInDetailMapper">
|
||||
|
||||
<resultMap type="com.gear.mat.domain.MatProductInDetail" id="MatProductInDetailResult">
|
||||
<result property="detailId" column="detail_id"/>
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="inNum" column="in_num"/>
|
||||
<result property="inTime" column="in_time"/>
|
||||
<result property="operator" column="operator"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<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="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectVoPagePlus" resultType="com.gear.mat.domain.vo.MatProductInDetailVo">
|
||||
select mpid.detail_id AS detailId,
|
||||
mpid.product_id AS productId,
|
||||
mpid.in_num AS inNum,
|
||||
mpid.in_time AS inTime,
|
||||
mpid.operator AS operator,
|
||||
mpid.create_time AS createTime,
|
||||
mpid.create_by AS createBy,
|
||||
mpid.update_time AS updateTime,
|
||||
mpid.update_by AS updateBy,
|
||||
mpid.remark AS remark,
|
||||
mp.product_name AS productName,
|
||||
mp.spec AS spec,
|
||||
mp.model AS model,
|
||||
mp.product_type AS productType,
|
||||
mp.current_stock AS currentStock
|
||||
FROM mat_product_in_detail mpid
|
||||
LEFT JOIN mat_product mp ON mpid.product_id = mp.product_id AND mp.del_flag = 0
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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.gear.mat.mapper.MatProductOutsourceOrderMapper">
|
||||
|
||||
<resultMap type="com.gear.mat.domain.MatProductOutsourceOrder" id="MatProductOutsourceOrderResult">
|
||||
<result property="orderId" column="order_id"/>
|
||||
<result property="orderNo" column="order_no"/>
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="productTypeSnapshot" column="product_type_snapshot"/>
|
||||
<result property="customerId" column="customer_id"/>
|
||||
<result property="customerName" column="customer_name"/>
|
||||
<result property="quantity" column="quantity"/>
|
||||
<result property="outTime" column="out_time"/>
|
||||
<result property="operator" column="operator"/>
|
||||
<result property="receivedQty" column="received_qty"/>
|
||||
<result property="receiveFlag" column="receive_flag"/>
|
||||
<result property="receiveTime" column="receive_time"/>
|
||||
<result property="receiveBy" column="receive_by"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<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="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectVoPagePlus" resultType="com.gear.mat.domain.vo.MatProductOutsourceOrderVo">
|
||||
select mo.order_id AS orderId,
|
||||
mo.order_no AS orderNo,
|
||||
mo.product_id AS productId,
|
||||
mp.product_name AS productName,
|
||||
mp.spec AS spec,
|
||||
mp.model AS model,
|
||||
mo.product_type_snapshot AS productTypeSnapshot,
|
||||
mo.customer_id AS customerId,
|
||||
mo.customer_name AS customerName,
|
||||
mo.quantity AS quantity,
|
||||
mo.received_qty AS receivedQty,
|
||||
mo.receive_flag AS receiveFlag,
|
||||
mo.out_time AS outTime,
|
||||
mo.receive_time AS receiveTime,
|
||||
mo.receive_by AS receiveBy,
|
||||
mo.operator AS operator,
|
||||
mo.remark AS remark,
|
||||
mo.create_time AS createTime,
|
||||
mo.create_by AS createBy,
|
||||
mo.update_time AS updateTime,
|
||||
mo.update_by AS updateBy
|
||||
FROM mat_product_outsource_order mo
|
||||
LEFT JOIN mat_product mp ON mo.product_id = mp.product_id AND mp.del_flag = 0
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -15,14 +15,19 @@ import com.gear.oa.domain.bo.GearStockIoOrderWithDetailBo;
|
||||
import com.gear.oa.domain.vo.GearStockIoOrderVo;
|
||||
import com.gear.oa.domain.vo.GearStockIoOrderWithDetailVo;
|
||||
import com.gear.oa.service.IGearStockIoOrderService;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -55,6 +60,187 @@ public class GearStockIoOrderController extends BaseController {
|
||||
return R.ok(stockIoOrderService.queryMaterialFlow(itemId, startTime, endTime));
|
||||
}
|
||||
|
||||
@Log(title = "物料出入库统计", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/materialFlow/export")
|
||||
public void exportMaterialFlow(@NotNull(message = "物料ID不能为空") @RequestParam Long itemId,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime,
|
||||
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date endTime,
|
||||
HttpServletResponse response) {
|
||||
IGearStockIoOrderService.MaterialFlowResp resp = stockIoOrderService.queryMaterialFlow(itemId, startTime, endTime);
|
||||
List<MaterialFlowExportRow> exportRows = new ArrayList<>();
|
||||
|
||||
MaterialFlowExportRow summary = new MaterialFlowExportRow();
|
||||
summary.setItemId(resp.getItemId());
|
||||
summary.setStartTime(resp.getStartTime());
|
||||
summary.setEndTime(resp.getEndTime());
|
||||
summary.setAction("汇总");
|
||||
summary.setConfirmInQty(nz(resp.getConfirmInQty()));
|
||||
summary.setOutQty(nz(resp.getOutQty()));
|
||||
summary.setRevokeInQty(nz(resp.getRevokeInQty()));
|
||||
summary.setRevokeOutQty(nz(resp.getRevokeOutQty()));
|
||||
summary.setNetQty(nz(resp.getNetQty()));
|
||||
exportRows.add(summary);
|
||||
|
||||
if (resp.getRows() != null) {
|
||||
for (IGearStockIoOrderService.MaterialFlowRow r : resp.getRows()) {
|
||||
MaterialFlowExportRow row = new MaterialFlowExportRow();
|
||||
row.setItemId(resp.getItemId());
|
||||
row.setTime(r.getTime());
|
||||
row.setAction(r.getAction());
|
||||
row.setOrderCode(r.getOrderCode());
|
||||
row.setIoType(r.getIoType());
|
||||
row.setQtyChange(r.getQtyChange());
|
||||
exportRows.add(row);
|
||||
}
|
||||
}
|
||||
|
||||
ExcelUtil.exportExcel(exportRows, "物料出入库统计", MaterialFlowExportRow.class, response);
|
||||
}
|
||||
|
||||
private static BigDecimal nz(BigDecimal v) {
|
||||
return v == null ? BigDecimal.ZERO : v;
|
||||
}
|
||||
|
||||
@ExcelIgnoreUnannotated
|
||||
public static class MaterialFlowExportRow {
|
||||
@ExcelProperty(value = "物料ID")
|
||||
private Long itemId;
|
||||
@ExcelProperty(value = "开始时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date startTime;
|
||||
@ExcelProperty(value = "结束时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date endTime;
|
||||
@ExcelProperty(value = "确认入库汇总")
|
||||
private BigDecimal confirmInQty;
|
||||
@ExcelProperty(value = "出库汇总")
|
||||
private BigDecimal outQty;
|
||||
@ExcelProperty(value = "撤回入库汇总")
|
||||
private BigDecimal revokeInQty;
|
||||
@ExcelProperty(value = "撤回出库汇总")
|
||||
private BigDecimal revokeOutQty;
|
||||
@ExcelProperty(value = "净变动汇总")
|
||||
private BigDecimal netQty;
|
||||
@ExcelProperty(value = "明细时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date time;
|
||||
@ExcelProperty(value = "动作")
|
||||
private String action;
|
||||
@ExcelProperty(value = "单号")
|
||||
private String orderCode;
|
||||
@ExcelProperty(value = "类型")
|
||||
private String ioType;
|
||||
@ExcelProperty(value = "数量变化")
|
||||
private BigDecimal qtyChange;
|
||||
|
||||
public Long getItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
public void setItemId(Long itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Date startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Date endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public BigDecimal getConfirmInQty() {
|
||||
return confirmInQty;
|
||||
}
|
||||
|
||||
public void setConfirmInQty(BigDecimal confirmInQty) {
|
||||
this.confirmInQty = confirmInQty;
|
||||
}
|
||||
|
||||
public BigDecimal getOutQty() {
|
||||
return outQty;
|
||||
}
|
||||
|
||||
public void setOutQty(BigDecimal outQty) {
|
||||
this.outQty = outQty;
|
||||
}
|
||||
|
||||
public BigDecimal getRevokeInQty() {
|
||||
return revokeInQty;
|
||||
}
|
||||
|
||||
public void setRevokeInQty(BigDecimal revokeInQty) {
|
||||
this.revokeInQty = revokeInQty;
|
||||
}
|
||||
|
||||
public BigDecimal getRevokeOutQty() {
|
||||
return revokeOutQty;
|
||||
}
|
||||
|
||||
public void setRevokeOutQty(BigDecimal revokeOutQty) {
|
||||
this.revokeOutQty = revokeOutQty;
|
||||
}
|
||||
|
||||
public BigDecimal getNetQty() {
|
||||
return netQty;
|
||||
}
|
||||
|
||||
public void setNetQty(BigDecimal netQty) {
|
||||
this.netQty = netQty;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getOrderCode() {
|
||||
return orderCode;
|
||||
}
|
||||
|
||||
public void setOrderCode(String orderCode) {
|
||||
this.orderCode = orderCode;
|
||||
}
|
||||
|
||||
public String getIoType() {
|
||||
return ioType;
|
||||
}
|
||||
|
||||
public void setIoType(String ioType) {
|
||||
this.ioType = ioType;
|
||||
}
|
||||
|
||||
public BigDecimal getQtyChange() {
|
||||
return qtyChange;
|
||||
}
|
||||
|
||||
public void setQtyChange(BigDecimal qtyChange) {
|
||||
this.qtyChange = qtyChange;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{orderId}")
|
||||
public R<GearStockIoOrderVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long orderId) {
|
||||
return R.ok(stockIoOrderService.queryById(orderId));
|
||||
|
||||
40
gear-ui3/src/api/mat/productInDetail.js
Normal file
40
gear-ui3/src/api/mat/productInDetail.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listProductInDetail(query) {
|
||||
return request({
|
||||
url: '/mat/productInDetail/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getProductInDetail(detailId) {
|
||||
return request({
|
||||
url: '/mat/productInDetail/' + detailId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addProductInDetail(data) {
|
||||
return request({
|
||||
url: '/mat/productInDetail',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateProductInDetail(data) {
|
||||
return request({
|
||||
url: '/mat/productInDetail',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delProductInDetail(detailId) {
|
||||
return request({
|
||||
url: '/mat/productInDetail/' + detailId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
39
gear-ui3/src/api/mat/productOutsourceOrder.js
Normal file
39
gear-ui3/src/api/mat/productOutsourceOrder.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listProductOutsourceOrder(query) {
|
||||
return request({
|
||||
url: '/mat/productOutsourceOrder/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getProductOutsourceOrder(orderId) {
|
||||
return request({
|
||||
url: '/mat/productOutsourceOrder/' + orderId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addProductOutsourceOrder(data) {
|
||||
return request({
|
||||
url: '/mat/productOutsourceOrder',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delProductOutsourceOrder(orderId) {
|
||||
return request({
|
||||
url: '/mat/productOutsourceOrder/' + orderId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function receiveProductOutsourceOrder(orderId, data) {
|
||||
return request({
|
||||
url: '/mat/productOutsourceOrder/receive/' + orderId,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -17,6 +17,14 @@
|
||||
<el-descriptions-item label="产品名称">
|
||||
{{ productDetail.productName || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="产品类型">
|
||||
<el-tag :type="productTypeTagType(productDetail.productType)" effect="dark">
|
||||
{{ productTypeLabel(productDetail.productType) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="库存">
|
||||
{{ formatDecimal(productDetail.currentStock) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="产品单价">
|
||||
{{ formatDecimal(productDetail.unitPrice) }} 元
|
||||
</el-descriptions-item>
|
||||
@@ -188,6 +196,9 @@ import { Document } from '@element-plus/icons-vue';
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '产品');
|
||||
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
|
||||
|
||||
const productDetail = ref({});
|
||||
const loading = ref(true);
|
||||
const materialLoading = ref(false);
|
||||
|
||||
@@ -40,6 +40,13 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="产品ID 主键" align="center" prop="productId" v-if="false" />
|
||||
<el-table-column label="产品名称" align="center" prop="productName" />
|
||||
<el-table-column label="产品类型" align="center" prop="productType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="productTypeTagType(scope.row.productType)" effect="dark">
|
||||
{{ productTypeLabel(scope.row.productType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品规格" align="center" prop="spec" />
|
||||
<el-table-column label="产品型号" align="center" prop="model" />
|
||||
<el-table-column label="产品单价" align="center" prop="unitPrice">
|
||||
@@ -47,6 +54,11 @@
|
||||
{{ formatDecimal(scope.row.unitPrice) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="库存" align="center" prop="currentStock" width="120">
|
||||
<template #default="scope">
|
||||
{{ formatDecimal(scope.row.currentStock) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附加属性" align="center" min-width="160">
|
||||
<template #default="scope">
|
||||
<el-tooltip
|
||||
@@ -132,9 +144,24 @@
|
||||
<el-form-item label="产品型号" prop="model">
|
||||
<el-input v-model="form.model" placeholder="请输入产品型号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品类型" prop="productType">
|
||||
<el-select v-model="form.productType" placeholder="请选择产品类型" style="width: 100%">
|
||||
<el-option label="产品" value="product" />
|
||||
<el-option label="半成品" value="semi" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品单价" prop="unitPrice">
|
||||
<el-input v-model="form.unitPrice" placeholder="请输入产品单价" />
|
||||
</el-form-item>
|
||||
<el-form-item label="库存" prop="currentStock">
|
||||
<el-input-number
|
||||
v-model="form.currentStock"
|
||||
style="width: 100%"
|
||||
:controls="false"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
@@ -403,12 +430,17 @@ const formatterTime = (time) => {
|
||||
return proxy.parseTime(time, '{y}-{m}-{d}')
|
||||
}
|
||||
|
||||
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '产品');
|
||||
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
|
||||
|
||||
const data = reactive({
|
||||
form: {
|
||||
productId: null,
|
||||
productName: null,
|
||||
spec: null,
|
||||
model: null,
|
||||
productType: 'product',
|
||||
currentStock: 0,
|
||||
unitPrice: null,
|
||||
delFlag: null,
|
||||
createTime: null,
|
||||
@@ -456,6 +488,8 @@ function reset() {
|
||||
productName: null,
|
||||
spec: null,
|
||||
model: null,
|
||||
productType: 'product',
|
||||
currentStock: 0,
|
||||
unitPrice: null,
|
||||
delFlag: null,
|
||||
createTime: null,
|
||||
@@ -506,6 +540,12 @@ function handleUpdate(row) {
|
||||
getProduct(_productId).then(response => {
|
||||
loading.value = false;
|
||||
form.value = response.data;
|
||||
if (!form.value.productType) {
|
||||
form.value.productType = 'product';
|
||||
}
|
||||
if (form.value.currentStock === null || form.value.currentStock === undefined) {
|
||||
form.value.currentStock = 0;
|
||||
}
|
||||
|
||||
// 处理图片文件列表
|
||||
if (form.value.productImages) {
|
||||
@@ -692,6 +732,8 @@ function submitForm() {
|
||||
productName: form.value.productName,
|
||||
spec: form.value.spec,
|
||||
model: form.value.model,
|
||||
productType: form.value.productType,
|
||||
currentStock: form.value.currentStock,
|
||||
unitPrice: form.value.unitPrice,
|
||||
remark: form.value.remark,
|
||||
productImages: form.value.productImages,
|
||||
|
||||
288
gear-ui3/src/views/mat/productIn/index.vue
Normal file
288
gear-ui3/src/views/mat/productIn/index.vue
Normal file
@@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="产品" prop="productId">
|
||||
<el-select
|
||||
v-model="queryParams.productId"
|
||||
placeholder="请选择产品"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteSearchProducts"
|
||||
:loading="productLoading"
|
||||
style="width: 260px"
|
||||
>
|
||||
<el-option
|
||||
v-for="p in productOptions"
|
||||
:key="p.productId"
|
||||
:label="productOptionLabel(p)"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人" prop="operator">
|
||||
<el-input v-model="queryParams.operator" placeholder="请输入入库操作人" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">撤回</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="明细ID" align="center" prop="detailId" v-if="false" />
|
||||
<el-table-column label="产品" align="center" min-width="240">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.productName || '-' }}</div>
|
||||
<div style="color:#909399;font-size:12px;">
|
||||
{{ [scope.row.spec, scope.row.model].filter(Boolean).join(' / ') }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品类型" align="center" prop="productType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="productTypeTagType(scope.row.productType)" effect="dark">
|
||||
{{ productTypeLabel(scope.row.productType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入库数量" align="center" prop="inNum" width="140">
|
||||
<template #default="scope">
|
||||
{{ formatDecimal(scope.row.inNum) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="入库时间" align="center" prop="inTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ formatterTime(scope.row.inTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作人" align="center" prop="operator" width="120" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">撤回</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="产品" prop="productId">
|
||||
<el-select
|
||||
v-model="form.productId"
|
||||
placeholder="请选择产品"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteSearchProducts"
|
||||
:loading="productLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="p in productOptions"
|
||||
:key="p.productId"
|
||||
:label="productOptionLabel(p)"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="入库数量" prop="inNum">
|
||||
<el-input-number v-model="form.inNum" style="width: 100%" :controls="false" :min="0" :precision="4" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入库时间" prop="inTime">
|
||||
<el-date-picker clearable v-model="form.inTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择入库时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人" prop="operator">
|
||||
<el-input v-model="form.operator" placeholder="请输入入库操作人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ProductInDetail">
|
||||
import { listProductInDetail, delProductInDetail, addProductInDetail } from "@/api/mat/productInDetail";
|
||||
import { listProductBase } from "@/api/mat/product";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { formatDecimal } from '@/utils/gear'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const list = ref([]);
|
||||
const open = ref(false);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
|
||||
const productOptions = ref([]);
|
||||
const productLoading = ref(false);
|
||||
|
||||
const formatterTime = (time) => {
|
||||
return proxy.parseTime(time, '{y}-{m}-{d}')
|
||||
}
|
||||
|
||||
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '成品');
|
||||
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
|
||||
|
||||
const productOptionLabel = (p) => {
|
||||
const name = p?.productName || '-';
|
||||
const parts = [p?.spec, p?.model].filter(Boolean);
|
||||
const typeText = p?.productType === 'semi' ? '半成品' : '成品';
|
||||
const base = parts.length ? `${name}(${parts.join(' / ')})` : name;
|
||||
return `${typeText} - ${base}`;
|
||||
};
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
productId: undefined,
|
||||
inNum: undefined,
|
||||
inTime: undefined,
|
||||
operator: undefined,
|
||||
},
|
||||
rules: {
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
listProductInDetail(queryParams.value).then(response => {
|
||||
list.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
open.value = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
const nickName = computed(() => userStore.nickName)
|
||||
|
||||
function reset() {
|
||||
const inTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
form.value = {
|
||||
detailId: null,
|
||||
productId: null,
|
||||
inNum: null,
|
||||
inTime: inTime,
|
||||
operator: nickName,
|
||||
remark: null
|
||||
};
|
||||
proxy.resetForm("formRef");
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef");
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.detailId);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "添加产品入库单";
|
||||
remoteSearchProducts('');
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
if (buttonLoading.value) return;
|
||||
proxy.$refs["formRef"].validate(valid => {
|
||||
if (!valid) return;
|
||||
buttonLoading.value = true;
|
||||
addProductInDetail(form.value).then(() => {
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
}).finally(() => {
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
const _detailIds = row?.detailId || ids.value;
|
||||
proxy.$modal.confirm('是否确认撤回入库记录编号为"' + _detailIds + '"的数据项?').then(function () {
|
||||
loading.value = true;
|
||||
return delProductInDetail(_detailIds);
|
||||
}).then(() => {
|
||||
loading.value = true;
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("撤回成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
proxy.download('mat/productInDetail/export', {
|
||||
...queryParams.value
|
||||
}, `product_in_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
function remoteSearchProducts(keyword) {
|
||||
productLoading.value = true;
|
||||
listProductBase({ pageNum: 1, pageSize: 50, productName: keyword || undefined }).then(res => {
|
||||
productOptions.value = res.rows || [];
|
||||
}).finally(() => {
|
||||
productLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
getList();
|
||||
remoteSearchProducts('');
|
||||
</script>
|
||||
376
gear-ui3/src/views/mat/productOutsource/index.vue
Normal file
376
gear-ui3/src/views/mat/productOutsource/index.vue
Normal file
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="半成品" prop="productId">
|
||||
<el-select
|
||||
v-model="queryParams.productId"
|
||||
placeholder="请选择半成品"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteSearchProducts"
|
||||
:loading="productLoading"
|
||||
style="width: 260px"
|
||||
>
|
||||
<el-option
|
||||
v-for="p in productOptions"
|
||||
:key="p.productId"
|
||||
:label="productOptionLabel(p)"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="公司" prop="customerName">
|
||||
<el-input v-model="queryParams.customerName" placeholder="请输入委托公司" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人" prop="operator">
|
||||
<el-input v-model="queryParams.operator" placeholder="请输入操作人" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">撤回</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="委外单号" align="center" prop="orderNo" width="170" />
|
||||
<el-table-column label="产品类型" align="center" prop="productTypeSnapshot" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="productTypeTagType(scope.row.productTypeSnapshot)" effect="dark">
|
||||
{{ productTypeLabel(scope.row.productTypeSnapshot) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="半成品" align="center" min-width="240">
|
||||
<template #default="scope">
|
||||
<div>{{ scope.row.productName || '-' }}</div>
|
||||
<div style="color:#909399;font-size:12px;">
|
||||
{{ [scope.row.spec, scope.row.model].filter(Boolean).join(' / ') }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="委托公司" align="center" prop="customerName" min-width="180" />
|
||||
<el-table-column label="委派数量" align="center" prop="quantity" width="140">
|
||||
<template #default="scope">
|
||||
{{ formatDecimal(scope.row.quantity) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已收回" align="center" prop="receivedQty" width="140">
|
||||
<template #default="scope">
|
||||
{{ formatDecimal(scope.row.receivedQty) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收回状态" align="center" width="110">
|
||||
<template #default="scope">
|
||||
<el-tag :type="receiveStatusTagType(scope.row)" effect="dark">
|
||||
{{ receiveStatusText(scope.row) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="委外时间" align="center" prop="outTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ formatterTime(scope.row.outTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作人" align="center" prop="operator" width="120" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Check" :disabled="isFullyReceived(scope.row)" @click="openReceive(scope.row)">收回</el-button>
|
||||
<el-button link type="primary" icon="Delete" :disabled="hasReceived(scope.row)" @click="handleDelete(scope.row)">撤回</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<el-dialog :title="title" v-model="open" width="520px" append-to-body>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
|
||||
<el-form-item label="半成品" prop="productId">
|
||||
<el-select
|
||||
v-model="form.productId"
|
||||
placeholder="请选择半成品"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteSearchProducts"
|
||||
:loading="productLoading"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="p in productOptions"
|
||||
:key="p.productId"
|
||||
:label="productOptionLabel(p)"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="委托公司" prop="customerName">
|
||||
<el-input v-model="form.customerName" placeholder="请输入委托公司" />
|
||||
</el-form-item>
|
||||
<el-form-item label="委派数量" prop="quantity">
|
||||
<el-input-number v-model="form.quantity" style="width: 100%" :controls="false" :min="0" :precision="4" />
|
||||
</el-form-item>
|
||||
<el-form-item label="委外时间" prop="outTime">
|
||||
<el-date-picker clearable v-model="form.outTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择委外时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人" prop="operator">
|
||||
<el-input v-model="form.operator" placeholder="请输入操作人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="收回" v-model="receiveOpen" width="460px" append-to-body>
|
||||
<el-form ref="receiveRef" :model="receiveForm" label-width="90px">
|
||||
<el-form-item label="收回数量">
|
||||
<el-input-number v-model="receiveForm.receiveQty" style="width: 100%" :controls="false" :min="0" :precision="4" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收回时间">
|
||||
<el-date-picker clearable v-model="receiveForm.receiveTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择收回时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收回人">
|
||||
<el-input v-model="receiveForm.receiveBy" placeholder="请输入收回人" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="receiveLoading" type="primary" @click="submitReceive">确 定</el-button>
|
||||
<el-button @click="receiveOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ProductOutsourceOrder">
|
||||
import { listProductOutsourceOrder, addProductOutsourceOrder, delProductOutsourceOrder, receiveProductOutsourceOrder } from "@/api/mat/productOutsourceOrder";
|
||||
import { listProductBase } from "@/api/mat/product";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { formatDecimal } from '@/utils/gear'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const list = ref([]);
|
||||
const open = ref(false);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
|
||||
const productOptions = ref([]);
|
||||
const productLoading = ref(false);
|
||||
|
||||
const receiveOpen = ref(false);
|
||||
const receiveLoading = ref(false);
|
||||
const receiveForm = ref({ orderId: null, receiveQty: null, receiveTime: null, receiveBy: null });
|
||||
|
||||
const formatterTime = (time) => proxy.parseTime(time, '{y}-{m}-{d}')
|
||||
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '成品');
|
||||
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
|
||||
|
||||
const rowQty = (v) => (v === null || v === undefined ? 0 : Number(v) || 0);
|
||||
const hasReceived = (row) => rowQty(row?.receivedQty) > 0;
|
||||
const isFullyReceived = (row) => rowQty(row?.receivedQty) >= rowQty(row?.quantity);
|
||||
const receiveStatusText = (row) => {
|
||||
const totalQty = rowQty(row?.quantity);
|
||||
const receivedQty = rowQty(row?.receivedQty);
|
||||
if (receivedQty <= 0) return '未收回';
|
||||
if (receivedQty >= totalQty) return '已收回';
|
||||
return '部分收回';
|
||||
};
|
||||
const receiveStatusTagType = (row) => {
|
||||
const t = receiveStatusText(row);
|
||||
if (t === '已收回') return 'success';
|
||||
if (t === '部分收回') return 'warning';
|
||||
return 'info';
|
||||
};
|
||||
|
||||
const productOptionLabel = (p) => {
|
||||
const name = p?.productName || '-';
|
||||
const parts = [p?.spec, p?.model].filter(Boolean);
|
||||
return parts.length ? `${name}(${parts.join(' / ')})` : name;
|
||||
};
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
productId: undefined,
|
||||
customerName: undefined,
|
||||
operator: undefined,
|
||||
},
|
||||
rules: {
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
listProductOutsourceOrder(queryParams.value).then(res => {
|
||||
list.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
open.value = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
const nickName = computed(() => userStore.nickName)
|
||||
|
||||
function reset() {
|
||||
const outTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
form.value = {
|
||||
orderId: null,
|
||||
orderNo: null,
|
||||
productId: null,
|
||||
customerId: null,
|
||||
customerName: null,
|
||||
quantity: null,
|
||||
outTime,
|
||||
operator: nickName,
|
||||
remark: null
|
||||
};
|
||||
proxy.resetForm("formRef");
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef");
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.orderId);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "新增半成品委外单";
|
||||
remoteSearchProducts('');
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
if (buttonLoading.value) return;
|
||||
proxy.$refs["formRef"].validate(valid => {
|
||||
if (!valid) return;
|
||||
buttonLoading.value = true;
|
||||
addProductOutsourceOrder(form.value).then(() => {
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
}).finally(() => {
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
const _orderIds = row?.orderId || ids.value;
|
||||
proxy.$modal.confirm('是否确认撤回委外单编号为"' + _orderIds + '"的数据项?').then(function () {
|
||||
loading.value = true;
|
||||
return delProductOutsourceOrder(_orderIds);
|
||||
}).then(() => {
|
||||
loading.value = true;
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("撤回成功");
|
||||
}).catch(() => {
|
||||
}).finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function openReceive(row) {
|
||||
const outTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
const totalQty = rowQty(row?.quantity);
|
||||
const receivedQty = rowQty(row?.receivedQty);
|
||||
const remaining = totalQty - receivedQty;
|
||||
receiveForm.value = {
|
||||
orderId: row?.orderId,
|
||||
receiveQty: remaining > 0 ? remaining : 0,
|
||||
receiveTime: outTime,
|
||||
receiveBy: nickName
|
||||
};
|
||||
receiveOpen.value = true;
|
||||
}
|
||||
|
||||
function submitReceive() {
|
||||
if (receiveLoading.value) return;
|
||||
const orderId = receiveForm.value.orderId;
|
||||
receiveLoading.value = true;
|
||||
receiveProductOutsourceOrder(orderId, {
|
||||
receiveQty: receiveForm.value.receiveQty,
|
||||
receiveTime: receiveForm.value.receiveTime,
|
||||
receiveBy: receiveForm.value.receiveBy
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess("收回成功");
|
||||
receiveOpen.value = false;
|
||||
getList();
|
||||
}).finally(() => {
|
||||
receiveLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
proxy.download('mat/productOutsourceOrder/export', {
|
||||
...queryParams.value
|
||||
}, `product_outsource_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
function remoteSearchProducts(keyword) {
|
||||
productLoading.value = true;
|
||||
listProductBase({ pageNum: 1, pageSize: 50, productName: keyword || undefined, productType: 'semi' }).then(res => {
|
||||
productOptions.value = res.rows || [];
|
||||
}).finally(() => {
|
||||
productLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
getList();
|
||||
remoteSearchProducts('');
|
||||
</script>
|
||||
@@ -30,7 +30,7 @@
|
||||
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
@@ -296,7 +296,7 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
|
||||
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
|
||||
<el-button @click="flowOpen = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -539,29 +539,24 @@ export default {
|
||||
this.flowLoading = false
|
||||
})
|
||||
},
|
||||
printFlow() {
|
||||
const el = this.$refs.flowPrintContent
|
||||
if (!el) return
|
||||
const w = window.open('', '_blank')
|
||||
if (!w) return
|
||||
const html = `
|
||||
<html>
|
||||
<head>
|
||||
<title>物料出入库统计</title>
|
||||
<style>
|
||||
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${el.innerHTML}</body>
|
||||
</html>`
|
||||
w.document.open()
|
||||
w.document.write(html)
|
||||
w.document.close()
|
||||
w.focus()
|
||||
w.print()
|
||||
w.close()
|
||||
exportFlow() {
|
||||
if (!this.flowForm.itemId) {
|
||||
this.$modal.msgError('请选择物料')
|
||||
return
|
||||
}
|
||||
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
|
||||
this.$modal.msgError('请选择时间范围')
|
||||
return
|
||||
}
|
||||
this.download(
|
||||
'/gear/stockIoOrder/materialFlow/export',
|
||||
{
|
||||
itemId: this.flowForm.itemId,
|
||||
startTime: this.flowForm.timeRange[0],
|
||||
endTime: this.flowForm.timeRange[1]
|
||||
},
|
||||
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editFormRef.validate((valid) => {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
@@ -277,7 +277,7 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
|
||||
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
|
||||
<el-button @click="flowOpen = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -497,29 +497,24 @@ export default {
|
||||
this.flowLoading = false
|
||||
})
|
||||
},
|
||||
printFlow() {
|
||||
const el = this.$refs.flowPrintContent
|
||||
if (!el) return
|
||||
const w = window.open('', '_blank')
|
||||
if (!w) return
|
||||
const html = `
|
||||
<html>
|
||||
<head>
|
||||
<title>物料出入库统计</title>
|
||||
<style>
|
||||
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${el.innerHTML}</body>
|
||||
</html>`
|
||||
w.document.open()
|
||||
w.document.write(html)
|
||||
w.document.close()
|
||||
w.focus()
|
||||
w.print()
|
||||
w.close()
|
||||
exportFlow() {
|
||||
if (!this.flowForm.itemId) {
|
||||
this.$modal.msgError('请选择物料')
|
||||
return
|
||||
}
|
||||
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
|
||||
this.$modal.msgError('请选择时间范围')
|
||||
return
|
||||
}
|
||||
this.download(
|
||||
'/gear/stockIoOrder/materialFlow/export',
|
||||
{
|
||||
itemId: this.flowForm.itemId,
|
||||
startTime: this.flowForm.timeRange[0],
|
||||
endTime: this.flowForm.timeRange[1]
|
||||
},
|
||||
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs.editFormRef.validate((valid) => {
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
|
||||
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
@@ -371,7 +371,7 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
|
||||
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
|
||||
<el-button @click="flowOpen = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -694,29 +694,24 @@ export default {
|
||||
this.flowLoading = false
|
||||
})
|
||||
},
|
||||
printFlow() {
|
||||
const el = this.$refs.flowPrintContent
|
||||
if (!el) return
|
||||
const w = window.open('', '_blank')
|
||||
if (!w) return
|
||||
const html = `
|
||||
<html>
|
||||
<head>
|
||||
<title>物料出入库统计</title>
|
||||
<style>
|
||||
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${el.innerHTML}</body>
|
||||
</html>`
|
||||
w.document.open()
|
||||
w.document.write(html)
|
||||
w.document.close()
|
||||
w.focus()
|
||||
w.print()
|
||||
w.close()
|
||||
exportFlow() {
|
||||
if (!this.flowForm.itemId) {
|
||||
this.$modal.msgError('请选择物料')
|
||||
return
|
||||
}
|
||||
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
|
||||
this.$modal.msgError('请选择时间范围')
|
||||
return
|
||||
}
|
||||
this.download(
|
||||
'/gear/stockIoOrder/materialFlow/export',
|
||||
{
|
||||
itemId: this.flowForm.itemId,
|
||||
startTime: this.flowForm.timeRange[0],
|
||||
endTime: this.flowForm.timeRange[1]
|
||||
},
|
||||
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
},
|
||||
showDetail(row) {
|
||||
this.detailOpen = true
|
||||
|
||||
Reference in New Issue
Block a user