已添加5个文件
已修改9个文件
6987 ■■■■■ 文件已修改
sql/product-inventory-management-new-pro.sql 5806 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/StaffSalaryMainController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/excel/StaffSalaryExportData.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/mapper/StaffSalaryMainMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/StaffSalaryMainService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-btw.yml 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-jfhy.yml 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-sdzz.yml 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/staff/StaffSalaryMainMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/product-inventory-management-new-pro.sql
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
@@ -78,7 +78,13 @@
              "contactPerson": "张三",
              "contactPhone": "13800138000",
              "companyAddress": "XX省XX市XX区XXè·¯XX号",
              "taxpayerIdentificationNumber": "91110108XXXXXXXXXX"
              "companyPhone": "0513-XXXXXXXX",
              "taxpayerIdentificationNumber": "91110108XXXXXXXXXX",
              "maintainer": "李四",
              "maintenanceTime": "2026-06-01",
              "bankAccount": "622202XXXXXXXXXXXX",
              "basicBankAccount": "XX银行XX支行",
              "bankCode": "308100XXXXXX"
            }
            {
              "entity": "salesLedger",
@@ -86,6 +92,7 @@
              "salesContractNo": "XS-20260601-001",
              "projectName": "XX项目",
              "entryDate": "2026-06-01",
              "entryPerson": "张三",
              "salesman": "销售员姓名",
              "contractAmount": 50000.00,
              "paymentMethod": "月结30天",
@@ -99,6 +106,7 @@
                  "quantity": 100,
                  "taxInclusiveUnitPrice": 500.00,
                  "taxInclusiveTotalPrice": 50000.00,
                  "taxExclusiveTotalPrice": 44247.79,
                  "taxRate": 13.00,
                  "unit": "ä»¶",
                  "type": 1
@@ -106,6 +114,7 @@
              ]
            }
            å®¢æˆ·åç§°è¦åƒæŒ‡å®šè¡Œä¸šçš„公司,合同编号格式XS-年月日-序号,金额合理。
            æ³¨æ„ taxExclusiveTotalPrice æ˜¯ä¸å«ç¨Žæ€»ä»·ï¼Œéœ€è¦æ ¹æ®å«ç¨Žæ€»ä»·å’Œç¨ŽçŽ‡è®¡ç®—ï¼ˆ=含税总价/(1+税率/100))。
            æ—¥æœŸèŒƒå›´: %s ~ %s,每种实体生成%d-%d条。
            """.formatted(dateStart, dateEnd, min, max);
    }
@@ -120,6 +129,7 @@
              "contactUserName": "李四",
              "contactUserPhone": "13900139000",
              "companyAddress": "XX省XX市XX区XXè·¯XX号",
              "companyPhone": "0513-XXXXXXXX",
              "taxpayerIdentificationNum": "91110108XXXXXXXXXX",
              "bankAccountName": "XX银行XX支行",
              "bankAccountNum": "622202XXXXXXXXXXXX",
@@ -141,6 +151,7 @@
                  "quantity": 50,
                  "taxInclusiveUnitPrice": 600.00,
                  "taxInclusiveTotalPrice": 30000.00,
                  "taxExclusiveTotalPrice": 26548.67,
                  "taxRate": 13.00,
                  "unit": "ä»¶",
                  "type": 2
@@ -148,6 +159,7 @@
              ]
            }
            ä¾›åº”商名称要像指定行业的供应商,合同编号格式CG-年月日-序号。
            æ³¨æ„ taxExclusiveTotalPrice æ˜¯ä¸å«ç¨Žæ€»ä»·ï¼Œéœ€è¦æ ¹æ®å«ç¨Žæ€»ä»·å’Œç¨ŽçŽ‡è®¡ç®—ï¼ˆ=含税总价/(1+税率/100))。
            æ—¥æœŸèŒƒå›´: %s ~ %s,每种实体生成%d-%d条。
            """.formatted(dateStart, dateEnd, min, max);
    }
src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
@@ -34,6 +34,8 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
@@ -208,7 +210,23 @@
                c.setContactPerson(item.getString("contactPerson"));
                c.setContactPhone(item.getString("contactPhone"));
                c.setCompanyAddress(item.getString("companyAddress"));
                c.setCompanyPhone(item.getString("companyPhone"));
                c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber"));
                c.setMaintainer(item.getString("maintainer"));
                if (item.containsKey("maintenanceTime")) {
                    c.setMaintenanceTime(java.sql.Date.valueOf(item.getString("maintenanceTime")));
                } else {
                    c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis()));
                }
                if (item.containsKey("bankAccount")) {
                    c.setBankAccount(item.getString("bankAccount"));
                }
                if (item.containsKey("basicBankAccount")) {
                    c.setBasicBankAccount(item.getString("basicBankAccount"));
                }
                if (item.containsKey("bankCode")) {
                    c.setBankCode(item.getString("bankCode"));
                }
                customerService.insertCustomer(c);
                if (c.getId() != null) {
                    nameToId.put(c.getCustomerName(), c.getId());
@@ -232,6 +250,7 @@
                s.setContactUserName(item.getString("contactUserName"));
                s.setContactUserPhone(item.getString("contactUserPhone"));
                s.setCompanyAddress(item.getString("companyAddress"));
                s.setCompanyPhone(item.getString("companyPhone"));
                s.setTaxpayerIdentificationNum(item.getString("taxpayerIdentificationNum"));
                s.setBankAccountName(item.getString("bankAccountName"));
                s.setBankAccountNum(item.getString("bankAccountNum"));
@@ -286,6 +305,10 @@
                dto.setSalesman(item.getString("salesman"));
                dto.setPaymentMethod(item.getString("paymentMethod"));
                dto.setType(item.getInteger("type"));
                // å½•入人:优先使用AI提供的数据,否则用当前登录用户
                if (item.containsKey("entryPerson")) {
                    dto.setEntryPerson(item.getString("entryPerson"));
                }
                if (item.containsKey("entryDate")) {
                    dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
                }
@@ -309,6 +332,17 @@
                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
                        slp.setUnit(pd.getString("unit"));
                        slp.setType(pd.getInteger("type"));
                        if (pd.containsKey("taxExclusiveTotalPrice")) {
                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
                            // ä¸å«ç¨Žæ€»ä»· = å«ç¨Žæ€»ä»· / (1 + ç¨Žçއ/100)
                            slp.setTaxExclusiveTotalPrice(
                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
                                    2, RoundingMode.HALF_UP));
                        } else {
                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
                        }
                        products.add(slp);
                    }
                    dto.setProductData(products);
