无关风月
2025-02-08 bd7d053beb9ba667a7842080661c6cc49be4fa69
房屋合同
18个文件已修改
8个文件已添加
12425 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/THouseController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TTenantController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/NumberToChineseUtils.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/template/1_yzj_租赁合同.xml 11322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TContractController.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/pom.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/constant/DictConstants.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/TerminateContractDTO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TContractMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TBill.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TCheckAcceptRecord.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/THouse.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractAppletQuery.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractBillQuery.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TContractService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/THouseServiceImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/BillVO.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/CheckAcceptRecordVO.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TContractVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -4,22 +4,27 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.dto.TContractDTO;
import com.ruoyi.system.dto.THouseDTO;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.TContractRentType;
import com.ruoyi.system.model.THouse;
import com.ruoyi.system.dto.TerminateContractDTO;
import com.ruoyi.system.model.*;
import com.ruoyi.system.query.TContractBillQuery;
import com.ruoyi.system.query.TContractQuery;
import com.ruoyi.system.query.THouseQuery;
import com.ruoyi.system.query.TUserHistoryQuery;
import com.ruoyi.system.service.TContractRentTypeService;
import com.ruoyi.system.service.TContractService;
import com.ruoyi.system.service.THouseService;
import com.ruoyi.system.service.*;
import com.ruoyi.system.vo.BillVO;
import com.ruoyi.system.vo.CheckAcceptRecordVO;
import com.ruoyi.system.vo.HouseVO;
import com.ruoyi.web.controller.tool.NumberToChineseUtils;
import com.ruoyi.web.controller.tool.WordUtil;
import io.swagger.annotations.Api;
import com.ruoyi.system.vo.TContractVO;
import io.swagger.annotations.Api;
@@ -29,9 +34,13 @@
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * <p>
@@ -51,6 +60,10 @@
    private TContractRentTypeService contractRentTypeService;
    @Autowired
    private THouseService houseService;
    @Autowired
    private TBillService billService;
    @Autowired
    private TCheckAcceptRecordService checkAcceptRecordService;
    @ApiOperation(value = "获取合同分页列表")
    @PostMapping(value = "/contractList")
    public R<PageInfo<TContract>> contractList(@RequestBody TContractQuery query) {
@@ -61,7 +74,7 @@
    @PostMapping(value = "/addContract")
    public R<Boolean> addContract(@Validated @RequestBody TContractDTO dto) {
        contractService.save(dto);
        if (dto.getIsIncreasing()==1){
        if (dto.getIsIncreasing()){
            TContractRentType tContractRentType = new TContractRentType();
            tContractRentType.setContractId(dto.getId());
            tContractRentType.setIncreasingDecreasing(dto.getIncreasingDecreasing());
@@ -79,7 +92,7 @@
        contractService.updateById(dto);
        contractRentTypeService.remove(new LambdaQueryWrapper<TContractRentType>()
                .eq(TContractRentType::getContractId,dto.getId()));
        if (dto.getIsIncreasing()==1){
        if (dto.getIsIncreasing()){
            TContractRentType tContractRentType = new TContractRentType();
            tContractRentType.setContractId(dto.getId());
            tContractRentType.setIncreasingDecreasing(dto.getIncreasingDecreasing());
@@ -93,7 +106,7 @@
    @Log(title = "合同管理-批量删除合同", businessType = BusinessType.DELETE)
    @ApiOperation(value = "批量删除合同")
    @DeleteMapping(value = "/deleteContractByIds")
    public R<Boolean> deleteContractByIds3
    public R<Boolean> deleteContractByIds
            (@RequestParam String ids) {
        if (StringUtils.isNotEmpty(ids)){
            contractService.removeBatchByIds(Arrays.asList(ids.split(",")));
@@ -107,6 +120,8 @@
        TContractVO res = new TContractVO();
        TContract contract = contractService.getById(id);
        BeanUtils.copyProperties(contract,res);
        res.setPayType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,res.getPayType()));
        res.setStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_STATUS,res.getStatus()));
        TContractRentType contractRentType = contractRentTypeService.lambdaQuery().eq(TContractRentType::getContractId, id).one();
        if (contractRentType!=null){
            BeanUtils.copyProperties(contractRentType,res);
@@ -121,8 +136,75 @@
            house.setTenantType(oldContract.getPayType());
        }
        res.setHouse(house);
        List<TBill> list = billService.lambdaQuery()
                .eq(TBill::getContractId, id)
                .in(TBill::getPayFeesStatus, Arrays.asList("1,4"))
                .list();
        BigDecimal payMoney = new BigDecimal("0");
        for (TBill tBill : list) {
            payMoney = payMoney.add(tBill.getPayFeesMoney()).add(tBill.getPayableFeesPenalty());
        }
        TCheckAcceptRecord tCheckAcceptRecord = checkAcceptRecordService.lambdaQuery().eq(TCheckAcceptRecord::getContractId, id).one();
        res.setCheckResult(tCheckAcceptRecord.getCheckResult());
        res.setPayMoney(payMoney);
        return R.ok(res);
    }
    @Log(title = "合同管理-撤销审批", businessType =  BusinessType.UPDATE)
    @ApiOperation(value = "撤销审批")
    @GetMapping(value = "/updateContractStatus")
    public R<Boolean> updateContractStatus(String id) {
        TContract contract = contractService.getById(id);
        contract.setStatus("1");
        return R.ok();
    }
    @ApiOperation(value = "终止合同剩余未缴费账单列表")
    @PostMapping(value = "/contractBillList")
    public R<PageInfo<BillVO>> contractBillList(@RequestBody TContractBillQuery query) {
        return R.ok(contractService.contractBillList(query));
    }
    @ApiOperation(value = "终止合同")
    @PostMapping(value = "/terminateContract")
    public R terminateContract(@RequestBody TerminateContractDTO dto) {
        contractService.terminateContract(dto);
        return R.ok();
    }
    @ApiOperation(value = "根据合同id查看验收记录")
    @GetMapping(value = "/getCheckByContractId")
    public R<CheckAcceptRecordVO> getCheckByContractId(String id) {
        return R.ok(contractService.getCheckByContractId(id));
    }
    @Autowired
    private WordUtil wordUtil;
    @ApiOperation(value = "生成合同附件")
    @PostMapping("/set")
    public R set(Integer id, HttpServletResponse response){
        TContract contract = contractService.getById(id);
        THouse tHouse = houseService.getById(contract.getHouseId());
        Map<String, Object> templateParam = new HashMap<>(5);
        templateParam.put("partyOneName", contract.getPartyOneName());
        templateParam.put("partyTwoName", contract.getPartyTwoName());
        templateParam.put("houseAddress", tHouse.getHouseAddress());
        templateParam.put("houseArea", tHouse.getHouseArea()+"m²");
        templateParam.put("startTime", DateUtils.localDateTimeToStringYear(contract.getStartTime()));
        templateParam.put("endTime", DateUtils.localDateTimeToStringYear(contract.getEndTime()));
        templateParam.put("monthRent", "¥¥"+contract.getMonthRent()+"元");
        templateParam.put("monthRentString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("totalYear", "¥¥"+contract.getTotalYear()+"元");
        templateParam.put("totalYearString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getTotalYear().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("payType", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
        templateParam.put("firstRent", "¥"+(contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12"))).setScale(2,BigDecimal.ROUND_DOWN)+"元");
        templateParam.put("firstRentString", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue()));
        templateParam.put("nextPayTime", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年");
        templateParam.put("deposit", "¥"+contract.getDeposit()+"元");
        templateParam.put("depositString", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()));
        templateParam.put("partyOnePerson", contract.getPartyOnePerson());
        templateParam.put("partyOnePhone", contract.getPartyOnePhone());
        templateParam.put("partyTwoPerson", contract.getPartyTwoPerson());
        templateParam.put("partyTwoPhone", contract.getPartyTwoPhone());
        String url = wordUtil.generatePdf("/templates", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\");
        return R.ok(url);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/THouseController.java
@@ -3,23 +3,30 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.system.dto.THouseDTO;
import com.ruoyi.system.dto.TTenantDTO;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.THouse;
import com.ruoyi.system.model.TTenant;
import com.ruoyi.system.query.THouseQuery;
import com.ruoyi.system.query.TTenantQuery;
import com.ruoyi.system.query.TUserHistoryQuery;
import com.ruoyi.system.service.TContractService;
import com.ruoyi.system.service.THouseService;
import com.ruoyi.system.vo.HouseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
 * <p>
@@ -51,7 +58,10 @@
    @ApiOperation(value = "查询房屋信息")
    @GetMapping(value = "/getHouseById")
    public R<THouse> getHouseById(@RequestParam String id) {
        return R.ok(tHouseService.getById(id));
        THouse tHouse = tHouseService.getById(id);
        tHouse.setLeaseStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_LEASE_STATUS,tHouse.getLeaseStatus()));
        tHouse.setBusinessAttributes(DictUtils.getDictLabel(DictConstants.DICT_TYPE_BUSINESS_ATTRIBUTES,tHouse.getBusinessAttributes()));
        return R.ok(tHouse);
    }
    @Log(title = "房屋基础信息管理-删除房屋", businessType = BusinessType.DELETE)
    @ApiOperation(value = "删除房屋")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TTenantController.java
@@ -3,8 +3,10 @@
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.dto.TTenantDTO;
@@ -85,7 +87,10 @@
    @ApiOperation(value = "查看租户详情")
    @GetMapping(value = "/getDetailById")
    public R<TTenant> getDetailById(@RequestParam String id) {
        return R.ok(tenantService.getById(id));
        TTenant tenant = tenantService.getById(id);
        tenant.setTenantAttributes(DictUtils.getDictLabel(DictConstants.DICT_TYPE_TENANT_ATTRIBUTE,tenant.getTenantAttributes()));
        tenant.setTenantType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_TENANT_TYPE,tenant.getTenantType()));
        return R.ok(tenant);
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/NumberToChineseUtils.java
New file
@@ -0,0 +1,129 @@
package com.ruoyi.web.controller.tool;
public class NumberToChineseUtils {
    // 中文数字字符
    private static final char[] CHINESE_NUMBERS = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
    // 单位字符
    private static final String[] UNITS = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿"};
    /**
     * 数字转大写中文
     *
     * @param num 需要转换的数字
     * @return 转换后的大写中文字符串
     */
    public static String numberToChinese(long num) {
        if (num == 0) {
            return "零";
        }
        StringBuilder result = new StringBuilder();
        String numStr = String.valueOf(num);
        int unitIndex = 0; // 单位索引
        boolean zeroFlag = false; // 标记上一个字符是否为0
        for (int i = numStr.length() - 1; i >= 0; i--) {
            int digit = numStr.charAt(i) - '0';
            String part = toChinesePart(digit, unitIndex, zeroFlag);
            result.insert(0, part);
            // 更新上一个字符是否为零的标记
            zeroFlag = digit == 0;
            // 更新单位索引
            if (unitIndex == 4 || unitIndex == 8) {
                unitIndex = 1; // 万和亿后单位重置
            } else {
                unitIndex++;
            }
        }
        // 去除结果字符串末尾的'零'
        while (result.length() > 1 && result.charAt(result.length() - 1) == '零') {
            result.deleteCharAt(result.length() - 1);
        }
        return result.toString();
    }
    /**
     * 转换数字部分并添加单位
     *
     * @param digit     当前数字
     * @param unitIndex 单位索引
     * @param zeroFlag  上一个字符是否为零
     * @return 转换后的字符串
     */
    private static String toChinesePart(int digit, int unitIndex, boolean zeroFlag) {
        if (digit == 0) {
            return zeroFlag ? "" : "零";
        }
        String part = CHINESE_NUMBERS[digit] + UNITS[unitIndex];
        // 连续两个'零'只保留一个
        if (part.equals("零零") || part.equals("零拾")) {
            return "零";
        }
        // 去除'零拾'、'零佰'、'零仟'
        if (part.startsWith("零")) {
            part = part.substring(1);
        }
        return part;
    }
    /**
     * 数字转大写中文(支持小数)
     *
     * @param number 需要转换的数字
     * @return 转换后的大写中文字符串
     */
    public static String numberToChinese(double number) {
        if (number == 0) {
            return "零";
        }
        StringBuilder result = new StringBuilder();
        String numStr = String.format("%.2f", number); // 保留两位小数
        String[] parts = numStr.split("\\.");
        // 整数部分
        if (!parts[0].equals("0")) {
            result.append(numberToChinese(Long.parseLong(parts[0])));
        }
        // 小数部分
        if (parts.length > 1) {
            String decimalPart = parts[1];
            if (!decimalPart.equals("00")) {
                result.append("元");
                if (decimalPart.charAt(0) != '0') {
                    result.append(CHINESE_NUMBERS[decimalPart.charAt(0) - '0']).append("角");
                }
                if (decimalPart.charAt(1) != '0') {
                    result.append(CHINESE_NUMBERS[decimalPart.charAt(1) - '0']).append("分");
                }
            } else {
                result.append("元整");
            }
        } else {
            result.append("元整");
        }
        return result.toString();
    }
    public static void main(String[] args) {
        System.out.println(numberToChinese(123456)); // 输出: 壹拾贰万叁仟肆佰伍拾陆元整
        System.out.println(numberToChinese(10010));  // 输出: 壹万零壹拾元整
        System.out.println(numberToChinese(100000001)); // 输出: 壹亿零壹元整
        System.out.println(numberToChinese(68435)); // 输出: 陆万捌仟肆佰叁拾伍元整
        System.out.println(numberToChinese(24000)); // 输出: 捌仟伍佰肆拾叁元整
        System.out.println(numberToChinese(123.45)); // 输出: 壹佰贰拾叁元肆角伍分
        System.out.println(numberToChinese(0.67));   // 输出: 零元陆角柒分
        System.out.println(numberToChinese(100.00)); // 输出: 壹佰元整
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
New file
@@ -0,0 +1,227 @@
package com.ruoyi.web.controller.tool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.util.HashMap;
@Slf4j
@Component
public class PdfUtils {
@Autowired
    private TencentCosUtil tencentCosUtil;
    /**
     * word 转 pdf
     *
     * @param url
     */
    public  String wordToPdf(String url,String filePath, String fileName) {
        try {
            DocumentType documentType = DocumentType.DOC;
            if(url.contains(".docx")){
                documentType = DocumentType.DOCX;
            }
            if(url.contains(".doc")){
                documentType = DocumentType.DOC;
            }
            if(url.contains(".xlsx")){
                documentType = DocumentType.XLSX;
            }else {
                if(url.contains(".xls")){
                    documentType = DocumentType.XLS;
                }
            }
            InputStream inputStream = new URL(url).openStream();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            IConverter converter = LocalConverter.builder().build();
            converter.convert(inputStream)
                    .as(documentType)
                    .to(stream)
                    .as(DocumentType.PDF).execute();
            //上传图片
            byte2File(stream.toByteArray(),filePath + "/pdf",fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf");
            MultipartFile multipartFile = convertToMultipartFile(stream,fileName.substring(0,fileName.lastIndexOf(".")) );
            String s = tencentCosUtil.upLoadFile(multipartFile);
            stream.close();
            inputStream.close();
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static MultipartFile convertToMultipartFile(ByteArrayOutputStream baos, String fileName) throws IOException {
        // 创建一个临时文件
        File tempFile = File.createTempFile(fileName, ".pdf");
        // 将ByteArrayOutputStream中的数据写入临时文件
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            baos.writeTo(fos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 创建一个MultipartFile对象
        return new MockMultipartFile(
                fileName + ".pdf",          // 参数名称
                fileName + ".pdf", // 文件名
                "application/pdf", // 内容类型
                Files.readAllBytes(tempFile.toPath()) // 文件内容
        );
    }
    /**
     * file转byte
     */
    public static byte[] file2byte(File file){
        byte[] buffer = null;
        try{
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1)
            {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return buffer;
    }
    /**
     * byte 转file
     */
    public static File byte2File(byte[] buf, String filePath, String fileName){
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        File file = null;
        try{
            File dir = new File(filePath+"/");
            if (!dir.exists()){
                dir.mkdirs();
            }
            file = new File(filePath +File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
//            osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
            bos.write(buf);
        }catch (Exception e){
            e.printStackTrace();
        }
        finally{
            if (bos != null){
                try{
                    bos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try{
                    fos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return file;
    }
    /**
     * multipartFile转File
     **/
    public static File multipartFile2File(MultipartFile multipartFile){
        File file = null;
        if (multipartFile != null){
            try {
                file= File.createTempFile("tmp", null);
                multipartFile.transferTo(file);
                System.gc();
                file.deleteOnExit();
            }catch (Exception e){
                e.printStackTrace();
                log.warn("multipartFile转File发生异常:"+e);
            }
        }
        return file;
    }
    public static void main(String[] args) {
//        String url = "file:///E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09\\专业技术工作总结.docx";
//        String filePath = "E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09";
//        String fileName = "专业技术工作总结.docx";
//        String s = wordToPdf(url, filePath, fileName);
//        System.err.println(s);
//        String url = "file:///F:\\测试动态列表Word.doc";
////        String filePath = "E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09";
////        String fileName = "专业技术工作总结.docx";4
//        String filePath = "F:\\";
//
//        String s = wordToPdf(url, filePath, "测试动态列表Word.doc");
//        System.err.println(s);
        // TODO Auto-generated method stub
//        HashMap<String, Object> paramMap = new HashMap<>();
//        paramMap.put("CorpID", "SCZT006959");
//        paramMap.put("Pwd", "123456");
//        paramMap.put("Mobile", "19522115070");
//        paramMap.put("Cell", "");
//        paramMap.put("SendTime", "");
//        paramMap.put("Content", java.net.URLEncoder.encode("你好,这是测试短信发送。【职评网】"));
//        String result3 = HttpUtil.post("http://sdk2.028lk.com/sdk2/BatchSend2.aspx", paramMap);
//        if (result3 == null) {
//            result3 = "";
//        }
//        result3 = StrUtil.trim(result3);
//        log.info("返回结果:" + result3);
//
//        if (result3.matches("^\\d+$") && !result3.equals("0")) {
//            return;
//        }
    }
    public String test(String fileName){
        String url = "file:///D:\\"+fileName;
//        String filePath = "E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09";
//        String fileName = "专业技术工作总结.docx";4
        String filePath = "E:\\";
        String s = wordToPdf(url, filePath, fileName);
        System.err.println(s);
        return s;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
New file
@@ -0,0 +1,168 @@
package com.ruoyi.web.controller.tool;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@Slf4j
@Component
public class WordUtil {
    /**
     * 基于模板生成 Word 文档
     *
     * @param basePackagePath  resources 目录下模板所在包路径
     * @param templateFileName 模板文件名
     * @param templateParam    模板参数
     * @param fileName         文件名
     */
//    public void generate(HttpServletResponse response, String basePackagePath, String templateFileName, Object templateParam, String fileName) {
//        try {
//            // 设置 HTTP 响应的内容类型为 Microsoft Word 文档
//            response.setContentType("application/msword");
//            // 设置响应字符编码为 UTF-8
//            response.setCharacterEncoding("utf-8");
//            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
//            String filename = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
//            // 设置响应头,指定文档将以附件的形式下载,并定义文件名
//            response.setHeader("Content-disposition", "attachment;filename=" + filename + ".doc");
//            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding("utf-8");
//            // 设置模板加载器,加载模板文件
//            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
//            Template t = configuration.getTemplate(templateFileName, "utf-8");
//            // 创建 Writer 对象,用于将生成的文档写到输出流中,缓存区大小设为 10KB
//            Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8), 10240);
//            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
//            t.process(templateParam, out);
//            out.close();
//        } catch (Exception e) {
//            log.info("基于模板{}生成Word文档异常,异常原因:{}", templateFileName, e.getMessage(), e);
//            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
//        }
//    }
    @Resource
    private TencentCosUtil tencentCosUtil;
    @Resource
    private PdfUtils pdfUtils;
    public String generate(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
        try {
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
//            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
            String encodedFileName =fileName ;
            // 定义保存文件的路径
            File saveDir = new File(saveDirectory);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            // 定义文件名
            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
            String s = tencentCosUtil.upLoadFile(mockMultipartFile);
            return s;
        } catch (IOException | TemplateException e) {
            log.error("生成Word文档异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
        }
    }
    public String generatePdf(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) {
        try {
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
//            String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
            String encodedFileName =fileName ;
            // 定义保存文件的路径
            File saveDir = new File(saveDirectory);
            if (!saveDir.exists()) {
                saveDir.mkdirs();
            }
            // 定义文件名
            String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc";
            // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new FileWriter(filePath), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
            File file = new File(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                throw new FileNotFoundException("文件不存在: " + filePath);
            }
            // 读取文件内容
            byte[] fileContent = new byte[(int) file.length()];
            try (FileInputStream fis = new FileInputStream(file)) {
                fis.read(fileContent);
            }
            String test = pdfUtils.test(encodedFileName + ".doc");
//            MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent);
//            String s = ObsUploadUtil.obsUpload(mockMultipartFile);
            return test;
        } catch (IOException | TemplateException e) {
            log.error("生成pdf异常,异常原因:{}", e.getMessage(), e);
            throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage());
        }
    }
}
ruoyi-admin/src/main/resources/template/1_yzj_租赁合同.xml
New file
Diff too large
ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -1,22 +1,30 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.dto.SignContractDTO;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.TContractRentType;
import com.ruoyi.system.model.THouse;
import com.ruoyi.system.query.TContractAppletQuery;
import com.ruoyi.system.query.TContractQuery;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TContractRentTypeService;
import com.ruoyi.system.service.TContractService;
import com.ruoyi.system.service.THouseService;
import com.ruoyi.system.vo.TContractVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
/**
 * <p>
@@ -27,6 +35,8 @@
 * @since 2025-01-17
 */
@RestController
@Api(tags = "我的合同")
@RequestMapping("/t-contract")
public class TContractController {
    @Autowired
@@ -37,21 +47,42 @@
    private THouseService houseService;
    @Autowired
    private TBillService billService;
    @Autowired
    private TokenService tokenService;
    @ApiOperation(value = "签订合同")
    @PostMapping(value = "/signContract")
    public R signContract(@RequestBody SignContractDTO dto) {
        TContract contract = contractService.getById(dto.getId());
        if (contract==null)return R.fail("合同不存在");
        if (contract.getStatus()==4)return R.fail("该合同已签订");
        contract.setSignature(dto.getSignature());
        contract.setStatus(2);
        contractService.updateById(contract);
        return R.ok();
        return contractService.signContract(dto);
    }
    @ApiOperation(value = "我的合同")
    @ApiOperation(value = "我的合同分页列表")
    @PostMapping(value = "/contractList")
    public R<PageInfo<TContract>> contractList(@RequestBody TContractQuery query) {
        return R.ok(contractService.contractList(query));
    public R<PageInfo<TContract>> contractList(@RequestBody TContractAppletQuery query) {
        // todo 获取登陆人id
        return R.ok(contractService.contractAppletList(query));
    }
    @ApiOperation(value = "查询合同信息信息")
    @GetMapping(value = "/getContractById")
    public R<TContractVO> getContractById(@RequestParam String id) {
        TContractVO res = new TContractVO();
        TContract contract = contractService.getById(id);
        BeanUtils.copyProperties(contract,res);
        res.setPayType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,res.getPayType()));
        res.setStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_STATUS,res.getStatus()));
        TContractRentType contractRentType = contractRentTypeService.lambdaQuery().eq(TContractRentType::getContractId, id).one();
        if (contractRentType!=null){
            BeanUtils.copyProperties(contractRentType,res);
        }
        TContract oldContract = contractService.getOne(new LambdaQueryWrapper<TContract>()
                .eq(TContract::getHouseId,contract.getHouseId())
                .eq(TContract::getStatus, 4)
                .le(TContract::getStartTime, LocalDateTime.now())
                .ge(TContract::getEndTime, LocalDateTime.now()));
        THouse house = houseService.getById(contract.getHouseId());
        if (oldContract!=null){
            house.setTenantType(oldContract.getPayType());
        }
        res.setHouse(house);
        return R.ok(res);
    }
}
ruoyi-common/pom.xml
@@ -19,8 +19,22 @@
        <swagger.core.version>1.6.2</swagger.core.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-local</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.documents4j</groupId>
            <artifactId>documents4j-transformer-msoffice-word</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.33</version>
        </dependency>
        <!-- Spring框架基本的核心工具 -->
        <dependency>
            <groupId>org.springframework</groupId>
ruoyi-common/src/main/java/com/ruoyi/common/constant/DictConstants.java
@@ -15,4 +15,28 @@
     * 租户类型
     */
    public static final String DICT_TYPE_TENANT_TYPE = "t_tenant_type";
    /**
     * 租赁状态 1=待出租 2=已出租 3=维修中
     */
    public static final String DICT_TYPE_LEASE_STATUS = "t_lease_status";
    /**
     * 租金支付方式 1=月付 季付 年付
     */
    public static final String DICT_TYPE_CONTRACT_PAY_TYPE = "t_contract_pay_type";
    /**
     * 业务属性 1住宅2商业3工业4车位5办公6仓储
     */
    public static final String DICT_TYPE_BUSINESS_ATTRIBUTES = "t_business_attributes";
    /**
     * 合同状态 1=待提交 2=待审批 3=未签订 4=已签订 5=已驳回 6=已终止 7=待结算 8=已结算
     */
    public static final String DICT_TYPE_CONTRACT_STATUS = "t_contract_status";
    /**
     * 验收状态 1=待验收 2=已验收
     */
    public static final String DICT_TYPE_CHECK_STATUS = "t_check_status";
    /**
     * 缴费状态 1=未缴费 2=待确认 3=已缴费 4=已逾期 5=已失效
     */
    public static final String DICT_TYPE_PAY_FEES_STATUS = "t_pay_fees_status";
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -340,6 +340,16 @@
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return df.format(time);
    }
    /**
     * localdatetime转为字符串
     *
     * @param time localdatetime
     * @return 字符串
     */
    public static String localDateTimeToStringYear(LocalDateTime time) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        return df.format(time);
    }
    /**
     * Date转为LocalDateTime
ruoyi-system/src/main/java/com/ruoyi/system/dto/TerminateContractDTO.java
New file
@@ -0,0 +1,19 @@
package com.ruoyi.system.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "终止合同DTO")
public class TerminateContractDTO implements Serializable {
    @ApiModelProperty(value = "合同id")
    private String id;
    @ApiModelProperty(value = "备注说明")
    private String terminateRemark;
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TContractMapper.java
@@ -3,7 +3,10 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.query.TContractAppletQuery;
import com.ruoyi.system.query.TContractBillQuery;
import com.ruoyi.system.query.TContractQuery;
import com.ruoyi.system.vo.BillVO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -19,4 +22,9 @@
public interface TContractMapper extends BaseMapper<TContract> {
    List<TContract> contractList(@Param("query") TContractQuery query, @Param("pageInfo") PageInfo<TContract> pageInfo);
    List<TContract> contractAppletList(@Param("query")TContractAppletQuery query, @Param("pageInfo")  PageInfo<TContract> pageInfo);
    List<BillVO> contractBillList(@Param("query") TContractBillQuery query, @Param("pageInfo") PageInfo<BillVO> pageInfo);
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TBill.java
@@ -45,13 +45,13 @@
    private BigDecimal payableFeesMoney;
    @ApiModelProperty(value = "应缴费日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @TableField("payable_fees_time")
    private LocalDateTime payableFeesTime;
    @ApiModelProperty(value = "缴费状态 1=未缴费 2=待确认 3=已缴费 4=已逾期")
    @ApiModelProperty(value = "缴费状态 1=未缴费 2=待确认 3=已缴费 4=已逾期 5= 已失效")
    @TableField("pay_fees_status")
    private Integer payFeesStatus;
    private String payFeesStatus;
    @ApiModelProperty(value = "缴费金额")
    @TableField("pay_fees_money")
@@ -68,7 +68,7 @@
    @ApiModelProperty(value = "账单类型 1=租金 2=押金 3=生活费用")
    @TableField("bill_type")
    private Integer billType;
    private String billType;
    @ApiModelProperty(value = "逾期天数")
    @TableField("over_days")
ruoyi-system/src/main/java/com/ruoyi/system/model/TCheckAcceptRecord.java
@@ -86,10 +86,13 @@
    @ApiModelProperty(value = "验收结果 1=合格 2=不合格")
    @TableField("check_result")
    private Integer checkResult;
    private Boolean checkResult;
    @ApiModelProperty(value = "验收结算金额")
    @TableField("check_money")
    private BigDecimal checkMoney;
    @ApiModelProperty(value = "验收状态 待验收 已验收")
    @TableField("status")
    private String status;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java
@@ -53,30 +53,30 @@
    @TableField("end_time")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "合计租金")
    @TableField("total_rent")
    private BigDecimal totalRent;
    @ApiModelProperty(value = "每月租金")
    @TableField("month_rent")
    private BigDecimal monthRent;
    @ApiModelProperty(value = "押金")
    @TableField("deposit")
    private BigDecimal deposit;
    @ApiModelProperty(value = "租金支付方式 1=月付 2=季付 3=年付")
    @ApiModelProperty(value = "租金支付方式 月付 季付 年付")
    @TableField("pay_type")
    private Integer payType;
    private String payType;
    @ApiModelProperty(value = "第一次支付日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("first_pay_time")
    private LocalDateTime firstPayTime;
    @ApiModelProperty(value = "是否递增递减 1=是 0=否")
    @ApiModelProperty(value = "是否递增递减 true=是 false=否")
    @TableField("isIncreasing")
    private Integer isIncreasing;
    private Boolean isIncreasing;
    @ApiModelProperty(value = "押金是否随租金递增递减 1=是 0=否")
    @ApiModelProperty(value = "押金是否随租金递增递减 true=是 false=否")
    @TableField("isIncreasing_deposit")
    private Integer isincreasingDeposit;
    private Boolean isincreasingDeposit;
    @ApiModelProperty(value = "违约金比例")
    @TableField("proportion")
@@ -122,9 +122,9 @@
    @TableField("remark")
    private String remark;
    @ApiModelProperty(value = "状态 1=待提交 2=待审批 3=未签订 4=已签订")
    @ApiModelProperty(value = "状态 待提交 待审批 未签订 已签订....")
    @TableField("status")
    private Integer status;
    private String status;
    @ApiModelProperty(value = "内存大小多个文件逗号拼接")
    @TableField("memory")
    private String memory;
@@ -134,5 +134,11 @@
    @ApiModelProperty(value = "租户确认合同电子签名")
    @TableField("signature")
    private String signature;
    @ApiModelProperty(value = "终止合同备注说明")
    @TableField("terminate_remark")
    private String terminateRemark;
    @ApiModelProperty(value = "合计年租金")
    @TableField("total_year")
    private BigDecimal totalYear;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/THouse.java
@@ -80,7 +80,7 @@
    @ApiModelProperty(value = "租赁状态 1=待出租 2=已出租 3=维修中")
    @TableField("lease_status")
    private Integer leaseStatus;
    private String leaseStatus;
    @ApiModelProperty(value = "楼栋")
    @TableField("building")
    private String building;
@@ -90,5 +90,5 @@
    @ApiModelProperty(value = "住户类型 1月租 2季租 3年租")
    @TableField(exist = false)
    private Integer tenantType;
    private String tenantType;
}
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractAppletQuery.java
@@ -11,4 +11,6 @@
    @ApiModelProperty(value = "全部不传 3=待签订 4=已签订")
    private Integer status;
    @ApiModelProperty(value = "租户id 前端忽略")
    private String tenantId;
}
ruoyi-system/src/main/java/com/ruoyi/system/query/TContractBillQuery.java
New file
@@ -0,0 +1,14 @@
package com.ruoyi.system.query;
import com.ruoyi.common.core.domain.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "终止合同分页列表查询Query")
public class TContractBillQuery extends BasePage {
    @ApiModelProperty(value = "合同id")
    private String id;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TContractService.java
@@ -2,8 +2,15 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.dto.SignContractDTO;
import com.ruoyi.system.dto.TerminateContractDTO;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.query.TContractAppletQuery;
import com.ruoyi.system.query.TContractBillQuery;
import com.ruoyi.system.query.TContractQuery;
import com.ruoyi.system.vo.BillVO;
import com.ruoyi.system.vo.CheckAcceptRecordVO;
/**
 * <p>
@@ -16,4 +23,16 @@
public interface TContractService extends IService<TContract> {
    PageInfo<TContract> contractList(TContractQuery query);
    PageInfo<TContract> contractAppletList(TContractAppletQuery query);
    PageInfo<BillVO> contractBillList(TContractBillQuery query);
    void terminateContract(TerminateContractDTO dto);
    CheckAcceptRecordVO getCheckByContractId(String id);
    R signContract(SignContractDTO dto);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java
@@ -1,14 +1,33 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.dto.SignContractDTO;
import com.ruoyi.system.dto.TerminateContractDTO;
import com.ruoyi.system.mapper.TBillMapper;
import com.ruoyi.system.mapper.TCheckAcceptRecordMapper;
import com.ruoyi.system.mapper.TContractMapper;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.TTenant;
import com.ruoyi.system.mapper.THouseMapper;
import com.ruoyi.system.model.*;
import com.ruoyi.system.query.TContractAppletQuery;
import com.ruoyi.system.query.TContractBillQuery;
import com.ruoyi.system.query.TContractQuery;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TContractService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.vo.BillVO;
import com.ruoyi.system.vo.CheckAcceptRecordVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
/**
@@ -21,13 +40,138 @@
 */
@Service
public class TContractServiceImpl extends ServiceImpl<TContractMapper, TContract> implements TContractService {
    @Resource
    private TCheckAcceptRecordMapper checkAcceptRecordMapper;
    @Resource
    private THouseMapper houseMapper;
    @Resource
    private TBillMapper billMapper;
    @Resource
    private TBillService billService;
    @Resource
    private TContractMapper contractMapper;
    @Override
    public PageInfo<TContract> contractList(TContractQuery query) {
        PageInfo<TContract> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<TContract> list = this.baseMapper.contractList(query,pageInfo);
        for (TContract tContract : list) {
            tContract.setPayType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,tContract.getPayType()));
            tContract.setStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_STATUS,tContract.getStatus()));
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public PageInfo<TContract> contractAppletList(TContractAppletQuery query) {
        PageInfo<TContract> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<TContract> list = this.baseMapper.contractAppletList(query,pageInfo);
        for (TContract tContract : list) {
            tContract.setPayType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,tContract.getPayType()));
            tContract.setStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_STATUS,tContract.getStatus()));
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public PageInfo<BillVO> contractBillList(TContractBillQuery query) {
        PageInfo<BillVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<BillVO> list = this.baseMapper.contractBillList(query,pageInfo);
        for (BillVO billVO : list) {
            if (billVO.getPayFeesStatus().equals("4")){
                billVO.setPayFeesMoneyString((billVO.getPayFeesMoney().add(billVO.getPayableFeesPenalty()))+"【"+billVO.getPayFeesMoney()+"+"+billVO.getPayableFeesPenalty()+"】");
            }
            billVO.setPayFeesStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_PAY_FEES_STATUS,billVO.getPayFeesStatus()));
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public void terminateContract(TerminateContractDTO dto) {
        TContract contract = this.baseMapper.selectById(dto.getId());
        contract.setTerminateRemark(dto.getTerminateRemark());
        contract.setStatus("4");
        this.baseMapper.updateById(contract);
        // 生成验收记录
        TCheckAcceptRecord tCheckAcceptRecord = new TCheckAcceptRecord();
        tCheckAcceptRecord.setContractId(dto.getId());
        tCheckAcceptRecord.setHouseId(contract.getHouseId());
        tCheckAcceptRecord.setLeaseReason("后台终止");
        tCheckAcceptRecord.setStatus("1");
        checkAcceptRecordMapper.insert(tCheckAcceptRecord);
        // 将所有未缴费账单设置未已失效
        List<TBill> tBills = billMapper.selectList(new LambdaQueryWrapper<TBill>()
                .in(TBill::getPayFeesStatus, Arrays.asList("1,4"))
                .eq(TBill::getContractId, dto.getId()));
        for (TBill tBill : tBills) {
            tBill.setPayFeesStatus("5");
        }
        billService.updateBatchById(tBills);
    }
    @Override
    public CheckAcceptRecordVO getCheckByContractId(String id) {
        CheckAcceptRecordVO checkAcceptRecordVO = new CheckAcceptRecordVO();
        TCheckAcceptRecord tCheckAcceptRecord = checkAcceptRecordMapper.selectOne(new LambdaQueryWrapper<TCheckAcceptRecord>()
                .eq(TCheckAcceptRecord::getContractId, id));
        BeanUtils.copyProperties(tCheckAcceptRecord,checkAcceptRecordVO);
        THouse tHouse = houseMapper.selectById(tCheckAcceptRecord.getHouseId());
        tHouse.setLeaseStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_LEASE_STATUS,tHouse.getLeaseStatus()));
        tHouse.setBusinessAttributes(DictUtils.getDictLabel(DictConstants.DICT_TYPE_BUSINESS_ATTRIBUTES,tHouse.getBusinessAttributes()));
        checkAcceptRecordVO.setHouse(tHouse);
        return checkAcceptRecordVO;
    }
    @Override
    public R signContract(SignContractDTO dto) {
        TContract contract = contractMapper.selectById(dto.getId());
        if (contract==null)return R.fail("合同不存在");
        if (contract.getStatus().equals("4"))return R.fail("该合同已签订");
        contract.setSignature(dto.getSignature());
        contract.setStatus("2");
        contractMapper.updateById(contract);
        // 用户签订合同后 生成第一批账单包含租金账单和押金账单 后续账单通过定时任务生成
        TBill rent = new TBill();
        rent.setContractId(contract.getId());
        // 应缴费租金
        BigDecimal payableFeesMoney = new BigDecimal("0");
        LocalDateTime startTime = contract.getStartTime();
        LocalDateTime endTime = contract.getEndTime();
//        // 计算相差多少天
//        long days = ChronoUnit.DAYS.between(startTime, endTime);
//        // 计算相差多少个月
//        long months = ChronoUnit.MONTHS.between(startTime, endTime);
//        if (months<=31){
//            // 小于等于一个月 合计租金就是首笔账单金额
//            payableFeesMoney = contract.getTotalRent();
//        }else{
//            switch (contract.getPayType()){
//                case "1":
//                    break;
//                case "2":
//                    break;
//                case "3":
//                    break;
//            }
//        }
//
//        rent.setPayableFeesMoney(payableFeesMoney);
//        rent.setPayableFeesTime(contract.getFirstPayTime());
//        rent.setPayFeesStatus("1");
//        rent.setBillType("1");
//
//        TBill deposit = new TBill();
//        deposit.setContractId(contract.getId());
//        deposit.setPayableFeesMoney(contract.getDeposit());
//        deposit.setPayableFeesTime(contract.getFirstPayTime());
//        deposit.setPayFeesStatus("1");
//        deposit.setBillType("2");
        return R.ok();
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/THouseServiceImpl.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.system.mapper.TContractMapper;
import com.ruoyi.system.mapper.THouseMapper;
import com.ruoyi.system.model.TContract;
@@ -38,9 +40,11 @@
                .le(TContract::getStartTime, LocalDateTime.now())
                .ge(TContract::getEndTime, LocalDateTime.now()));
        for (THouse tHouse : list) {
            tHouse.setLeaseStatus(DictUtils.getDictLabel(DictConstants.DICT_TYPE_LEASE_STATUS,tHouse.getLeaseStatus()));
            tHouse.setBusinessAttributes(DictUtils.getDictLabel(DictConstants.DICT_TYPE_BUSINESS_ATTRIBUTES,tHouse.getBusinessAttributes()));
            TContract tContract = tContracts.stream().filter(e -> e.getHouseId().equals(tHouse.getId())).findFirst().orElse(null);
            if (tContract!=null){
                tHouse.setTenantType(tContract.getPayType());
                tHouse.setTenantType(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CONTRACT_PAY_TYPE,tContract.getPayType()));
            }
        }
        pageInfo.setRecords(list);
@@ -51,6 +55,9 @@
    public PageInfo<HouseVO> userHistoryList(TUserHistoryQuery query) {
        PageInfo<HouseVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<HouseVO> list = this.baseMapper.userHistoryList(query,pageInfo);
        for (HouseVO houseVO : list) {
            houseVO.setBusinessAttributes(DictUtils.getDictLabel(DictConstants.DICT_TYPE_BUSINESS_ATTRIBUTES,houseVO.getBusinessAttributes()));
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
ruoyi-system/src/main/java/com/ruoyi/system/vo/BillVO.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.system.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.system.model.TBill;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel(value = "终止合同-未缴费帐单列表VO")
public class BillVO extends TBill {
    @ApiModelProperty(value = "合同编号")
    private String contractNumber;
    @ApiModelProperty(value = "租户姓名")
    private String residentName;
    @ApiModelProperty(value = "联系电话")
    private String phone;
    @ApiModelProperty(value = "当缴费状态为已逾期 使用该字段作为应缴费金额")
    private String payFeesMoneyString;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/CheckAcceptRecordVO.java
New file
@@ -0,0 +1,20 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.model.TCheckAcceptRecord;
import com.ruoyi.system.model.THouse;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "房屋验收记录VO")
public class CheckAcceptRecordVO extends TCheckAcceptRecord {
    @ApiModelProperty(value = "房屋信息")
    private THouse house;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TContractVO.java
@@ -1,10 +1,8 @@
package com.ruoyi.system.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.THouse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -32,4 +30,8 @@
    @ApiModelProperty(value = "房屋信息")
    private THouse house;
    @ApiModelProperty(value = "当前未缴费账单金额")
    private BigDecimal payMoney;
    @ApiModelProperty(value = "房屋验收结果")
    private Boolean checkResult;
}
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml
@@ -9,7 +9,7 @@
        <result column="contract_name" property="contractName" />
        <result column="start_time" property="startTime" />
        <result column="end_time" property="endTime" />
        <result column="total_rent" property="totalRent" />
        <result column="month_rent" property="monthRent" />
        <result column="deposit" property="deposit" />
        <result column="pay_type" property="payType" />
        <result column="first_pay_time" property="firstPayTime" />
@@ -32,11 +32,17 @@
        <result column="create_by" property="createBy" />
        <result column="update_by" property="updateBy" />
        <result column="disabled" property="disabled" />
        <result column="memory" property="memory" />
        <result column="contract_file_name" property="contractFileName" />
        <result column="signature" property="signature" />
        <result column="terminate_remark" property="terminateRemark" />
        <result column="total_year" property="totalYear" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, contract_number, contract_name, start_time, end_time, total_rent, deposit, pay_type, first_pay_time, isIncreasing, isIncreasing_deposit, proportion, house_id, party_one_name, party_one_person, party_one_phone, tenant_id, party_two_name, party_two_person, party_two_phone, contract_file, remark, status, create_time, update_time, create_by, update_by, disabled
        id, contract_number, contract_name, start_time, end_time, month_rent, deposit, pay_type, first_pay_time, isIncreasing, isIncreasing_deposit, proportion, house_id, party_one_name, party_one_person, party_one_phone, tenant_id, party_two_name, party_two_person, party_two_phone, contract_file, remark, status, create_time, update_time, create_by, update_by, disabled,
            memory, contract_file_name, signature, terminate_remark, total_year
    </sql>
    <select id="contractList" resultType="com.ruoyi.system.model.TContract">
        select t1.* from t_contract t1
@@ -57,5 +63,28 @@
        </where>
    </select>
    <select id="contractAppletList" resultType="com.ruoyi.system.model.TContract">
        select t1.* from t_contract t1
        <where>
            <if test="query.status != null">
                and t1.status = #{query.status}
            </if>
            <if test="query.tenantId != null">
                and t1.tenant_id = #{query.tenantId}
            </if>
            AND t1.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        </where>
    </select>
    <select id="contractBillList" resultType="com.ruoyi.system.vo.BillVO">
        select t1.*,t2.contract_number as contractNumber,t3.resident_name as residentName,t3.phone as phone
        from t_bill t1
        left join t_contract t2 on t1.contract_id = t2.id
        left join t_resident t3 on t2.tenant_id = t3.id
        where t2.id = #{query.id}
        and (t1.pay_fees_status = 1 or t1.pay_fees_status = 4)
        AND t1.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        AND t2.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
        AND t3.disabled = ${@com.ruoyi.common.enums.DisabledEnum@NO.getCode()}
    </select>
</mapper>