maven
6 小时以前 30a4a720cfdd57248514f50d141dfd51519aa75d
yys 销售指标,采购报表
已添加13个文件
已修改10个文件
820 ■■■■■ 文件已修改
src/main/java/com/ruoyi/CodeGenerator.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/controller/BorrowInfoController.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/mapper/BorrowInfoMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/pojo/AccountIncome.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/pojo/BorrowInfo.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/BorrowInfoService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/security/service/SysLoginService.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/ProcurementBusinessSummaryController.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/ProcurementBusinessSummaryDto.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/ProcurementBusinessSummaryServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesTrendDto.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/account/BorrowInfoMapper.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/SysUserMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/CodeGenerator.java
@@ -19,11 +19,11 @@
// æ¼”示例子,执行 main æ–¹æ³•控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
    public static String database_url = "jdbc:mysql://127.0.0.1:3306/product-inventory-management";
    public static String database_url = "jdbc:mysql://127.0.0.1:3306/product-inventory-management-new";
    public static String database_username = "root";
    public static String database_password= "123456";
    public static String author = "芯导软件(江苏)有限公司";
    public static String model = "quality"; // æ¨¡å—
    public static String model = "account"; // æ¨¡å—
    public static String setParent = "com.ruoyi."+ model; // åŒ…路径
    public static String tablePrefix = ""; // è®¾ç½®è¿‡æ»¤è¡¨å‰ç¼€
    public static void main(String[] args) {
src/main/java/com/ruoyi/account/controller/BorrowInfoController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
package com.ruoyi.account.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.pojo.BorrowInfo;
import com.ruoyi.account.service.BorrowInfoService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 * å€Ÿæ¬¾ä¿¡æ¯è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:57:29
 */
@Api(tags = "借款信息表")
@RestController
@RequestMapping("/borrowInfo")
public class BorrowInfoController {
    @Autowired
    private BorrowInfoService borrowInfoService;
    @GetMapping("/listPage")
    @ApiOperation("分页查询")
    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
        return borrowInfoService.listPage(page,borrowInfo);
    }
    /**
     * æ–°å¢ž
     */
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "新增借款信息", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody BorrowInfo borrowInfo) {
        return borrowInfoService.add(borrowInfo);
    }
    /**
     * ä¿®æ”¹
     */
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "修改借款信息", businessType = BusinessType.UPDATE)
    public AjaxResult updateBorrowInfo(@RequestBody BorrowInfo borrowInfo) {
        return borrowInfoService.updateBorrowInfo(borrowInfo);
    }
    /**
     * åˆ é™¤
     */
    @DeleteMapping("/delete")
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "删除借款信息", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        return borrowInfoService.delete(ids);
    }
    /**
     * å¯¼å‡º
     */
    @PostMapping("/export")
    @ApiOperation(value = "导出借款信息")
    public void export(HttpServletResponse response, BorrowInfo borrowInfo) {
        List<BorrowInfo> list = borrowInfoService.list();
        ExcelUtil<BorrowInfo> util = new ExcelUtil<>(BorrowInfo.class);
        util.exportExcel(response,list, "借款信息数据");
    }
}
src/main/java/com/ruoyi/account/mapper/BorrowInfoMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.account.mapper;
import com.ruoyi.account.pojo.BorrowInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å€Ÿæ¬¾ä¿¡æ¯è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:57:29
 */
@Mapper
public interface BorrowInfoMapper extends BaseMapper<BorrowInfo> {
}
src/main/java/com/ruoyi/account/pojo/AccountIncome.java
@@ -30,6 +30,16 @@
    private Long id;
    /**
     * ä¸šåŠ¡id
     */
    private Long businessId;
    /**
     * ä¸šåŠ¡ç±»åž‹ 1-回款 2-借款
     */
    private Integer businessType;
    /**
     * æ”¶å…¥æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
src/main/java/com/ruoyi/account/pojo/BorrowInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package com.ruoyi.account.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.dto.DateQueryDto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
/**
 * <p>
 * å€Ÿæ¬¾ä¿¡æ¯è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:57:29
 */