@@ -333,6 +367,7 @@
                PurchaseLedgerDto dto = new PurchaseLedgerDto();
                dto.setSupplierId(supplierId);
                dto.setSupplierName(supplierName);
                dto.setPurchaseContractNumber(item.getString("purchaseContractNumber"));
                dto.setProjectName(item.getString("projectName"));
                dto.setContractAmount(item.getBigDecimal("contractAmount"));
                dto.setPaymentMethod(item.getString("paymentMethod"));
@@ -356,6 +391,16 @@
                        slp.setTaxRate(pd.getBigDecimal("taxRate"));
                        slp.setUnit(pd.getString("unit"));
                        slp.setType(2);
                        if (pd.containsKey("taxExclusiveTotalPrice")) {
                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
                            slp.setTaxExclusiveTotalPrice(
                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
                                    2, RoundingMode.HALF_UP));
                        } else {
                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
                        }
                        products.add(slp);
                    }
                    dto.setProductData(products);
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -164,6 +164,9 @@
        purchaseLedger.setApprovalStatus(1);
        // 3. æ–°å¢žæˆ–更新主表
        if (purchaseLedger.getId() == null) {
            if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) {
                purchaseLedger.setPurchaseContractNumber(generatePurchaseContractNo(purchaseLedger.getEntryDate()));
            }
            purchaseLedgerMapper.insert(purchaseLedger);
        } else {
            // åˆ é™¤é‡‡è´­å®¡æ ¸ï¼Œé‡æ–°æäº¤
@@ -1073,4 +1076,82 @@
        }
        return sb.toString();
    }
    private static final String PURCHASE_LOCK_PREFIX = "purchase_contract_no:";
    private static final long PURCHASE_LOCK_WAIT_TIMEOUT = 10;
    private static final long PURCHASE_LOCK_EXPIRE_TIME = 30;
    private String generatePurchaseContractNo(Date entryDate) {
        LocalDate currentDate = entryDate != null ? DateUtils.toLocalDate(entryDate) : LocalDate.now();
        String datePart = currentDate.format(DateTimeFormatter.BASIC_ISO_DATE);
        String lockKey = PURCHASE_LOCK_PREFIX + datePart;
        String lockValue = Thread.currentThread().getId() + "-" + System.nanoTime();
        try {
            long startWaitTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startWaitTime < PURCHASE_LOCK_WAIT_TIMEOUT * 1000) {
                Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, PURCHASE_LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
                if (Boolean.TRUE.equals(locked)) {
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("获取锁时被中断", e);
                }
            }
            if (Boolean.FALSE.equals(redisTemplate.hasKey(lockKey))) {
                throw new RuntimeException("获取采购合同编号生成锁失败:超时");
            }
            String prefix = "CG-" + datePart + "-";
            List<PurchaseLedger> existingList = purchaseLedgerMapper.selectList(
                    new LambdaQueryWrapper<PurchaseLedger>()
                            .likeRight(PurchaseLedger::getPurchaseContractNumber, prefix)
                            .select(PurchaseLedger::getPurchaseContractNumber));
            List<Integer> existingSequences = existingList.stream()
                    .map(PurchaseLedger::getPurchaseContractNumber)
                    .filter(Objects::nonNull)
                    .map(no -> {
                        int lastDash = no.lastIndexOf('-');
                        if (lastDash >= 0) {
                            try {
                                return Integer.parseInt(no.substring(lastDash + 1));
                            } catch (NumberFormatException e) {
                                return 0;
                            }
                        }
                        return 0;
                    })
                    .collect(Collectors.toList());
            int nextSequence = findFirstMissingSequence(existingSequences);
            return prefix + String.format("%03d", nextSequence);
        } finally {
            String luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end";
            redisTemplate.execute(
                    new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
                    Collections.singletonList(lockKey),
                    lockValue
            );
        }
    }
    private int findFirstMissingSequence(List<Integer> sequences) {
        if (sequences.isEmpty()) {
            return 1;
        }
        sequences.sort(Integer::compareTo);
        int next = 1;
        for (int seq : sequences) {
            if (seq == next) {
                next++;
            } else if (seq > next) {
                break;
            }
        }
        return next;
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -571,6 +571,10 @@
        SalesLedger salesLedger = convertToEntity(salesLedgerDto);
        salesLedger.setCustomerName(customer.getCustomerName());
        salesLedger.setTenantId(customer.getTenantId());
        // å½•入人:如果未传则使用当前登录用户
        if (StringUtils.isEmpty(salesLedger.getEntryPerson())) {
            salesLedger.setEntryPerson(String.valueOf(SecurityUtils.getUserId()));
        }
        // 3. æ–°å¢žæˆ–更新主表
        if (salesLedger.getId() == null) {
            String contractNo = salesLedger.getSalesContractNo();
src/main/java/com/ruoyi/staff/controller/StaffSalaryMainController.java
@@ -10,6 +10,7 @@
import com.ruoyi.staff.service.StaffSalaryMainService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
@@ -74,6 +75,16 @@
        return staffSalaryMainService.delete(ids);
    }
    @PostMapping("/export")
    @Operation(summary = "导出员工薪资明细")
    public void export(HttpServletResponse response, String salaryMonth) {
        staffSalaryMainService.exportSalaryDetail(response, salaryMonth);
    }
    @GetMapping("/availableDepts")
    @Operation(summary = "获取可选部门(排除已发放工资表的部门)")
    public AjaxResult getAvailableDepts(String salaryMonth) {
        return staffSalaryMainService.getAvailableDepts(salaryMonth);
    }
}
src/main/java/com/ruoyi/staff/excel/StaffSalaryExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
package com.ruoyi.staff.excel;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
/**
 * å‘˜å·¥è–ªèµ„导出数据
 */
