feat: 新增甲方客户管理模块及配套功能

1. 新增甲方客户CRUD接口、前端页面与权限控制
2. 新增发货单管理模块,包含订单状态流转
3. 修复系统菜单名称乱码问题
4. 新增项目启动脚本与数据库初始化脚本
5. 新增相关实体类、Mapper、Service实现
6. 补充项目设计文档与忽略配置
This commit is contained in:
2026-06-09 21:44:31 +08:00
parent ef9584cdb9
commit bbddcb494d
26 changed files with 2084 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.ruoyi.system.domain.bid;
import com.ruoyi.common.core.domain.BaseEntity;
public class BizClient extends BaseEntity {
private Long clientId;
private Long tenantId;
private String clientNo;
private String clientName;
private String contact;
private String phone;
private String email;
private String city;
private String address;
private String grade;
private String source;
private String status;
public Long getClientId() { return clientId; }
public void setClientId(Long clientId) { this.clientId = clientId; }
public Long getTenantId() { return tenantId; }
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
public String getClientNo() { return clientNo; }
public void setClientNo(String clientNo) { this.clientNo = clientNo; }
public String getClientName() { return clientName; }
public void setClientName(String clientName) { this.clientName = clientName; }
public String getContact() { return contact; }
public void setContact(String contact) { this.contact = contact; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
public String getGrade() { return grade; }
public void setGrade(String grade) { this.grade = grade; }
public String getSource() { return source; }
public void setSource(String source) { this.source = source; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
}

View File

@@ -0,0 +1,59 @@
package com.ruoyi.system.domain.bid;
import com.ruoyi.common.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
public class BizDeliveryOrder extends BaseEntity {
private Long doId;
private Long tenantId;
private String doNo;
private Long rfqId;
private Long quotationId;
private Long supplierId;
private BigDecimal totalAmount;
private String currency;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date delayDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date actualCloseDate;
private String closeDateSetBy;
private String deliveryStatus;
private List<BizDeliveryOrderItem> items;
private String supplierName;
public Long getDoId() { return doId; }
public void setDoId(Long doId) { this.doId = doId; }
public Long getTenantId() { return tenantId; }
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
public String getDoNo() { return doNo; }
public void setDoNo(String doNo) { this.doNo = doNo; }
public Long getRfqId() { return rfqId; }
public void setRfqId(Long rfqId) { this.rfqId = rfqId; }
public Long getQuotationId() { return quotationId; }
public void setQuotationId(Long quotationId) { this.quotationId = quotationId; }
public Long getSupplierId() { return supplierId; }
public void setSupplierId(Long supplierId) { this.supplierId = supplierId; }
public BigDecimal getTotalAmount() { return totalAmount; }
public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
public String getCurrency() { return currency; }
public void setCurrency(String currency) { this.currency = currency; }
public Date getDeliveryDate() { return deliveryDate; }
public void setDeliveryDate(Date deliveryDate) { this.deliveryDate = deliveryDate; }
public Date getDelayDate() { return delayDate; }
public void setDelayDate(Date delayDate) { this.delayDate = delayDate; }
public Date getActualCloseDate() { return actualCloseDate; }
public void setActualCloseDate(Date actualCloseDate) { this.actualCloseDate = actualCloseDate; }
public String getCloseDateSetBy() { return closeDateSetBy; }
public void setCloseDateSetBy(String closeDateSetBy) { this.closeDateSetBy = closeDateSetBy; }
public String getDeliveryStatus() { return deliveryStatus; }
public void setDeliveryStatus(String deliveryStatus) { this.deliveryStatus = deliveryStatus; }
public List<BizDeliveryOrderItem> getItems() { return items; }
public void setItems(List<BizDeliveryOrderItem> items) { this.items = items; }
public String getSupplierName() { return supplierName; }
public void setSupplierName(String supplierName) { this.supplierName = supplierName; }
}

View File

@@ -0,0 +1,37 @@
package com.ruoyi.system.domain.bid;
import java.math.BigDecimal;
public class BizDeliveryOrderItem {
private Long itemId;
private Long doId;
private Long materialId;
private String materialName;
private String spec;
private String unit;
private BigDecimal quantity;
private BigDecimal unitPrice;
private BigDecimal totalPrice;
private String remark;
public Long getItemId() { return itemId; }
public void setItemId(Long itemId) { this.itemId = itemId; }
public Long getDoId() { return doId; }
public void setDoId(Long doId) { this.doId = doId; }
public Long getMaterialId() { return materialId; }
public void setMaterialId(Long materialId) { this.materialId = materialId; }
public String getMaterialName() { return materialName; }
public void setMaterialName(String materialName) { this.materialName = materialName; }
public String getSpec() { return spec; }
public void setSpec(String spec) { this.spec = spec; }
public String getUnit() { return unit; }
public void setUnit(String unit) { this.unit = unit; }
public BigDecimal getQuantity() { return quantity; }
public void setQuantity(BigDecimal quantity) { this.quantity = quantity; }
public BigDecimal getUnitPrice() { return unitPrice; }
public void setUnitPrice(BigDecimal unitPrice) { this.unitPrice = unitPrice; }
public BigDecimal getTotalPrice() { return totalPrice; }
public void setTotalPrice(BigDecimal totalPrice) { this.totalPrice = totalPrice; }
public String getRemark() { return remark; }
public void setRemark(String remark) { this.remark = remark; }
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.system.mapper.bid;
import com.ruoyi.system.domain.bid.BizClient;
import java.util.List;
import java.util.Map;
public interface BizClientMapper {
List<BizClient> selectBizClientList(BizClient query);
BizClient selectBizClientById(Long id);
int insertBizClient(BizClient record);
int updateBizClient(BizClient record);
int deleteBizClientById(Long id);
int deleteBizClientByIds(Long[] ids);
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
}

View File

@@ -0,0 +1,10 @@
package com.ruoyi.system.mapper.bid;
import com.ruoyi.system.domain.bid.BizDeliveryOrderItem;
import java.util.List;
public interface BizDeliveryOrderItemMapper {
List<BizDeliveryOrderItem> selectItemsByDoId(Long doId);
int insertBizDeliveryOrderItem(BizDeliveryOrderItem item);
int deleteByDoId(Long doId);
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.system.mapper.bid;
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
import java.util.List;
public interface BizDeliveryOrderMapper {
List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query);
BizDeliveryOrder selectBizDeliveryOrderById(Long id);
int insertBizDeliveryOrder(BizDeliveryOrder record);
int updateBizDeliveryOrder(BizDeliveryOrder record);
int deleteBizDeliveryOrderById(Long id);
int deleteBizDeliveryOrderByIds(Long[] ids);
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.system.service.bid;
import com.ruoyi.system.domain.bid.BizClient;
import java.util.List;
import java.util.Map;
public interface IBizClientService {
List<BizClient> selectBizClientList(BizClient query);
BizClient selectBizClientById(Long id);
int insertBizClient(BizClient record);
int updateBizClient(BizClient record);
int deleteBizClientById(Long id);
int deleteBizClientByIds(Long[] ids);
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.system.service.bid;
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
import java.util.List;
public interface IBizDeliveryOrderService {
List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query);
BizDeliveryOrder selectBizDeliveryOrderById(Long id);
int insertBizDeliveryOrder(BizDeliveryOrder record);
int updateBizDeliveryOrder(BizDeliveryOrder record);
int deleteBizDeliveryOrderById(Long id);
int deleteBizDeliveryOrderByIds(Long[] ids);
}

View File

@@ -0,0 +1,50 @@
package com.ruoyi.system.service.bid.impl;
import com.ruoyi.system.domain.bid.BizClient;
import com.ruoyi.system.mapper.bid.BizClientMapper;
import com.ruoyi.system.service.bid.IBizClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class BizClientServiceImpl implements IBizClientService {
@Autowired
private BizClientMapper mapper;
@Override
public List<BizClient> selectBizClientList(BizClient query) {
return mapper.selectBizClientList(query);
}
@Override
public BizClient selectBizClientById(Long id) {
return mapper.selectBizClientById(id);
}
@Override
public int insertBizClient(BizClient record) {
return mapper.insertBizClient(record);
}
@Override
public int updateBizClient(BizClient record) {
return mapper.updateBizClient(record);
}
@Override
public int deleteBizClientById(Long id) {
return mapper.deleteBizClientById(id);
}
@Override
public int deleteBizClientByIds(Long[] ids) {
return mapper.deleteBizClientByIds(ids);
}
@Override
public List<Map<String, Object>> selectClientDeliveryOrders(Long clientId) {
return mapper.selectClientDeliveryOrders(clientId);
}
}

View File

@@ -0,0 +1,89 @@
package com.ruoyi.system.service.bid.impl;
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
import com.ruoyi.system.domain.bid.BizDeliveryOrderItem;
import com.ruoyi.system.mapper.bid.BizDeliveryOrderMapper;
import com.ruoyi.system.mapper.bid.BizDeliveryOrderItemMapper;
import com.ruoyi.system.service.bid.IBizDeliveryOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Service
public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
@Autowired
private BizDeliveryOrderMapper mapper;
@Autowired
private BizDeliveryOrderItemMapper itemMapper;
@Override
public List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query) {
return mapper.selectBizDeliveryOrderList(query);
}
@Override
public BizDeliveryOrder selectBizDeliveryOrderById(Long id) {
BizDeliveryOrder d = mapper.selectBizDeliveryOrderById(id);
if (d != null) d.setItems(itemMapper.selectItemsByDoId(id));
return d;
}
@Override
@Transactional
public int insertBizDeliveryOrder(BizDeliveryOrder record) {
if (record.getDoNo() == null || record.getDoNo().isEmpty()) {
record.setDoNo("DO" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
}
if (record.getDeliveryStatus() == null || record.getDeliveryStatus().isEmpty()) {
record.setDeliveryStatus("pending");
}
int rows = mapper.insertBizDeliveryOrder(record);
if (record.getItems() != null) {
BigDecimal total = BigDecimal.ZERO;
for (BizDeliveryOrderItem item : record.getItems()) {
item.setDoId(record.getDoId());
if (item.getUnitPrice() != null && item.getQuantity() != null) {
item.setTotalPrice(item.getUnitPrice().multiply(item.getQuantity()));
total = total.add(item.getTotalPrice());
}
itemMapper.insertBizDeliveryOrderItem(item);
}
record.setTotalAmount(total);
mapper.updateBizDeliveryOrder(record);
}
return rows;
}
@Override
@Transactional
public int updateBizDeliveryOrder(BizDeliveryOrder record) {
itemMapper.deleteByDoId(record.getDoId());
if (record.getItems() != null) {
BigDecimal total = BigDecimal.ZERO;
for (BizDeliveryOrderItem item : record.getItems()) {
item.setDoId(record.getDoId());
if (item.getUnitPrice() != null && item.getQuantity() != null) {
item.setTotalPrice(item.getUnitPrice().multiply(item.getQuantity()));
total = total.add(item.getTotalPrice());
}
itemMapper.insertBizDeliveryOrderItem(item);
}
record.setTotalAmount(total);
}
return mapper.updateBizDeliveryOrder(record);
}
@Override
public int deleteBizDeliveryOrderById(Long id) {
return mapper.deleteBizDeliveryOrderById(id);
}
@Override
public int deleteBizDeliveryOrderByIds(Long[] ids) {
return mapper.deleteBizDeliveryOrderByIds(ids);
}
}

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.bid.BizClientMapper">
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizClient">
<id property="clientId" column="client_id"/>
<result property="tenantId" column="tenant_id"/>
<result property="clientNo" column="client_no"/>
<result property="clientName" column="client_name"/>
<result property="contact" column="contact"/>
<result property="phone" column="phone"/>
<result property="email" column="email"/>
<result property="city" column="city"/>
<result property="address" column="address"/>
<result property="grade" column="grade"/>
<result property="source" column="source"/>
<result property="status" column="status"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectBizClientList" resultMap="BaseRM">
SELECT * FROM biz_client
<where>
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
<if test="clientName != null and clientName != ''">
AND (client_name LIKE CONCAT('%',#{clientName},'%')
OR client_no LIKE CONCAT('%',#{clientName},'%')
OR contact LIKE CONCAT('%',#{clientName},'%'))
</if>
<if test="status != null and status != ''"> AND status=#{status}</if>
</where>
ORDER BY client_id DESC
</select>
<select id="selectBizClientById" resultMap="BaseRM">
SELECT * FROM biz_client WHERE client_id=#{id}
</select>
<insert id="insertBizClient" useGeneratedKeys="true" keyProperty="clientId">
INSERT INTO biz_client(tenant_id,client_no,client_name,contact,phone,email,city,address,grade,source,status,create_by,create_time)
VALUES(#{tenantId},#{clientNo},#{clientName},#{contact},#{phone},#{email},#{city},#{address},#{grade},#{source},#{status},#{createBy},NOW())
</insert>
<update id="updateBizClient">
UPDATE biz_client
<set>
<if test="clientNo != null">client_no=#{clientNo},</if>
<if test="clientName != null">client_name=#{clientName},</if>
<if test="contact != null">contact=#{contact},</if>
<if test="phone != null">phone=#{phone},</if>
<if test="email != null">email=#{email},</if>
<if test="city != null">city=#{city},</if>
<if test="address != null">address=#{address},</if>
<if test="grade != null">grade=#{grade},</if>
<if test="source != null">source=#{source},</if>
<if test="status != null">status=#{status},</if>
update_by=#{updateBy}, update_time=NOW()
</set>
WHERE client_id=#{clientId}
</update>
<delete id="deleteBizClientById">DELETE FROM biz_client WHERE client_id=#{id}</delete>
<delete id="deleteBizClientByIds">
DELETE FROM biz_client WHERE client_id IN
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete>
<select id="selectClientDeliveryOrders" resultType="java.util.Map">
SELECT d.do_no,
d.delivery_date,
d.delay_date,
d.actual_close_date,
d.delivery_status,
d.total_amount,
s.supplier_name,
(SELECT COUNT(*) FROM biz_delivery_order_item WHERE do_id = d.do_id) AS item_count
FROM biz_client_quote cq
JOIN biz_rfq r ON r.client_quote_id = cq.quote_id
JOIN biz_delivery_order d ON d.rfq_id = r.rfq_id
LEFT JOIN biz_supplier s ON d.supplier_id = s.supplier_id
WHERE cq.client_id = #{clientId}
ORDER BY d.create_time DESC
</select>
</mapper>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.bid.BizDeliveryOrderItemMapper">
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizDeliveryOrderItem">
<id property="itemId" column="item_id"/>
<result property="doId" column="do_id"/>
<result property="materialId" column="material_id"/>
<result property="materialName" column="material_name"/>
<result property="spec" column="spec"/>
<result property="unit" column="unit"/>
<result property="quantity" column="quantity"/>
<result property="unitPrice" column="unit_price"/>
<result property="totalPrice" column="total_price"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectItemsByDoId" resultMap="BaseRM">
SELECT * FROM biz_delivery_order_item WHERE do_id=#{doId}
</select>
<insert id="insertBizDeliveryOrderItem" useGeneratedKeys="true" keyProperty="itemId">
INSERT INTO biz_delivery_order_item(do_id,material_id,material_name,spec,unit,quantity,unit_price,total_price,remark)
VALUES(#{doId},#{materialId},#{materialName},#{spec},#{unit},#{quantity},#{unitPrice},#{totalPrice},#{remark})
</insert>
<delete id="deleteByDoId">DELETE FROM biz_delivery_order_item WHERE do_id=#{doId}</delete>
</mapper>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.bid.BizDeliveryOrderMapper">
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizDeliveryOrder">
<id property="doId" column="do_id"/>
<result property="tenantId" column="tenant_id"/>
<result property="doNo" column="do_no"/>
<result property="rfqId" column="rfq_id"/>
<result property="quotationId" column="quotation_id"/>
<result property="supplierId" column="supplier_id"/>
<result property="totalAmount" column="total_amount"/>
<result property="currency" column="currency"/>
<result property="deliveryDate" column="delivery_date"/>
<result property="delayDate" column="delay_date"/>
<result property="actualCloseDate" column="actual_close_date"/>
<result property="closeDateSetBy" column="close_date_set_by"/>
<result property="deliveryStatus" column="delivery_status"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="supplierName" column="supplier_name"/>
</resultMap>
<select id="selectBizDeliveryOrderList" resultMap="BaseRM">
SELECT d.*, s.supplier_name
FROM biz_delivery_order d
LEFT JOIN biz_supplier s ON d.supplier_id=s.supplier_id
<where>
<if test="tenantId != null"> AND d.tenant_id=#{tenantId}</if>
<if test="doNo != null and doNo != ''"> AND d.do_no LIKE CONCAT('%',#{doNo},'%')</if>
<if test="supplierId != null"> AND d.supplier_id=#{supplierId}</if>
<if test="deliveryStatus != null and deliveryStatus != ''"> AND d.delivery_status=#{deliveryStatus}</if>
<if test="supplierName != null and supplierName != ''"> AND s.supplier_name LIKE CONCAT('%',#{supplierName},'%')</if>
</where>
ORDER BY d.create_time DESC
</select>
<select id="selectBizDeliveryOrderById" resultMap="BaseRM">
SELECT d.*, s.supplier_name
FROM biz_delivery_order d
LEFT JOIN biz_supplier s ON d.supplier_id=s.supplier_id
WHERE d.do_id=#{id}
</select>
<insert id="insertBizDeliveryOrder" useGeneratedKeys="true" keyProperty="doId">
INSERT INTO biz_delivery_order(tenant_id,do_no,rfq_id,quotation_id,supplier_id,total_amount,currency,delivery_date,delay_date,actual_close_date,close_date_set_by,delivery_status,remark,create_by,create_time)
VALUES(#{tenantId},#{doNo},#{rfqId},#{quotationId},#{supplierId},#{totalAmount},#{currency},#{deliveryDate},#{delayDate},#{actualCloseDate},#{closeDateSetBy},#{deliveryStatus},#{remark},#{createBy},NOW())
</insert>
<update id="updateBizDeliveryOrder">
UPDATE biz_delivery_order
<set>
<if test="doNo != null">do_no=#{doNo},</if>
<if test="supplierId != null">supplier_id=#{supplierId},</if>
<if test="totalAmount != null">total_amount=#{totalAmount},</if>
<if test="deliveryDate != null">delivery_date=#{deliveryDate},</if>
<if test="delayDate != null">delay_date=#{delayDate},</if>
<if test="actualCloseDate != null">actual_close_date=#{actualCloseDate},</if>
<if test="closeDateSetBy != null">close_date_set_by=#{closeDateSetBy},</if>
<if test="deliveryStatus != null">delivery_status=#{deliveryStatus},</if>
<if test="remark != null">remark=#{remark},</if>
update_by=#{updateBy}, update_time=NOW()
</set>
WHERE do_id=#{doId}
</update>
<delete id="deleteBizDeliveryOrderById">DELETE FROM biz_delivery_order WHERE do_id=#{id}</delete>
<delete id="deleteBizDeliveryOrderByIds">
DELETE FROM biz_delivery_order WHERE do_id IN
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete>
</mapper>