@Getter
@Setter
@TableName("borrow_info")
@ApiModel(value = "BorrowInfo对象", description = "借款信息表")
public class BorrowInfo extends DateQueryDto implements Serializable{
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("借款记录主键ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("借款人姓名")
    @Excel(name = "借款人姓名")
    private String borrowerName;
    @ApiModelProperty("借款金额(元)")
    @Excel(name = "借款金额(元)")
    private BigDecimal borrowAmount;
    @ApiModelProperty("借款利率(如:5.85 ä»£è¡¨5.85%)")
    @Excel(name = "借款利率")
    private BigDecimal interestRate;
    @ApiModelProperty("借款日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "借款日期", width = 30, dateFormat = "yyyy-MM-dd")
    private LocalDate borrowDate;
    @ApiModelProperty("实际还款日期(还款后填充)")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "实际还款日期", width = 30, dateFormat = "yyyy-MM-dd")
    private LocalDate repayDate;
    @ApiModelProperty("借款状态:1=待还款,2=已还款")
    @Excel(name = "借款状态", readConverterExp = "1=待还款,2=已还款")
    private Integer status;
    @ApiModelProperty("备注(借款说明)")
    @Excel(name = "备注")
    private String remark;
    @ApiModelProperty("创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("创建者ID")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty("修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("修改者ID")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty("租户id")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
}
src/main/java/com/ruoyi/account/service/BorrowInfoService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.account.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.pojo.BorrowInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.AjaxResult;
import java.util.List;
/**
 * <p>
 * å€Ÿæ¬¾ä¿¡æ¯è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:57:29
 */
public interface BorrowInfoService extends IService<BorrowInfo> {
    AjaxResult listPage(Page page, BorrowInfo borrowInfo);
    AjaxResult add(BorrowInfo borrowInfo);
    AjaxResult updateBorrowInfo(BorrowInfo borrowInfo);
    AjaxResult delete(List<Long> ids);
}
src/main/java/com/ruoyi/account/service/impl/BorrowInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
package com.ruoyi.account.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.pojo.AccountExpense;
import com.ruoyi.account.pojo.AccountIncome;
import com.ruoyi.account.pojo.BorrowInfo;
import com.ruoyi.account.mapper.BorrowInfoMapper;
import com.ruoyi.account.service.AccountExpenseService;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.account.service.BorrowInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.sales.service.ReceiptPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * <p>
 * å€Ÿæ¬¾ä¿¡æ¯è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:57:29
 */
@Service
@Slf4j
public class BorrowInfoServiceImpl extends ServiceImpl<BorrowInfoMapper, BorrowInfo> implements BorrowInfoService {
    @Autowired
    private BorrowInfoMapper borrowInfoMapper;
    @Autowired
    private AccountIncomeService accountIncomeService;
    @Autowired
    private AccountExpenseService accountExpenseService;
    @Override
    public AjaxResult listPage(Page page, BorrowInfo borrowInfo) {
        LambdaQueryWrapper<BorrowInfo> borrowInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(borrowInfo != null){
            if(StringUtils.isNotEmpty(borrowInfo.getEntryDateStart()) && StringUtils.isNotEmpty(borrowInfo.getEntryDateEnd())){
                borrowInfoLambdaQueryWrapper.ge(BorrowInfo::getBorrowDate, borrowInfo.getEntryDateStart());
                borrowInfoLambdaQueryWrapper.le(BorrowInfo::getBorrowDate, borrowInfo.getEntryDateEnd());
            }
            if(borrowInfo.getStatus() != null){
                borrowInfoLambdaQueryWrapper.eq(BorrowInfo::getStatus, borrowInfo.getStatus());
            }
            if(StringUtils.isNotEmpty(borrowInfo.getBorrowerName())){
                borrowInfoLambdaQueryWrapper.like(BorrowInfo::getBorrowerName, borrowInfo.getBorrowerName());
            }
        }
        return AjaxResult.success(borrowInfoMapper.selectPage(page, borrowInfoLambdaQueryWrapper));
    }
    @Override
    public AjaxResult add(BorrowInfo borrowInfo) {
        int insert = borrowInfoMapper.insert(borrowInfo);
        if(insert > 0){
            // æ·»åŠ æˆåŠŸï¼Œè¿›å…¥æ”¶å…¥ç®¡ç†
            AccountIncome accountIncome = new AccountIncome();
            accountIncome.setBusinessId(borrowInfo.getId());
            accountIncome.setBusinessType(2);
            accountIncome.setIncomeDate(DateUtils.toDate(borrowInfo.getBorrowDate()));
            accountIncome.setIncomeType("2");
            accountIncome.setIncomeMoney(borrowInfo.getBorrowAmount());
            accountIncome.setIncomeDescribed("借款");
            accountIncome.setIncomeMethod("3");
            accountIncome.setInputTime(DateUtils.getNowDate());
            accountIncome.setInputUser(borrowInfo.getBorrowerName());
            accountIncomeService.save(accountIncome);
            return AjaxResult.success("添加成功");
        }
        return AjaxResult.success("添加失败");
    }
    @Override
    public AjaxResult updateBorrowInfo(BorrowInfo borrowInfo) {
        int update = borrowInfoMapper.updateById(borrowInfo);
        if(update > 0){
            // ä¿®æ”¹æˆåŠŸï¼Œä¿®æ”¹æ”¶å…¥ç®¡ç†
            AccountIncome one = accountIncomeService.getOne(new LambdaQueryWrapper<AccountIncome>()
                    .eq(AccountIncome::getBusinessId, borrowInfo.getId())
                    .eq(AccountIncome::getBusinessType, 2)
                    .last("limit 1"));
            if(one != null){
                one.setIncomeMoney(borrowInfo.getBorrowAmount());
                accountIncomeService.updateById(one);
            }
            // æ˜¯å¦ä¸ºè¿˜æ¬¾
            if(borrowInfo.getStatus() != null && borrowInfo.getStatus() == 2){
                // æ–°å¢žæ”¯å‡ºè®°å½•
                AccountExpense accountExpense = new AccountExpense();
                accountExpense.setBusinessId(borrowInfo.getId());
                accountExpense.setBusinessType(2);
                accountExpense.setExpenseDate(DateUtils.toDate(borrowInfo.getRepayDate()));
                accountExpense.setExpenseType("4");
                accountExpense.setExpenseMoney(borrowInfo.getBorrowAmount());
                accountExpense.setExpenseDescribed("还款");
                accountExpense.setExpenseMethod("3");
                accountExpense.setInputTime(DateUtils.getNowDate());
                accountExpense.setInputUser(borrowInfo.getBorrowerName());
                accountExpenseService.save(accountExpense);
            }
            return AjaxResult.success("修改成功");
        }
        return  AjaxResult.success("修改失败");
    }
    @Override
    public AjaxResult delete(List<Long> ids) {
        int delete = borrowInfoMapper.deleteBatchIds(ids);
        if(delete > 0){
            // åˆ é™¤æˆåŠŸï¼Œåˆ é™¤æ”¶å…¥ç®¡ç†
            accountIncomeService.remove(new LambdaQueryWrapper<AccountIncome>()
                    .in(AccountIncome::getBusinessId, ids)
                    .eq(AccountIncome::getBusinessType, 2));
            // åˆ é™¤æ”¯å‡ºç®¡ç†
            accountExpenseService.remove(new LambdaQueryWrapper<AccountExpense>()
                    .in(AccountExpense::getBusinessId, ids)
                    .eq(AccountExpense::getBusinessType, 2));
            return AjaxResult.success("删除成功");
        }
        return  AjaxResult.success("删除失败");
    }
}
src/main/java/com/ruoyi/framework/security/service/SysLoginService.java
@@ -270,13 +270,13 @@
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // æ›´æ–°ç”¨æˆ·ä¿¡æ¯ï¼Œä¿®æ”¹å½“前选中公司
        SysUser user = loginUser.getUser();
        if(factoryId != null){
            user.setTenantId(factoryId);
        }else{
            user.setTenantId(tokenService.getDeptIdsByUserId(user.getUserId())[0]);
        }
        sysUserMapper.updateUser(user);
//        SysUser user = loginUser.getUser();
//        if(factoryId != null){
//            user.setTenantId(factoryId);
//        }else{
//            user.setTenantId(tokenService.getDeptIdsByUserId(user.getUserId())[0]);
//        }
//        sysUserMapper.updateUser(user);
        // ç”Ÿæˆtoken
        return tokenService.createToken(loginUser);
    }
src/main/java/com/ruoyi/purchase/controller/ProcurementBusinessSummaryController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.purchase.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.purchase.service.impl.ProcurementBusinessSummaryServiceImpl;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author :yys
 * @date : 2026/1/15 13:29
 */
@Api(tags = "采购业务汇总")
@RestController
@RequestMapping("/procurementBusinessSummary")
public class ProcurementBusinessSummaryController extends BaseController {
    @Autowired
    private ProcurementBusinessSummaryServiceImpl procurementBusinessSummaryService;
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, ProcurementBusinessSummaryDto procurementBusinessSummaryDto) {
        return procurementBusinessSummaryService.listPage(page, procurementBusinessSummaryDto);
    }
}
src/main/java/com/ruoyi/purchase/dto/ProcurementBusinessSummaryDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package com.ruoyi.purchase.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.basic.dto.ProductDto;
import com.ruoyi.basic.dto.ProductModelDto;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author :yys
 * @date : 2026/1/15 13:34
 */