@Data
public class StaffSalaryExportData {
    @Excel(name = "工资月份")
    private String salaryMonth;
    @Excel(name = "工资主题")
    private String salaryTitle;
    @Excel(name = "员工姓名")
    private String staffName;
    @Excel(name = "部门名称")
    private String deptName;
    @Excel(name = "基本工资")
    private BigDecimal basicSalary;
    @Excel(name = "计件工资")
    private BigDecimal pieceSalary;
    @Excel(name = "计时工资")
    private BigDecimal hourlySalary;
    @Excel(name = "其他收入")
    private BigDecimal otherIncome;
    @Excel(name = "社保个人")
    private BigDecimal socialPersonal;
    @Excel(name = "公积金个人")
    private BigDecimal fundPersonal;
    @Excel(name = "其他支出")
    private BigDecimal otherDeduct;
    @Excel(name = "社保补缴")
    private BigDecimal socialSupplementAmount;
    @Excel(name = "工资个税")
    private BigDecimal salaryTax;
    @Excel(name = "应发工资")
    private BigDecimal grossSalary;
    @Excel(name = "应扣工资")
    private BigDecimal deductSalary;
    @Excel(name = "实发工资")
    private BigDecimal netSalary;
    @Excel(name = "备注")
    private String remark;
}
src/main/java/com/ruoyi/staff/mapper/StaffSalaryMainMapper.java
@@ -4,6 +4,8 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
 * <p>
 * å‘˜å·¥å·¥èµ„主表 Mapper æŽ¥å£
