diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizRfqController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizRfqController.java index 5546cd52..ad28ea8a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizRfqController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizRfqController.java @@ -9,14 +9,17 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.domain.bid.BizClientQuote; import com.ruoyi.system.domain.bid.BizRfq; import com.ruoyi.system.domain.bid.BizRfqItem; +import com.ruoyi.system.mapper.bid.BizClientQuoteMapper; import com.ruoyi.system.service.bid.IBizRfqService; @RestController @RequestMapping("/bid/rfq") public class BizRfqController extends BaseController { @Autowired private IBizRfqService service; + @Autowired private BizClientQuoteMapper clientQuoteMapper; @PreAuthorize("@ss.hasPermi('bid:rfq:list')") @GetMapping("/list") @@ -42,6 +45,8 @@ public class BizRfqController extends BaseController { @PostMapping public AjaxResult add(@RequestBody BizRfq rfq) { rfq.setCreateBy(getUsername()); + Long tenantId = getDeptId(); + rfq.setTenantId(tenantId != null ? tenantId : 1L); return toAjax(service.insertBizRfq(rfq)); } @@ -66,4 +71,24 @@ public class BizRfqController extends BaseController { public AjaxResult remove(@PathVariable Long[] rfqIds) { return toAjax(service.deleteBizRfqByIds(rfqIds)); } + + // ========== 关联甲方报价 ========== + + /** 获取可选甲方报价列表(下拉选择器用) */ + @PreAuthorize("@ss.hasPermi('bid:rfq:add')") + @GetMapping("/client-quote-options") + public AjaxResult clientQuoteOptions() { + BizClientQuote query = new BizClientQuote(); + List list = clientQuoteMapper.selectClientQuoteList(query); + return success(list); + } + + /** 基于甲方报价快速创建 RFQ */ + @PreAuthorize("@ss.hasPermi('bid:rfq:add')") + @Log(title = "报价请求", businessType = BusinessType.INSERT) + @PostMapping("/create-from-quote/{clientQuoteId}") + public AjaxResult createFromQuote(@PathVariable Long clientQuoteId) { + Long tenantId = getDeptId(); + return success(service.createRfqFromClientQuote(clientQuoteId, tenantId != null ? tenantId : 1L)); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizRfq.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizRfq.java index 4bb6d8f2..d3416249 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizRfq.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizRfq.java @@ -13,6 +13,9 @@ public class BizRfq extends BaseEntity { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date deadline; private String deliveryAddr; + private Long clientQuoteId; + private String clientQuoteNo; + private String clientName; private String status; private List items; private List supplierIds; @@ -29,6 +32,12 @@ public class BizRfq extends BaseEntity { public void setDeadline(Date deadline) { this.deadline = deadline; } public String getDeliveryAddr() { return deliveryAddr; } public void setDeliveryAddr(String deliveryAddr) { this.deliveryAddr = deliveryAddr; } + public Long getClientQuoteId() { return clientQuoteId; } + public void setClientQuoteId(Long clientQuoteId) { this.clientQuoteId = clientQuoteId; } + public String getClientQuoteNo() { return clientQuoteNo; } + public void setClientQuoteNo(String clientQuoteNo) { this.clientQuoteNo = clientQuoteNo; } + public String getClientName() { return clientName; } + public void setClientName(String clientName) { this.clientName = clientName; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public List getItems() { return items; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizRfqMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizRfqMapper.java index 4d648faf..3f134176 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizRfqMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizRfqMapper.java @@ -9,5 +9,6 @@ public interface BizRfqMapper { int insertBizRfq(BizRfq record); int updateBizRfq(BizRfq record); int deleteBizRfqById(Long id); + String selectNextRfqNo(); int deleteBizRfqByIds(Long[] ids); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizRfqService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizRfqService.java index 59c7a134..d442cbfa 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizRfqService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizRfqService.java @@ -13,4 +13,6 @@ public interface IBizRfqService { int deleteBizRfqByIds(Long[] ids); int publishRfq(Long rfqId, Long[] supplierIds); List selectItemsByRfqId(Long rfqId); + /** 基于甲方报价快速创建 RFQ(复制物料明细) */ + BizRfq createRfqFromClientQuote(Long clientQuoteId, Long tenantId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizRfqServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizRfqServiceImpl.java index cf5b4d9b..2614e773 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizRfqServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizRfqServiceImpl.java @@ -1,20 +1,24 @@ package com.ruoyi.system.service.bid.impl; +import com.ruoyi.system.domain.bid.BizClientQuote; +import com.ruoyi.system.domain.bid.BizClientQuoteItem; import com.ruoyi.system.domain.bid.BizRfq; import com.ruoyi.system.domain.bid.BizRfqItem; +import com.ruoyi.system.mapper.bid.BizClientQuoteMapper; import com.ruoyi.system.mapper.bid.BizRfqItemMapper; import com.ruoyi.system.mapper.bid.BizRfqMapper; import com.ruoyi.system.service.bid.IBizRfqService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Date; import java.util.List; +import java.util.stream.Collectors; @Service public class BizRfqServiceImpl implements IBizRfqService { @Autowired private BizRfqMapper rfqMapper; @Autowired private BizRfqItemMapper itemMapper; + @Autowired private BizClientQuoteMapper clientQuoteMapper; @Override public List selectBizRfqList(BizRfq query) { return rfqMapper.selectBizRfqList(query); } @@ -29,6 +33,9 @@ public class BizRfqServiceImpl implements IBizRfqService { @Override @Transactional public int insertBizRfq(BizRfq rfq) { + if (rfq.getRfqNo() == null || rfq.getRfqNo().isBlank()) { + rfq.setRfqNo(rfqMapper.selectNextRfqNo()); + } rfq.setStatus("draft"); int rows = rfqMapper.insertBizRfq(rfq); if (rfq.getItems() != null) { @@ -71,4 +78,50 @@ public class BizRfqServiceImpl implements IBizRfqService { public List selectItemsByRfqId(Long rfqId) { return itemMapper.selectItemsByRfqId(rfqId); } + + @Override + @Transactional + public BizRfq createRfqFromClientQuote(Long clientQuoteId, Long tenantId) { + // 加载甲方报价 + BizClientQuote quote = clientQuoteMapper.selectClientQuoteById(clientQuoteId); + if (quote == null) { + throw new RuntimeException("甲方报价单不存在: " + clientQuoteId); + } + + // 创建 RFQ + BizRfq rfq = new BizRfq(); + rfq.setRfqNo(rfqMapper.selectNextRfqNo()); + rfq.setTenantId(tenantId); + rfq.setRfqTitle("采购需求: " + quote.getClientName() + " - " + quote.getQuoteNo()); + rfq.setClientQuoteId(quote.getQuoteId()); + rfq.setDeliveryAddr(""); + rfq.setStatus("draft"); + rfq.setRemark("源自甲方报价单: " + quote.getQuoteNo()); + + // 复制物料明细 + List sourceItems = clientQuoteMapper.selectItemsByQuoteId(clientQuoteId); + if (sourceItems != null && !sourceItems.isEmpty()) { + rfq.setItems(sourceItems.stream().map(src -> { + BizRfqItem item = new BizRfqItem(); + item.setMaterialId(src.getMaterialId()); + item.setMaterialName(src.getMaterialName()); + item.setSpec(src.getSpec()); + item.setUnit(src.getUnit()); + item.setQuantity(src.getQuantity()); + item.setExpectedPrice(src.getUnitPrice()); + item.setRemark(src.getRemark()); + return item; + }).collect(Collectors.toList())); + } + + rfqMapper.insertBizRfq(rfq); + if (rfq.getItems() != null) { + for (BizRfqItem item : rfq.getItems()) { + item.setRfqId(rfq.getRfqId()); + itemMapper.insertBizRfqItem(item); + } + } + + return rfqMapper.selectBizRfqById(rfq.getRfqId()); + } } diff --git a/ruoyi-system/src/main/resources/mapper/bid/BizRfqMapper.xml b/ruoyi-system/src/main/resources/mapper/bid/BizRfqMapper.xml index c55f8ee8..a911a61f 100644 --- a/ruoyi-system/src/main/resources/mapper/bid/BizRfqMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/bid/BizRfqMapper.xml @@ -9,6 +9,9 @@ + + + @@ -17,22 +20,40 @@ + + SELECT r.*, + cq.quote_no AS clientQuoteNo, + cq.client_name AS clientName + FROM biz_rfq r + LEFT JOIN biz_client_quote cq ON r.client_quote_id = cq.quote_id + + - + + + - INSERT INTO biz_rfq(tenant_id,rfq_no,rfq_title,deadline,delivery_addr,status,remark,create_by,create_time) - VALUES(#{tenantId},#{rfqNo},#{rfqTitle},#{deadline},#{deliveryAddr},#{status},#{remark},#{createBy},NOW()) + INSERT INTO biz_rfq(tenant_id,rfq_no,rfq_title,deadline,delivery_addr,client_quote_id,status,remark,create_by,create_time) + VALUES(#{tenantId},#{rfqNo},#{rfqTitle},#{deadline},#{deliveryAddr},#{clientQuoteId},#{status},#{remark},#{createBy},NOW()) @@ -41,6 +62,7 @@ rfq_title=#{rfqTitle}, deadline=#{deadline}, delivery_addr=#{deliveryAddr}, + client_quote_id=#{clientQuoteId}, status=#{status}, remark=#{remark}, update_by=#{updateBy}, update_time=NOW() diff --git a/ruoyi-ui/src/api/bid/rfq.js b/ruoyi-ui/src/api/bid/rfq.js index 53cf170a..f0de4793 100644 --- a/ruoyi-ui/src/api/bid/rfq.js +++ b/ruoyi-ui/src/api/bid/rfq.js @@ -7,3 +7,7 @@ export const addRfq = (data) => request({ url: baseUrl, method: 'post', data }) export const updateRfq = (data) => request({ url: baseUrl, method: 'put', data }) export const publishRfq = (rfqId, supplierIds) => request({ url: baseUrl + '/publish/' + rfqId, method: 'put', data: supplierIds }) export const delRfq = (ids) => request({ url: baseUrl + '/' + ids, method: 'delete' }) + +// 关联甲方报价 +export const getClientQuoteOptions = () => request({ url: baseUrl + '/client-quote-options', method: 'get' }) +export const createRfqFromQuote = (clientQuoteId) => request({ url: baseUrl + '/create-from-quote/' + clientQuoteId, method: 'post' }) diff --git a/ruoyi-ui/src/views/bid/clientquote/index.vue b/ruoyi-ui/src/views/bid/clientquote/index.vue index 0bb6463e..893c1458 100644 --- a/ruoyi-ui/src/views/bid/clientquote/index.vue +++ b/ruoyi-ui/src/views/bid/clientquote/index.vue @@ -78,12 +78,6 @@ - - -