@Data
@ApiModel
public class ProcurementBusinessSummaryDto {
    private String productCategory;
    /**
     * è§„格型号
     */
    private String specificationModel;
    @ApiModelProperty(value = "开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date entryDateStart;
    @ApiModelProperty(value = "结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date entryDateEnd;
    /**
     * é‡‡è´­æ•°é‡
     */
    private BigDecimal purchaseNum;
    /**
     * é‡‡è´­é‡‘额
     */
    private BigDecimal purchaseAmount;
    /**
     * é‡‡è´­æ¬¡æ•°
     */
    private Integer purchaseTimes;
    /**
     * å¹³å‡å•ä»·
     */
    private BigDecimal averagePrice;
    /**
     * ä¾›åº”商名称
     */
    private String supplierName;
    /**
     * å½•入日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date entryDate;
}
src/main/java/com/ruoyi/purchase/service/impl/PaymentRegistrationServiceImpl.java
@@ -6,6 +6,9 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.account.pojo.AccountExpense;
import com.ruoyi.account.service.AccountExpenseService;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.common.utils.DateUtils;
@@ -60,6 +63,8 @@
    private ProductRecordMapper productRecordMapper;
    private AccountExpenseService accountExpenseService;
    /**
     * æŸ¥è¯¢ä»˜æ¬¾ç™»è®°
     *
@@ -98,7 +103,7 @@
     */
    @Override
    public int insertPaymentRegistration(List<PaymentRegistration> paymentRegistrationList) {
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        LoginUser userId = SecurityUtils.getLoginUser();
        for (PaymentRegistration paymentRegistration : paymentRegistrationList) {
            PaymentRegistration byId = paymentRegistration;
            if (!ObjectUtils.isEmpty(paymentRegistration.getId())){
@@ -114,11 +119,24 @@
            }
            paymentRegistration.setCreateTime(DateUtils.getNowDate());
            paymentRegistration.setUpdateTime(DateUtils.getNowDate());
            paymentRegistration.setRegistrantId(userId);
            paymentRegistration.setRegistrantId(userId.getUserId());
            salesLedgerProduct.setTicketsTotal(salesLedgerProduct.getTicketsTotal().add(paymentRegistration.getCurrentPaymentAmount()));
            salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getTicketsTotal()));
            paymentRegistrationMapper.insert(paymentRegistration);
            salesLedgerProductMapper.updateById(salesLedgerProduct);
            // 2. å¤„理账户收入
            AccountExpense accountExpense = new AccountExpense();
            accountExpense.setExpenseDate(purchaseLedger.getEntryDate());
            accountExpense.setExpenseType("0");
            accountExpense.setSupplierName(purchaseLedger.getSupplierName());
            accountExpense.setExpenseMoney(paymentRegistration.getCurrentPaymentAmount());
            accountExpense.setExpenseDescribed("付款支出");
            accountExpense.setExpenseMethod("0");
            accountExpense.setBusinessId(paymentRegistration.getId());
            accountExpense.setBusinessType(1);
            accountExpense.setInputTime(new Date());
            accountExpense.setInputUser(userId.getNickName());
            accountExpenseService.save(accountExpense);
        }
        return 1;
src/main/java/com/ruoyi/purchase/service/impl/ProcurementBusinessSummaryServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.ruoyi.purchase.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author :yys
 * @date : 2026/1/15 13:30
 */
@Service
@Slf4j
public class ProcurementBusinessSummaryServiceImpl {
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    public AjaxResult listPage(Page page, ProcurementBusinessSummaryDto procurementBusinessSummaryDto) {
        return AjaxResult.success(salesLedgerProductMapper.procurementBusinessSummaryListPage(page, procurementBusinessSummaryDto));
    }
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -191,41 +191,11 @@
        purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId());
        purchaseLedger.setRecorderName(sysUser.getNickName());
        purchaseLedger.setPhoneNumber(sysUser.getPhonenumber());
        // 2. å¤„理账户收入
        AccountExpense accountExpense = new AccountExpense();
        accountExpense.setExpenseDate(purchaseLedger.getEntryDate());
        accountExpense.setExpenseType("0");
        accountExpense.setSupplierName(purchaseLedger.getSupplierName());
        accountExpense.setExpenseMoney(purchaseLedger.getContractAmount());
        accountExpense.setExpenseDescribed("采购合同:" + purchaseLedger.getPurchaseContractNumber());
        accountExpense.setExpenseMethod("0");
        accountExpense.setInvoiceNumber(purchaseLedger.getPurchaseContractNumber());
        accountExpense.setInputTime(new Date());
        accountExpense.setInputUser(loginUser.getNickName());
        // 3. æ–°å¢žæˆ–更新主表
        if (purchaseLedger.getId() == null) {
            purchaseLedgerMapper.insert(purchaseLedger);
//            accountIncomeService.save(accountIncome);
            accountExpenseService.save(accountExpense);
        } else {
            purchaseLedgerMapper.updateById(purchaseLedger);
            PurchaseLedger purchaseLedgerDB = purchaseLedgerMapper.selectById(purchaseLedger.getId());
            List<AccountExpense> accountExpenseDBs = accountExpenseService.getByInvoiceNumberList(purchaseLedger.getPurchaseContractNumber());
            if (!CollectionUtils.isEmpty(accountExpenseDBs)) {
                accountExpenseDBs.forEach(accountExpenseDB ->{
                    accountExpenseDB.setExpenseDate(purchaseLedgerDB.getEntryDate());
                    accountExpenseDB.setExpenseType("0");
                    accountExpenseDB.setSupplierName(purchaseLedgerDB.getSupplierName());
                    accountExpenseDB.setExpenseMoney(purchaseLedgerDB.getContractAmount());
                    accountExpenseDB.setExpenseDescribed("采购合同:" + purchaseLedgerDB.getPurchaseContractNumber());
                    accountExpenseDB.setExpenseMethod("0");
                    accountExpenseDB.setInvoiceNumber(purchaseLedgerDB.getPurchaseContractNumber());
                    accountExpenseService.updateById(accountExpenseDB);
                });
            }
        }
        // 4. å¤„理子表数据
src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
package com.ruoyi.sales.controller;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.sales.dto.StatisticsTableDto;
import com.ruoyi.sales.service.impl.MetricStatisticsServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author :yys
 * @date : 2026/1/15 9:39
 */
@Api(tags = "指标统计")
@RestController
@RequestMapping("/metricStatistics")
public class MetricStatisticsController extends BaseController {
    @Autowired
    private MetricStatisticsServiceImpl metricStatisticsService;
    @ApiOperation("头部总计")
    @GetMapping("/total")
    public AjaxResult total() {
        return metricStatisticsService.total();
    }
    @ApiOperation("统计表")
    @GetMapping("/statisticsTable")
    public AjaxResult statisticsTable(StatisticsTableDto statisticsTableDto) {
        return metricStatisticsService.statisticsTable(statisticsTableDto);
    }
}
src/main/java/com/ruoyi/sales/dto/SalesTrendDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.ruoyi.sales.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author :yys
 * @date : 2026/1/15 10:34
 */
@Data
public class SalesTrendDto {
    private String month; // æœˆä»½ï¼ˆå¦‚2024-12)
    private Integer orderCount; // è®¢å•æ•°
    private BigDecimal salesAmount; // é”€å”®é¢
    private BigDecimal shipRate;
}
src/main/java/com/ruoyi/sales/dto/StatisticsTableDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.sales.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.dto.DateQueryDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * @author :yys
 * @date : 2026/1/15 10:18
 */
@Data
@ApiModel
public class StatisticsTableDto{
    private String customerName;
    private String productCategory;
    @ApiModelProperty(value = "开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date entryDateStart;
    @ApiModelProperty(value = "结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date entryDateEnd;
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -6,8 +6,11 @@
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.sales.dto.SalesLedgerDto;
import com.ruoyi.sales.dto.SalesTrendDto;
import com.ruoyi.sales.dto.StatisticsTableDto;
import com.ruoyi.sales.pojo.SalesLedger;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.math.BigDecimal;
import java.util.List;
@@ -45,4 +48,33 @@
     * @return
     */
    IPage<SalesLedger> selectSalesLedgerListPage(Page page, @Param("salesLedgerDto") SalesLedgerDto salesLedgerDto);
    /**
     * æŒ‰æœˆä»½ç»Ÿè®¡è®¢å•数、销售额(支持产品大类、客户名称筛选)
     * @param statisticsTableDto ç»Ÿè®¡æŸ¥è¯¢å‚æ•°DTO
     * @return é”€å”®è¶‹åŠ¿ç»Ÿè®¡ç»“æžœ
     */
    @Select("<script>" +
            "SELECT " +
            "DATE_FORMAT(sl.entry_date, '%Y-%m') AS month, " +
            "COUNT(DISTINCT sl.id) AS order_count, " +  // æ€»è®¢å•æ•°
            "SUM(slp.tax_inclusive_total_price) AS sales_amount, " +  // é”€å”®é¢
            // å‘货率 = å‘货订单数 * 100 / æ€»è®¢å•数(保留2位小数,避免除0报错)
            "ROUND(IF(COUNT(DISTINCT sl.id) = 0, 0, " +
            "SUM(CASE WHEN slp.approve_status = 2 THEN 1 ELSE 0 END) / COUNT(DISTINCT sl.id) * 100), 2) AS ship_rate " +
            "FROM sales_ledger sl " +
            "LEFT JOIN sales_ledger_product slp ON sl.id = slp.sales_ledger_id " +
            "WHERE sl.entry_date BETWEEN #{statisticsTableDto.entryDateStart} AND #{statisticsTableDto.entryDateEnd} " +
            // äº§å“å¤§ç±»ç­›é€‰
            "<if test='statisticsTableDto.productCategory != null and statisticsTableDto.productCategory != \"\"'>" +
            "AND slp.product_category = #{statisticsTableDto.productCategory} " +
            "</if>" +
            // å®¢æˆ·åç§°ç­›é€‰
            "<if test='statisticsTableDto.customerName != null and statisticsTableDto.customerName != \"\"'>" +
            "AND sl.customer_name = #{statisticsTableDto.customerName} " +
            "</if>" +
            "GROUP BY DATE_FORMAT(sl.entry_date, '%Y-%m') " +
            "ORDER BY month" +
            "</script>")
    List<SalesTrendDto> statisticsTable(@Param("statisticsTableDto")StatisticsTableDto statisticsTableDto);
}
src/main/java/com/ruoyi/sales/mapper/SalesLedgerProductMapper.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.config.MyBaseMapper;
import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.sales.dto.SalesLedgerProductDto;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import org.apache.ibatis.annotations.Param;
@@ -23,4 +24,6 @@
    IPage<SalesLedgerProductDto> listPage(Page page, @Param("req") SalesLedgerProductDto salesLedgerProduct);
    IPage<SalesLedgerProductDto> listPagePurchaseLedger(Page page,@Param("req") SalesLedgerProductDto salesLedgerProduct);
    IPage<ProcurementBusinessSummaryDto> procurementBusinessSummaryListPage(Page page,@Param("req") ProcurementBusinessSummaryDto procurementBusinessSummaryDto);
}
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -207,7 +207,7 @@
     * å‘货审批状态
     */
//    @TableField(exist = false)
    @ApiModelProperty(value = "审批状态:0未生产,1已生产,2待审核(审核中),3审核完成,4审核失败")
    @ApiModelProperty(value = "审批状态:0未生产,1已生产,2已发货")
    private Integer approveStatus;
    @ApiModelProperty(value = "待回款总金额")
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.sales.dto.SalesTrendDto;
import com.ruoyi.sales.dto.StatisticsTableDto;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @author :yys
 * @date : 2026/1/15 9:41
 */
@Service
@Slf4j
public class MetricStatisticsServiceImpl {
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    public AjaxResult total() {
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(null);
        if(CollectionUtils.isEmpty(salesLedgers)) return AjaxResult.success(salesLedgers);
        Map<String, Object> map = new HashMap<>();
        // é”€å”®é¢
        map.put("contractAmountTotal", salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        // è®¢å•数量
        map.put("total", new BigDecimal(salesLedgers.size()));
        // å‘货率
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getType, 1));
        map.put("shipRate", "0%");
        if(CollectionUtils.isEmpty(salesLedgerProducts)) return AjaxResult.success(map);
        // å‘货数量
        long count = salesLedgerProducts.stream()
                .filter(salesLedgerProduct -> salesLedgerProduct.getApproveStatus().equals(2))
                .count();
        map.put("shipRate", String.format("%.2f", count * 100.0 / salesLedgerProducts.size()) + "%");
        return AjaxResult.success(map);
    }
    public AjaxResult statisticsTable(StatisticsTableDto statisticsTableDto) {
        Map<String, Object> map = new HashMap<>();
        if (statisticsTableDto.getEntryDateStart() == null || statisticsTableDto.getEntryDateEnd() == null) {
            Calendar calendar = Calendar.getInstance();
            // ç»“束时间默认是当前时间
            statisticsTableDto.setEntryDateEnd(new Date());
            // å¼€å§‹æ—¶é—´é»˜è®¤æ˜¯6个月前
            calendar.add(Calendar.MONTH, -6);
            statisticsTableDto.setEntryDateStart(calendar.getTime());
        }
        List<SalesTrendDto> salesTrendDtos = salesLedgerMapper.statisticsTable(statisticsTableDto);
        if(CollectionUtils.isEmpty(salesTrendDtos)) return AjaxResult.success(map);
        map.put("dateList", salesTrendDtos.stream().map(SalesTrendDto::getMonth).collect(Collectors.toList()));
        map.put("orderCountList", salesTrendDtos.stream().map(SalesTrendDto::getOrderCount).collect(Collectors.toList()));
        map.put("salesAmountList", salesTrendDtos.stream().map(SalesTrendDto::getSalesAmount).collect(Collectors.toList()));
        map.put("shippingRateList", salesTrendDtos.stream().map(SalesTrendDto::getShipRate).collect(Collectors.toList()));
        return AjaxResult.success(map);
    }
}
src/main/resources/mapper/account/BorrowInfoMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
<?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.account.mapper.BorrowInfoMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.account.pojo.BorrowInfo">
        <id column="id" property="id" />
        <result column="borrower_name" property="borrowerName" />
        <result column="borrow_amount" property="borrowAmount" />
        <result column="interest_rate" property="interestRate" />
        <result column="borrow_date" property="borrowDate" />
        <result column="repay_date" property="repayDate" />
        <result column="status" property="status" />
        <result column="remark" property="remark" />
        <result column="create_time" property="createTime" />
        <result column="create_user" property="createUser" />
        <result column="update_time" property="updateTime" />
        <result column="update_user" property="updateUser" />
        <result column="tenant_id" property="tenantId" />
    </resultMap>
</mapper>
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -96,4 +96,34 @@
        </where>
        order by slp.register_date desc
    </select>
    <select id="procurementBusinessSummaryListPage"
            resultType="com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto">
        SELECT
        slp.product_category AS productCategory,
        slp.specification_model AS specificationModel,
        sl.supplier_name AS supplierName,
        SUM(slp.quantity) AS purchaseNum,
        SUM(slp.tax_inclusive_total_price) AS purchaseAmount,
        COUNT(DISTINCT slp.sales_ledger_id) AS purchaseTimes,
        <!-- å¹³å‡å•ä»· = æ€»é‡‡è´­é‡‘额/总采购数量,保留2位小数,避免除0 -->
        ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 2) AS averagePrice,
        <!-- è¯¥äº§å“å¤§ç±»ä¸‹æœ€åŽä¸€ä¸ªå½•入日期(取台账主表的entry_date) -->
        MAX(sl.entry_date) AS entryDate
        FROM sales_ledger_product slp
        <!-- å…³è”台账主表:获取录入日期entry_date -->
        LEFT JOIN purchase_ledger sl ON slp.sales_ledger_id = sl.id
        WHERE slp.type = 2 <!-- å›ºå®šç­›é€‰ï¼šé‡‡è´­å°è´¦ï¼ˆtype=2) -->
        <!-- é‡‡è´­æ—¥æœŸç­›é€‰ï¼šå¯é€‰æ¡ä»¶ -->
        <if test="req.entryDateStart != null and req.entryDateEnd != null">
            AND sl.entry_date BETWEEN #{req.entryDateStart} AND #{req.entryDateEnd} <!-- æ—¶é—´èŒƒå›´ï¼šéžç©ºæœ‰æ•ˆ -->
        </if>
        <!-- äº§å“å¤§ç±»ç­›é€‰ï¼šå¯é€‰æ¡ä»¶ -->
        <if test="req.productCategory != null and req.productCategory != ''">
            AND slp.product_category = #{req.productCategory}
        </if>
        <!-- æŒ‰äº§å“å¤§ç±»åˆ†ç»„聚合 -->
        GROUP BY slp.product_category
        <!-- æŒ‰äº§å“å¤§ç±»æŽ’序 -->
        ORDER BY slp.product_category
    </select>
</mapper>
src/main/resources/mapper/system/SysUserMapper.xml
@@ -190,7 +190,6 @@
    <insert id="insertUser" parameterType="com.ruoyi.project.system.domain.SysUser" useGeneratedKeys="true" keyProperty="userId">
         insert into sys_user(
             <if test="userId != null and userId != 0">user_id,</if>
             <if test="deptId != null and deptId != 0">dept_id,</if>
             <if test="userName != null and userName != ''">user_name,</if>
             <if test="nickName != null and nickName != ''">nick_name,</if>
             <if test="email != null and email != ''">email,</if>
@@ -205,7 +204,6 @@
             create_time
         )values(
             <if test="userId != null and userId != ''">#{userId},</if>
             <if test="deptId != null and deptId != ''">#{deptId},</if>
             <if test="userName != null and userName != ''">#{userName},</if>
             <if test="nickName != null and nickName != ''">#{nickName},</if>
             <if test="email != null and email != ''">#{email},</if>