@@ -15,4 +17,6 @@
@Mapper
public interface StaffSalaryMainMapper extends BaseMapper<StaffSalaryMain> {
    List<String> selectIssuedDeptIds(String salaryMonth);
}
src/main/java/com/ruoyi/staff/service/StaffSalaryMainService.java
@@ -5,6 +5,7 @@
import com.ruoyi.staff.dto.CalculateSalaryDto;
import com.ruoyi.staff.dto.StaffSalaryCalculateDto;
import com.ruoyi.staff.pojo.StaffSalaryMain;
import jakarta.servlet.http.HttpServletResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@@ -30,4 +31,8 @@
    AjaxResult calculateSalary(CalculateSalaryDto calculateSalaryDto);
    AjaxResult calculateSalaryByEmployee(StaffSalaryCalculateDto staffSalaryCalculateDto);
    void exportSalaryDetail(HttpServletResponse response, String salaryMonth);
    AjaxResult getAvailableDepts(String salaryMonth);
}
src/main/java/com/ruoyi/staff/service/impl/StaffSalaryMainServiceImpl.java
@@ -4,8 +4,13 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.staff.excel.StaffSalaryExportData;
import jakarta.servlet.http.HttpServletResponse;
import com.ruoyi.staff.dto.CalculateSalaryDto;
import com.ruoyi.staff.dto.StaffSalaryCalculateDto;
import com.ruoyi.staff.mapper.StaffLeaveMapper;
@@ -21,9 +26,12 @@
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * <p>
@@ -43,6 +51,7 @@
    private final SchemeApplicableStaffServiceImpl schemeApplicableStaffService;
    private final SysUserDeptMapper sysUserDeptMapper;
    private final StaffLeaveMapper staffLeaveMapper;
    private final SysDeptMapper sysDeptMapper;
    @Override
    public AjaxResult listPage(Page page, StaffSalaryMain staffSalaryMain) {
@@ -69,6 +78,26 @@
    @Override
    public AjaxResult add(StaffSalaryMain staffSalaryMain) {
        if (staffSalaryMain == null || StringUtils.isEmpty(staffSalaryMain.getSalaryMonth())) {
            return AjaxResult.error("参数错误");
        }
        Integer status = staffSalaryMain.getStatus();
        if (status != null && status == 5) {
            String salaryMonth = staffSalaryMain.getSalaryMonth();
            String deptIds = staffSalaryMain.getDeptIds();
            List<StaffSalaryMain> issuedList = staffSalaryMainMapper.selectList(new LambdaQueryWrapper<StaffSalaryMain>()
                    .eq(StaffSalaryMain::getSalaryMonth, salaryMonth)
                    .eq(StaffSalaryMain::getStatus, 5));
            for (StaffSalaryMain issued : issuedList) {
                if (hasOverlappingDept(deptIds, issued.getDeptIds())) {
                    return AjaxResult.error("同一月份同一部门工资不可以发放多次");
                }
            }
        }
        staffSalaryMainMapper.insert(staffSalaryMain);
        staffSalaryMain.getStaffSalaryDetailList().forEach(detail -> {
            detail.setMainId(staffSalaryMain.getId());
@@ -86,6 +115,30 @@
        if(staffSalaryMain1 == null){
            return AjaxResult.error("参数错误");
        }
        Integer newStatus = staffSalaryMain.getStatus();
        if (newStatus != null && newStatus == 5) {
            String salaryMonth = staffSalaryMain.getSalaryMonth();
            if (StringUtils.isEmpty(salaryMonth)) {
                salaryMonth = staffSalaryMain1.getSalaryMonth();
            }
            String deptIds = staffSalaryMain.getDeptIds();
            if (StringUtils.isEmpty(deptIds)) {
                deptIds = staffSalaryMain1.getDeptIds();
            }
            List<StaffSalaryMain> issuedList = staffSalaryMainMapper.selectList(new LambdaQueryWrapper<StaffSalaryMain>()
                    .eq(StaffSalaryMain::getSalaryMonth, salaryMonth)
                    .eq(StaffSalaryMain::getStatus, 5)
                    .ne(StaffSalaryMain::getId, staffSalaryMain.getId()));
            for (StaffSalaryMain issued : issuedList) {
                if (hasOverlappingDept(deptIds, issued.getDeptIds())) {
                    return AjaxResult.error("同一月份同一部门工资不可以发放多次");
                }
            }
        }
        // å¾…审核不可编辑
//        if(staffSalaryMain1.getStatus() > 3){
//            return AjaxResult.error("待审核不可编辑");
@@ -174,6 +227,47 @@
        return AjaxResult.success(map);
    }
    @Override
    public void exportSalaryDetail(HttpServletResponse response, String salaryMonth) {
        LambdaQueryWrapper<StaffSalaryMain> mainWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(salaryMonth)) {
            mainWrapper.eq(StaffSalaryMain::getSalaryMonth, salaryMonth);
        }
        List<StaffSalaryMain> mainList = staffSalaryMainMapper.selectList(mainWrapper);
        List<StaffSalaryExportData> exportDataList = new ArrayList<>();
        for (StaffSalaryMain main : mainList) {
            List<StaffSalaryDetail> detailList = staffSalaryDetailMapper.selectList(
                    new LambdaQueryWrapper<StaffSalaryDetail>().eq(StaffSalaryDetail::getMainId, main.getId())
            );
            for (StaffSalaryDetail detail : detailList) {
                StaffSalaryExportData exportData = new StaffSalaryExportData();
                exportData.setSalaryMonth(main.getSalaryMonth());
                exportData.setSalaryTitle(main.getSalaryTitle());
                exportData.setStaffName(detail.getStaffName());
                exportData.setDeptName(detail.getDeptName());
                exportData.setBasicSalary(detail.getBasicSalary());
                exportData.setPieceSalary(detail.getPieceSalary());
                exportData.setHourlySalary(detail.getHourlySalary());
                exportData.setOtherIncome(detail.getOtherIncome());
                exportData.setSocialPersonal(detail.getSocialPersonal());
                exportData.setFundPersonal(detail.getFundPersonal());
                exportData.setOtherDeduct(detail.getOtherDeduct());
                exportData.setSocialSupplementAmount(detail.getSocialSupplementAmount());
                exportData.setSalaryTax(detail.getSalaryTax());
                exportData.setGrossSalary(detail.getGrossSalary());
                exportData.setDeductSalary(detail.getDeductSalary());
                exportData.setNetSalary(detail.getNetSalary());
                exportData.setRemark(detail.getRemark());
                exportDataList.add(exportData);
            }
        }
        ExcelUtil<StaffSalaryExportData> util = new ExcelUtil<>(StaffSalaryExportData.class);
        util.exportExcel(response, exportDataList, "员工薪资明细");
    }
    public List<Map<String, Object>> setSchemeApplicableStaffUserInfo(List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return new ArrayList<>();
@@ -182,4 +276,52 @@
        return sysUserDeptMapper.setSchemeApplicableStaffUserInfo(ids);
    }
    @Override
    public AjaxResult getAvailableDepts(String salaryMonth) {
        if (StringUtils.isEmpty(salaryMonth)) {
            return AjaxResult.error("工资月份不能为空");
        }
        List<String> issuedDeptIdStrings = staffSalaryMainMapper.selectIssuedDeptIds(salaryMonth);
        Set<Long> issuedDeptIds = new HashSet<>();
        for (String deptIds : issuedDeptIdStrings) {
            if (StringUtils.isNotEmpty(deptIds)) {
                String[] ids = deptIds.split(",");
                for (String id : ids) {
                    issuedDeptIds.add(Long.parseLong(id.trim()));
                }
            }
        }
        List<SysDept> allDepts = sysDeptMapper.selectList(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getStatus, "0")
                .eq(SysDept::getDelFlag, "0"));
        List<SysDept> availableDepts = new ArrayList<>();
        for (SysDept dept : allDepts) {
            if (!issuedDeptIds.contains(dept.getDeptId())) {
                availableDepts.add(dept);
            }
        }
        return AjaxResult.success(availableDepts);
    }
    private boolean hasOverlappingDept(String deptIds1, String deptIds2) {
        if (StringUtils.isEmpty(deptIds1) || StringUtils.isEmpty(deptIds2)) {
            return false;
        }
        Set<String> deptSet1 = new HashSet<>(Arrays.asList(deptIds1.split(",")));
        String[] deptArray2 = deptIds2.split(",");
        for (String deptId : deptArray2) {
            if (deptSet1.contains(deptId.trim())) {
                return true;
            }
        }
        return false;
    }
}
src/main/resources/application-btw.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,268 @@
# é¡¹ç›®ç›¸å…³é…ç½®
ruoyi:
  # åç§°
  name: RuoYi
  # ç‰ˆæœ¬
  version: 3.8.9
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2025
  # æ–‡ä»¶è·¯å¾„ ç¤ºä¾‹ï¼ˆ Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
  profile: /javaWork/product-inventory-management/file
  # èŽ·å–ip地址开关
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°å­—计算 char å­—符验证
  captchaType: math
  # ååŒå®¡æ‰¹ç¼–号前缀(配置文件后缀命名)
  approvalNumberPrefix: NEW
  # ä¸ªæŽ¨ Unipush é…ç½®
  getui:
    appId: PfjyAAE0FK64FaO1w2CMb1
    appKey: zTMb831OEL6J4GK1uE3Ob4
    masterSecret: K1GFtsv42v61tXGnF7SGE5
    domain: https://restapi.getui.cn/v2/
    # ç¦»çº¿æŽ¨é€ä½¿ç”¨çš„包名/组件名
    intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 9003
  servlet:
    # åº”用的访问路径
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # è¿žæŽ¥æ•°æ»¡åŽçš„æŽ’队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# æ—¥å¿—配置
logging:
  level:
    com.ruoyi: warn
    org.springframework: warn
minio:
  endpoint: http://114.132.189.42/
  port: 7019
  secure: false
  accessKey: admin
  secretKey: 12345678
  preview-expiry: 24 # é¢„览地址默认24小时
  default-bucket: jxc
# ç”¨æˆ·é…ç½®
user:
  password:
    # å¯†ç æœ€å¤§é”™è¯¯æ¬¡æ•°
    maxRetryCount: 5
    # å¯†ç é”å®šæ—¶é—´ï¼ˆé»˜è®¤10分钟)
    lockTime: 10
# Spring配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # ä¸»åº“数据源
      master:
        url: jdbc:mysql://172.17.0.1:3306/product-inventory-management-btw?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: xd@123456..
      # ä»Žåº“数据源
      slave:
        # ä»Žæ•°æ®æºå¼€å…³/默认关闭
        enabled: false
        url:
        username:
        password:
      # åˆå§‹è¿žæŽ¥æ•°
      initialSize: 5
      # æœ€å°è¿žæŽ¥æ± æ•°é‡
      minIdle: 10
      # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
      maxActive: 20
      # é…ç½®èŽ·å–è¿žæŽ¥ç­‰å¾…è¶…æ—¶çš„æ—¶é—´
      maxWait: 60000
      # é…ç½®è¿žæŽ¥è¶…æ—¶æ—¶é—´
      connectTimeout: 30000
      # é…ç½®ç½‘络超时时间
      socketTimeout: 60000
      # é…ç½®é—´éš”多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å°ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      minEvictableIdleTimeMillis: 300000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å¤§ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # é…ç½®æ£€æµ‹è¿žæŽ¥æ˜¯å¦æœ‰æ•ˆ
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # è®¾ç½®ç™½åå•,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # æŽ§åˆ¶å°ç®¡ç†ç”¨æˆ·åå’Œå¯†ç 
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # æ…¢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
  # èµ„源信息
  messages:
    # å›½é™…化资源文件路径
    basename: i18n/messages
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
      # å•个文件大小
      max-file-size: 1GB
      # è®¾ç½®æ€»ä¸Šä¼ çš„æ–‡ä»¶å¤§å°
      max-request-size: 2GB
  # æœåŠ¡æ¨¡å—
  devtools:
    restart:
      # çƒ­éƒ¨ç½²å¼€å…³
      enabled: false
  # redis é…ç½®
  data:
    mongodb:
      uri: mongodb://114.132.189.42:9028/chat_memory_db_btw
    # redis é…ç½®
    redis:
      # åœ°å€
#      host: 127.0.0.1
      host: 172.17.0.1
      # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
      port: 6379
      # æ•°æ®åº“索引
      database: 0
      # å¯†ç 
      #    password: root2022!
      password:
      # è¿žæŽ¥è¶…æ—¶æ—¶é—´
      timeout: 10s
      lettuce:
        pool:
          # è¿žæŽ¥æ± ä¸­çš„æœ€å°ç©ºé—²è¿žæŽ¥
          min-idle: 0
          # è¿žæŽ¥æ± ä¸­çš„æœ€å¤§ç©ºé—²è¿žæŽ¥
          max-idle: 8
          # è¿žæŽ¥æ± çš„æœ€å¤§æ•°æ®åº“连接数
          max-active: 8
          # #连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
  # Quartz定时任务配置(新增部分)
  quartz:
    job-store-type: jdbc  # ä½¿ç”¨æ•°æ®åº“存储
    jdbc:
      initialize-schema: never  # é¦–次运行时自动创建表结构,成功后改为never
      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL表结构脚本
    properties:
      org:
        quartz:
          scheduler:
            instanceName: RuoYiScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL适配
            tablePrefix: qrtz_  # è¡¨åå‰ç¼€ï¼Œä¸Žè„šæœ¬ä¸€è‡´
            isClustered: false  # å•节点模式(集群需改为true)
            clusterCheckinInterval: 10000
            txIsolationLevelSerializable: true
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10  # çº¿ç¨‹æ± å¤§å°
            threadPriority: 5
            makeThreadsDaemons: true
          updateCheck: false  # å…³é—­ç‰ˆæœ¬æ£€æŸ¥
# token配置
token:
  # ä»¤ç‰Œè‡ªå®šä¹‰æ ‡è¯†
  header: Authorization
  # ä»¤ç‰Œå¯†é’¥
  secret: xpAVjhCjQDaDB7mjPAzMDSbQWXNu2zYkTdDNUsPMS5Xx8QMmQVYN7n74eZrYJxDJ
  # ä»¤ç‰Œæœ‰æ•ˆæœŸï¼ˆé»˜è®¤30分钟)
  expireTime: 450
# MyBatis Plus配置
mybatis-plus:
  # æœç´¢æŒ‡å®šåŒ…别名   æ ¹æ®è‡ªå·±çš„项目来
  typeAliasesPackage: com.ruoyi.**.pojo
  # é…ç½®mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # åŠ è½½å…¨å±€çš„é…ç½®æ–‡ä»¶
  configLocation: classpath:mybatis/mybatis-config.xml
  global-config:
    enable-sql-runner: true
    db-config:
      id-type: auto
# PageHelper分页插件
pagehelper:
  helperDialect: mysql
  supportMethodsArguments: true
  params: count=countSql
# Swagger配置
swagger:
  # æ˜¯å¦å¼€å¯swagger
  enabled: true
  # è¯·æ±‚前缀
  pathMapping: /dev-api
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
  enabled: true
  # æŽ’除链接(多个用逗号分隔)
  excludes: /system/notice
  # åŒ¹é…é“¾æŽ¥
  urlPatterns: /system/*,/monitor/*,/tool/*
# ä»£ç ç”Ÿæˆ
gen:
  # ä½œè€…
  author: ruoyi
  # é»˜è®¤ç”ŸæˆåŒ…路径 system éœ€æ”¹æˆè‡ªå·±çš„æ¨¡å—名称 å¦‚ system monitor tool
  packageName: com.ruoyi.project.system
  # è‡ªåŠ¨åŽ»é™¤è¡¨å‰ç¼€ï¼Œé»˜è®¤æ˜¯true
  autoRemovePre: false
  # è¡¨å‰ç¼€ï¼ˆç”Ÿæˆç±»åä¸ä¼šåŒ…含表前缀,多个用逗号分隔)
  tablePrefix: sys_
  # æ˜¯å¦å…è®¸ç”Ÿæˆæ–‡ä»¶è¦†ç›–到本地(自定义路径),默认不允许
  allowOverwrite: false
# æ–‡ä»¶ä¸Šä¼ é…ç½®
file:
  temp-dir: /javaWork/product-inventory-management/file/temp/uploads   # ä¸´æ—¶ç›®å½•
  upload-dir: /javaWork/product-inventory-management/file/prod/uploads # æ­£å¼ç›®å½•
  path: /javaWork/product-inventory-management/file # ä¸Šä¼ ç›®å½•
  urlPrefix: /prod-api/common # é“¾æŽ¥å‰ç¼€
  domain: http://1.15.17.182:9101 # åŸŸåå‰ç¼€
  expired: 120 # è¿‡æœŸæ—¶é—´(单位:分钟)
  useLimit: 10 # ä½¿ç”¨æ¬¡æ•°
  compress: true # æ˜¯å¦åŽ‹ç¼©
  needCompressSize: 10MB # åŽ‹ç¼©é˜ˆå€¼
  compressQuality: 0.5 # åŽ‹ç¼©è´¨é‡(0.0-1.0)
src/main/resources/application-jfhy.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,268 @@
# é¡¹ç›®ç›¸å…³é…ç½®
ruoyi:
  # åç§°
  name: RuoYi
  # ç‰ˆæœ¬
  version: 3.8.9
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2025
  # æ–‡ä»¶è·¯å¾„ ç¤ºä¾‹ï¼ˆ Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
  profile: /javaWork/product-inventory-management/file
  # èŽ·å–ip地址开关
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°å­—计算 char å­—符验证
  captchaType: math
  # ååŒå®¡æ‰¹ç¼–号前缀(配置文件后缀命名)
  approvalNumberPrefix: NEW
  # ä¸ªæŽ¨ Unipush é…ç½®
  getui:
    appId: PfjyAAE0FK64FaO1w2CMb1
    appKey: zTMb831OEL6J4GK1uE3Ob4
    masterSecret: K1GFtsv42v61tXGnF7SGE5
    domain: https://restapi.getui.cn/v2/
    # ç¦»çº¿æŽ¨é€ä½¿ç”¨çš„包名/组件名
    intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 9003
  servlet:
    # åº”用的访问路径
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # è¿žæŽ¥æ•°æ»¡åŽçš„æŽ’队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# æ—¥å¿—配置
logging:
  level:
    com.ruoyi: warn
    org.springframework: warn
minio:
  endpoint: http://114.132.189.42/
  port: 7019
  secure: false
  accessKey: admin
  secretKey: 12345678
  preview-expiry: 24 # é¢„览地址默认24小时
  default-bucket: jxc
# ç”¨æˆ·é…ç½®
user:
  password:
    # å¯†ç æœ€å¤§é”™è¯¯æ¬¡æ•°
    maxRetryCount: 5
    # å¯†ç é”å®šæ—¶é—´ï¼ˆé»˜è®¤10分钟)
    lockTime: 10
# Spring配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # ä¸»åº“数据源
      master:
        url: jdbc:mysql://172.17.0.1:3306/product-inventory-management-jfhy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: xd@123456..
      # ä»Žåº“数据源
      slave:
        # ä»Žæ•°æ®æºå¼€å…³/默认关闭
        enabled: false
        url:
        username:
        password:
      # åˆå§‹è¿žæŽ¥æ•°
      initialSize: 5
      # æœ€å°è¿žæŽ¥æ± æ•°é‡
      minIdle: 10
      # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
      maxActive: 20
      # é…ç½®èŽ·å–è¿žæŽ¥ç­‰å¾…è¶…æ—¶çš„æ—¶é—´
      maxWait: 60000
      # é…ç½®è¿žæŽ¥è¶…æ—¶æ—¶é—´
      connectTimeout: 30000
      # é…ç½®ç½‘络超时时间
      socketTimeout: 60000
      # é…ç½®é—´éš”多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å°ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      minEvictableIdleTimeMillis: 300000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å¤§ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # é…ç½®æ£€æµ‹è¿žæŽ¥æ˜¯å¦æœ‰æ•ˆ
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # è®¾ç½®ç™½åå•,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # æŽ§åˆ¶å°ç®¡ç†ç”¨æˆ·åå’Œå¯†ç 
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # æ…¢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
  # èµ„源信息
  messages:
    # å›½é™…化资源文件路径
    basename: i18n/messages
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
      # å•个文件大小
      max-file-size: 1GB
      # è®¾ç½®æ€»ä¸Šä¼ çš„æ–‡ä»¶å¤§å°
      max-request-size: 2GB
  # æœåŠ¡æ¨¡å—
  devtools:
    restart:
      # çƒ­éƒ¨ç½²å¼€å…³
      enabled: false
  # redis é…ç½®
  data:
    mongodb:
      uri: mongodb://114.132.189.42:9028/chat_memory_db_jfhy
    # redis é…ç½®
    redis:
      # åœ°å€
#      host: 127.0.0.1
      host: 172.17.0.1
      # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
      port: 6379
      # æ•°æ®åº“索引
      database: 0
      # å¯†ç 
      #    password: root2022!
      password:
      # è¿žæŽ¥è¶…æ—¶æ—¶é—´
      timeout: 10s
      lettuce:
        pool:
          # è¿žæŽ¥æ± ä¸­çš„æœ€å°ç©ºé—²è¿žæŽ¥
          min-idle: 0
          # è¿žæŽ¥æ± ä¸­çš„æœ€å¤§ç©ºé—²è¿žæŽ¥
          max-idle: 8
          # è¿žæŽ¥æ± çš„æœ€å¤§æ•°æ®åº“连接数
          max-active: 8
          # #连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
  # Quartz定时任务配置(新增部分)
  quartz:
    job-store-type: jdbc  # ä½¿ç”¨æ•°æ®åº“存储
    jdbc:
      initialize-schema: never  # é¦–次运行时自动创建表结构,成功后改为never
      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL表结构脚本
    properties:
      org:
        quartz:
          scheduler:
            instanceName: RuoYiScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL适配
            tablePrefix: qrtz_  # è¡¨åå‰ç¼€ï¼Œä¸Žè„šæœ¬ä¸€è‡´
            isClustered: false  # å•节点模式(集群需改为true)
            clusterCheckinInterval: 10000
            txIsolationLevelSerializable: true
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10  # çº¿ç¨‹æ± å¤§å°
            threadPriority: 5
            makeThreadsDaemons: true
          updateCheck: false  # å…³é—­ç‰ˆæœ¬æ£€æŸ¥
# token配置
token:
  # ä»¤ç‰Œè‡ªå®šä¹‰æ ‡è¯†
  header: Authorization
  # ä»¤ç‰Œå¯†é’¥
  secret: xpAVjhCjQDaDB7mjPAzMDSbQWXNu2zYkTdDNUsPMS5Xx8QMmQVYN7n74eZrYJxDJ
  # ä»¤ç‰Œæœ‰æ•ˆæœŸï¼ˆé»˜è®¤30分钟)
  expireTime: 450
# MyBatis Plus配置
mybatis-plus:
  # æœç´¢æŒ‡å®šåŒ…别名   æ ¹æ®è‡ªå·±çš„项目来
  typeAliasesPackage: com.ruoyi.**.pojo
  # é…ç½®mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # åŠ è½½å…¨å±€çš„é…ç½®æ–‡ä»¶
  configLocation: classpath:mybatis/mybatis-config.xml
  global-config:
    enable-sql-runner: true
    db-config:
      id-type: auto
# PageHelper分页插件
pagehelper:
  helperDialect: mysql
  supportMethodsArguments: true
  params: count=countSql
# Swagger配置
swagger:
  # æ˜¯å¦å¼€å¯swagger
  enabled: true
  # è¯·æ±‚前缀
  pathMapping: /dev-api
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
  enabled: true
  # æŽ’除链接(多个用逗号分隔)
  excludes: /system/notice
  # åŒ¹é…é“¾æŽ¥
  urlPatterns: /system/*,/monitor/*,/tool/*
# ä»£ç ç”Ÿæˆ
gen:
  # ä½œè€…
  author: ruoyi
  # é»˜è®¤ç”ŸæˆåŒ…路径 system éœ€æ”¹æˆè‡ªå·±çš„æ¨¡å—名称 å¦‚ system monitor tool
  packageName: com.ruoyi.project.system
  # è‡ªåŠ¨åŽ»é™¤è¡¨å‰ç¼€ï¼Œé»˜è®¤æ˜¯true
  autoRemovePre: false
  # è¡¨å‰ç¼€ï¼ˆç”Ÿæˆç±»åä¸ä¼šåŒ…含表前缀,多个用逗号分隔)
  tablePrefix: sys_
  # æ˜¯å¦å…è®¸ç”Ÿæˆæ–‡ä»¶è¦†ç›–到本地(自定义路径),默认不允许
  allowOverwrite: false
# æ–‡ä»¶ä¸Šä¼ é…ç½®
file:
  temp-dir: /javaWork/product-inventory-management/file/temp/uploads   # ä¸´æ—¶ç›®å½•
  upload-dir: /javaWork/product-inventory-management/file/prod/uploads # æ­£å¼ç›®å½•
  path: /javaWork/product-inventory-management/file # ä¸Šä¼ ç›®å½•
  urlPrefix: /prod-api/common # é“¾æŽ¥å‰ç¼€
  domain: http://1.15.17.182:9099 # åŸŸåå‰ç¼€
  expired: 120 # è¿‡æœŸæ—¶é—´(单位:分钟)
  useLimit: 10 # ä½¿ç”¨æ¬¡æ•°
  compress: true # æ˜¯å¦åŽ‹ç¼©
  needCompressSize: 10MB # åŽ‹ç¼©é˜ˆå€¼
  compressQuality: 0.5 # åŽ‹ç¼©è´¨é‡(0.0-1.0)
src/main/resources/application-sdzz.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,268 @@
# é¡¹ç›®ç›¸å…³é…ç½®
ruoyi:
  # åç§°
  name: RuoYi
  # ç‰ˆæœ¬
  version: 3.8.9
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2025
  # æ–‡ä»¶è·¯å¾„ ç¤ºä¾‹ï¼ˆ Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
  profile: /javaWork/product-inventory-management/file
  # èŽ·å–ip地址开关
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°å­—计算 char å­—符验证
  captchaType: math
  # ååŒå®¡æ‰¹ç¼–号前缀(配置文件后缀命名)
  approvalNumberPrefix: NEW
  # ä¸ªæŽ¨ Unipush é…ç½®
  getui:
    appId: PfjyAAE0FK64FaO1w2CMb1
    appKey: zTMb831OEL6J4GK1uE3Ob4
    masterSecret: K1GFtsv42v61tXGnF7SGE5
    domain: https://restapi.getui.cn/v2/
    # ç¦»çº¿æŽ¨é€ä½¿ç”¨çš„包名/组件名
    intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 9003
  servlet:
    # åº”用的访问路径
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # è¿žæŽ¥æ•°æ»¡åŽçš„æŽ’队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# æ—¥å¿—配置
logging:
  level:
    com.ruoyi: warn
    org.springframework: warn
minio:
  endpoint: http://114.132.189.42/
  port: 7019
  secure: false
  accessKey: admin
  secretKey: 12345678
  preview-expiry: 24 # é¢„览地址默认24小时
  default-bucket: jxc
# ç”¨æˆ·é…ç½®
user:
  password:
    # å¯†ç æœ€å¤§é”™è¯¯æ¬¡æ•°
    maxRetryCount: 5
    # å¯†ç é”å®šæ—¶é—´ï¼ˆé»˜è®¤10分钟)
    lockTime: 10
# Spring配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # ä¸»åº“数据源
      master:
        url: jdbc:mysql://192.168.1.53:3306/product-inventory-management-sdzz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: sdzz@123456..
      # ä»Žåº“数据源
      slave:
        # ä»Žæ•°æ®æºå¼€å…³/默认关闭
        enabled: false
        url:
        username:
        password:
      # åˆå§‹è¿žæŽ¥æ•°
      initialSize: 5
      # æœ€å°è¿žæŽ¥æ± æ•°é‡
      minIdle: 10
      # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
      maxActive: 20
      # é…ç½®èŽ·å–è¿žæŽ¥ç­‰å¾…è¶…æ—¶çš„æ—¶é—´
      maxWait: 60000
      # é…ç½®è¿žæŽ¥è¶…æ—¶æ—¶é—´
      connectTimeout: 30000
      # é…ç½®ç½‘络超时时间
      socketTimeout: 60000
      # é…ç½®é—´éš”多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å°ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      minEvictableIdleTimeMillis: 300000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å¤§ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # é…ç½®æ£€æµ‹è¿žæŽ¥æ˜¯å¦æœ‰æ•ˆ
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # è®¾ç½®ç™½åå•,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # æŽ§åˆ¶å°ç®¡ç†ç”¨æˆ·åå’Œå¯†ç 
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # æ…¢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
  # èµ„源信息
  messages:
    # å›½é™…化资源文件路径
    basename: i18n/messages
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
      # å•个文件大小
      max-file-size: 1GB
      # è®¾ç½®æ€»ä¸Šä¼ çš„æ–‡ä»¶å¤§å°
      max-request-size: 2GB
  # æœåŠ¡æ¨¡å—
  devtools:
    restart:
      # çƒ­éƒ¨ç½²å¼€å…³
      enabled: false
  # redis é…ç½®
  data:
    mongodb:
      uri: mongodb://114.132.189.42:9028/chat_memory_db_sdzz
    # redis é…ç½®
    redis:
      # åœ°å€
      host: 192.168.1.53
#      host: 172.17.0.1
      # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
      port: 6379
      # æ•°æ®åº“索引
      database: 0
      # å¯†ç 
      #    password: root2022!
      password:
      # è¿žæŽ¥è¶…æ—¶æ—¶é—´
      timeout: 10s
      lettuce:
        pool:
          # è¿žæŽ¥æ± ä¸­çš„æœ€å°ç©ºé—²è¿žæŽ¥
          min-idle: 0
          # è¿žæŽ¥æ± ä¸­çš„æœ€å¤§ç©ºé—²è¿žæŽ¥
          max-idle: 8
          # è¿žæŽ¥æ± çš„æœ€å¤§æ•°æ®åº“连接数
          max-active: 8
          # #连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
  # Quartz定时任务配置(新增部分)
  quartz:
    job-store-type: jdbc  # ä½¿ç”¨æ•°æ®åº“存储
    jdbc:
      initialize-schema: never  # é¦–次运行时自动创建表结构,成功后改为never
      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL表结构脚本
    properties:
      org:
        quartz:
          scheduler:
            instanceName: RuoYiScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL适配
            tablePrefix: qrtz_  # è¡¨åå‰ç¼€ï¼Œä¸Žè„šæœ¬ä¸€è‡´
            isClustered: false  # å•节点模式(集群需改为true)
            clusterCheckinInterval: 10000
            txIsolationLevelSerializable: true
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10  # çº¿ç¨‹æ± å¤§å°
            threadPriority: 5
            makeThreadsDaemons: true
          updateCheck: false  # å…³é—­ç‰ˆæœ¬æ£€æŸ¥
# token配置
token:
  # ä»¤ç‰Œè‡ªå®šä¹‰æ ‡è¯†
  header: Authorization
  # ä»¤ç‰Œå¯†é’¥
  secret: xpAVjhCjQDaDB7mjPAzMDSbQWXNu2zYkTdDNUsPMS5Xx8QMmQVYN7n74eZrYJxDJ
  # ä»¤ç‰Œæœ‰æ•ˆæœŸï¼ˆé»˜è®¤30分钟)
  expireTime: 450
# MyBatis Plus配置
mybatis-plus:
  # æœç´¢æŒ‡å®šåŒ…别名   æ ¹æ®è‡ªå·±çš„项目来
  typeAliasesPackage: com.ruoyi.**.pojo
  # é…ç½®mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # åŠ è½½å…¨å±€çš„é…ç½®æ–‡ä»¶
  configLocation: classpath:mybatis/mybatis-config.xml
  global-config:
    enable-sql-runner: true
    db-config:
      id-type: auto
# PageHelper分页插件
pagehelper:
  helperDialect: mysql
  supportMethodsArguments: true
  params: count=countSql
# Swagger配置
swagger:
  # æ˜¯å¦å¼€å¯swagger
  enabled: true
  # è¯·æ±‚前缀
  pathMapping: /dev-api
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
  enabled: true
  # æŽ’除链接(多个用逗号分隔)
  excludes: /system/notice
  # åŒ¹é…é“¾æŽ¥
  urlPatterns: /system/*,/monitor/*,/tool/*
# ä»£ç ç”Ÿæˆ
gen:
  # ä½œè€…
  author: ruoyi
  # é»˜è®¤ç”ŸæˆåŒ…路径 system éœ€æ”¹æˆè‡ªå·±çš„æ¨¡å—名称 å¦‚ system monitor tool
  packageName: com.ruoyi.project.system
  # è‡ªåŠ¨åŽ»é™¤è¡¨å‰ç¼€ï¼Œé»˜è®¤æ˜¯true
  autoRemovePre: false
  # è¡¨å‰ç¼€ï¼ˆç”Ÿæˆç±»åä¸ä¼šåŒ…含表前缀,多个用逗号分隔)
  tablePrefix: sys_
  # æ˜¯å¦å…è®¸ç”Ÿæˆæ–‡ä»¶è¦†ç›–到本地(自定义路径),默认不允许
  allowOverwrite: false
# æ–‡ä»¶ä¸Šä¼ é…ç½®
file:
  temp-dir: /javaWork/product-inventory-management/file/temp/uploads   # ä¸´æ—¶ç›®å½•
  upload-dir: /javaWork/product-inventory-management/file/prod/uploads # æ­£å¼ç›®å½•
  path: /javaWork/product-inventory-management/file # ä¸Šä¼ ç›®å½•
  urlPrefix: /prod-api/common # é“¾æŽ¥å‰ç¼€
  domain: http://127.0.0.1:9001 # åŸŸåå‰ç¼€
  expired: 120 # è¿‡æœŸæ—¶é—´(单位:分钟)
  useLimit: 10 # ä½¿ç”¨æ¬¡æ•°
  compress: true # æ˜¯å¦åŽ‹ç¼©
  needCompressSize: 10MB # åŽ‹ç¼©é˜ˆå€¼
  compressQuality: 0.5 # åŽ‹ç¼©è´¨é‡(0.0-1.0)
src/main/resources/mapper/staff/StaffSalaryMainMapper.xml
@@ -16,4 +16,11 @@
        <result column="update_user" property="updateUser" />
    </resultMap>
    <select id="selectIssuedDeptIds" resultType="java.lang.String">
        SELECT DISTINCT dept_ids
        FROM staff_salary_main
        WHERE salary_month = #{salaryMonth}
          AND status = 5
    </select>
</mapper>