无关风月
2025-03-21 1e1d0497cc600cc10c22c217b35fb3c43a1e024f
Merge branch 'master' of https://gitee.com/xiaochen991015/xizang
20个文件已修改
12个文件已添加
897 ■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ScreenController.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TInvoiceController.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TStreetController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TencentCosUtil.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/TencentMailUtil.java 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TContractMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/THouseMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TStreetMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/THouse.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TStreet.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/model/TTenant.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ITStreetService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TContractService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TInvoiceService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ScreenService.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/THouseServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TInvoiceServiceImpl.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TStreetServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenRentIncomeTrendVO.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenRentRankVO.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenTopStaticsDataVO.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TenantCountTrendVO.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/TStreetMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/ScreenController.java
New file
@@ -0,0 +1,78 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.service.TContractService;
import com.ruoyi.system.service.impl.ScreenService;
import com.ruoyi.system.vo.ScreenRentIncomeTrendVO;
import com.ruoyi.system.vo.ScreenRentRankVO;
import com.ruoyi.system.vo.ScreenTopStaticsDataVO;
import com.ruoyi.system.vo.TenantCountTrendVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @author mitao
 * @date 2025/3/19
 */
@Api(tags = {"大屏相关接口"})
@RestController
@RequestMapping("/screen")
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class ScreenController {
    private final ScreenService screenService;
    @GetMapping("/statics-data")
    @ApiOperation(value = "获取顶部统计数据")
    public R<ScreenTopStaticsDataVO> getTopStaticsData() {
        return R.ok(screenService.getTopStaticsData());
    }
    @GetMapping("/rent-rank")
    @ApiOperation("区域租金排名")
    public R<List<ScreenRentRankVO>> rentRank() {
        return R.ok(screenService.streetRentRank());
    }
    @GetMapping("/rent-income-trend")
    @ApiOperation("租金收入趋势")
    public R<ScreenRentIncomeTrendVO> rentIncomeTrend() {
        return R.ok(screenService.rentIncomeTrend());
    }
    private final TContractService contractService;
    @GetMapping("/getTenantCountTrend")
    @ApiModelProperty(value = "租户数量趋势统计")
    public R<?> getTenantCountTrend() {
        // 获取所有签约时间不为空的合同
        List<TContract> contracts = contractService.list(new LambdaQueryWrapper<TContract>()
                .isNotNull(TContract::getSignTime));
        // 使用年-月格式化日期,并按此分组计算每个时间段的合同数量
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yy-M");
        List<TenantCountTrendVO> trendData = contracts.stream()
                .collect(Collectors.groupingBy(contract -> contract.getSignTime().toLocalDate()
                        .withDayOfMonth(1) // 将日期调整为该月的第一天,以便正确分组
                        .atStartOfDay()))
                .entrySet().stream()
                .map(entry -> {
                    String period = entry.getKey().format(formatter);
                    long count = entry.getValue().size();
                    return new TenantCountTrendVO(period, count);
                })
                .collect(Collectors.toList());
        return R.ok(trendData);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -80,6 +80,8 @@
    private StateProcessTemplateService stateProcessTemplateService;
    @Autowired
    private FlwTaskMapper flwTaskMapper;
    @Autowired
    private TTenantService tenantService;
    @ApiOperation(value = "获取合同分页列表")
    @PostMapping(value = "/contractList")
@@ -295,13 +297,25 @@
        List<TContract> list = contractService.lambdaQuery().in(TContract::getId, dto.getIds()).list();
        List<String> res = new ArrayList<>();
        for (TContract contract : list) {
            String templateFileName = "1_yzj_租赁合同_个人.docx";
            TBill firstBill = billService.lambdaQuery().eq(TBill::getContractId, contract.getId())
                    .orderByDesc(TBill::getStartTime).last("limit 1").one();
            TTenant tenant = tenantService.getById(contract.getTenantId());
            THouse tHouse = houseService.getById(contract.getHouseId());
            Map<String, Object> templateParam = new HashMap<>(5);
            templateParam.put("${contractNumber}", contract.getContractNumber());
            templateParam.put("${partyOneName}", contract.getPartyOneName());
            templateParam.put("${partyTwoName}", contract.getPartyTwoName());
            if (Objects.nonNull(tenant)) {
                templateParam.put("${mailAddress}", StringUtils.isNotBlank(tenant.getMailAddress()) ? tenant.getMailAddress() : "");
                templateParam.put("${idCard}", StringUtils.isNotBlank(tenant.getIdCard()) ? tenant.getIdCard() : "");
                //企业、政府机构、国有企业
                if (tenant.getTenantType().equals("2") || tenant.getTenantType().equals("5") || tenant.getTenantType().equals("7")){
                    templateParam.put("${creditCode}", StringUtils.isNotBlank(tenant.getCreditCode()) ? tenant.getCreditCode() : "");
                    templateParam.put("${legalPerson}", StringUtils.isNotBlank(tenant.getLegalPerson()) ? tenant.getLegalPerson() : "");
                    templateFileName = "1_yzj_租赁合同_企业.docx";
                }
            }
            templateParam.put("${houseAddress}", tHouse.getHouseAddress());
            templateParam.put("${houseArea}", tHouse.getHouseArea()+"m²");
            long between = ChronoUnit.DAYS.between(contract.getStartTime(), contract.getStartPayTime())+1;
@@ -339,7 +353,7 @@
                templateParam.put("${checkTime}", "");
            }
            String url = wordUtil.generatePdf("/usr/local/project/file/", "1_yzj_租赁合同.docx", templateParam, "租赁合同", "/usr/local/project/file/");
            String url = wordUtil.generatePdf("/usr/local/project/file/", templateFileName, templateParam, "租赁合同", "/usr/local/project/file/");
            res.add(url);
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TInvoiceController.java
@@ -12,10 +12,16 @@
import com.ruoyi.system.query.TInvoiceQuery;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TInvoiceService;
import com.ruoyi.web.controller.tool.TencentCosUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
@@ -33,6 +39,8 @@
    private TInvoiceService invoiceService;
    @Autowired
    TBillService tBillService;
    @Autowired
    TencentCosUtil tencentCosUtil;
    @PreAuthorize("@ss.hasPermi('invoice:list')")
    @ApiOperation(value = "获取开票列表")
    @PostMapping("/list")
@@ -58,7 +66,51 @@
    @PostMapping("/uploadVoucher")
    @PreAuthorize("@ss.hasPermi('invoice:list:payment')")
    public R<Boolean> uploadVoucher(@RequestBody TInvoiceQuery query) {
        return R.ok(invoiceService.uploadVoucher(query));
        String invoiceVoucher = query.getInvoiceVoucher();
        String invoiceVoucherName = query.getInvoiceVoucherName();
        if (invoiceVoucher == null || invoiceVoucherName == null) {
            return R.fail("请上传发票文件");
        }
        String[] voucherUrls = invoiceVoucher.split(",");
        String[] voucherNames = invoiceVoucherName.split(",");
        // 确保两个数组长度一致
        int length = Math.min(voucherUrls.length, voucherNames.length);
        if (length == 0) {
            return R.fail("请上传发票文件");
        }
        // 构建附件列表
        List<Map<String, String>> attachments = new ArrayList<>(length);
        for (int i = 0; i < length; i++) {
            String voucherUrl = voucherUrls[i];
            String fileName = voucherNames[i];
            Map<String, String> attachment = new HashMap<>(2); // 初始容量为2,避免扩容
            String tempDir = System.getProperty("java.io.tmpdir");
            Path filePath = Paths.get(tempDir, fileName);
            // 保存到临时目录
            tencentCosUtil.download(voucherUrl,filePath.toString(),fileName);
            attachment.put("filePath", filePath.toString());
            attachment.put("fileName", fileName);
            attachments.add(attachment);
        }
        return R.ok(invoiceService.uploadVoucher(query,attachments));
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TStreetController.java
New file
@@ -0,0 +1,50 @@
package com.ruoyi.web.controller.api;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.model.TStreet;
import com.ruoyi.system.service.ITStreetService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>
 * 街道 前端控制器
 * </p>
 *
 * @author mitao
 * @since 2025-03-19
 */
@Api(tags = {"街道相关接口"})
@RestController
@RequestMapping("/t-street")
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class TStreetController {
    private final ITStreetService tStreetService;
    @GetMapping("/list")
    @ApiOperation(value = "获取街道列表")
    public R<List<TStreet>> list() {
        return R.ok(tStreetService.list());
    }
    @GetMapping("/init")
    @ApiOperation(value = "初始化街道列表")
    public R<?> init(){
        ArrayList<String> strings = Lists.newArrayList("八廓街道", "吉日街道", "布达拉宫广场街道", "公德林街道", "扎细街道", "纳金街道", "娘热街道", "金珠西路街道", "堆龙德庆区东嘎街道", "两岛街道", "柳梧新区柳梧乡", "色拉街道", "蔡公堂街道", "娘热路街道", "夺底街道", "纳如街道");
        strings.forEach(streetName->{
            TStreet tStreet = new TStreet();
            tStreet.setStreetName(streetName);
            tStreetService.save(tStreet);
        });
        return R.ok();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TencentCosUtil.java
@@ -27,6 +27,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
@@ -256,4 +261,29 @@
    }
    /**
     * 将文件下载到指定目录
     * @param fileUrl
     * @param saveDir
     * @param fileName
     * @throws IOException
     */
    public void download(String fileUrl, String saveDir, String fileName){
        fileUrl = fileUrl.replace(cosConfig.getRootSrc(), "");
        // 下载文件并获取输入流
        COSObject object = cosClient.getObject(cosConfig.getBucketName(),fileUrl);
        try (
                InputStream in = object.getObjectContent();
                ){
            Path targetPath = Paths.get(saveDir, fileName);
            // 确保目录存在
            Files.createDirectories(targetPath.getParent());
            // 将文件保存到目标路径
            Files.copy(in, targetPath, StandardCopyOption.REPLACE_EXISTING);
        }catch (IOException e){
            log.error("读取cos图片发生异常", e);
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -1,16 +1,21 @@
package com.ruoyi.common.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.time.DateFormatUtils;
/**
 * 时间工具类
@@ -267,7 +272,7 @@
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, startMonth);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        Date first = cal.getTime();
@@ -279,9 +284,9 @@
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, lastMonth);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        Date last = cal.getTime();
        map.put("last", last);
ruoyi-common/src/main/java/com/ruoyi/common/utils/TencentMailUtil.java
@@ -8,16 +8,18 @@
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import java.net.URLEncoder;
import javax.activation.URLDataSource;
import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
@@ -132,14 +134,43 @@
            // 设置邮件标题
            message.setSubject("发票");
            // 创建邮件内容
            Multipart multipart = createMultipart(list);
            Multipart multipart = new MimeMultipart();
            // 添加文本消息部分
            BodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setHeader("Content-Type", "text/plain;charset=utf-8");
            messageBodyPart.setContent("您在小程序提交的开票申请已开票成功,请查看附件内容","text/html;charset=UTF-8");
            multipart.addBodyPart(messageBodyPart);
            List<Path> tempFilePath = new ArrayList<>();
            // 添加附件部分
            for (Map<String, String> map : list) {
                messageBodyPart = new MimeBodyPart();
                String filePath = map.get("filePath");
                String fileName = map.get("fileName");
                tempFilePath.add(Paths.get(filePath));
                FileDataSource source = new FileDataSource(filePath);
                messageBodyPart.setDataHandler(new DataHandler(source));
                String filenameEncode = MimeUtility.encodeText(fileName, "UTF-8", "base64");
                // String encodedFileName = Base64.getEncoder().encodeToString(fileName.getBytes(StandardCharsets.UTF_8));
                // String filenameEncode = MimeUtility.encodeText(encodedFileName);
                messageBodyPart.setFileName(filenameEncode);
                messageBodyPart.setHeader("Content-Transfer-Encoding", "base64");
                messageBodyPart.setHeader("Content-Disposition", "attachment");
                messageBodyPart.setHeader("Content-Type", "application/octet-stream;name=\"" + filenameEncode + "\"");
                multipart.addBodyPart(messageBodyPart);
            }
            // 设置邮件内容
            message.setContent(multipart);
            // 发送邮件
            Transport.send(message);
            // 删除临时目录里面的文件
            for (Path path : tempFilePath) {
                Files.deleteIfExists(path);
            }
        } catch (MessagingException | UnsupportedEncodingException | MalformedURLException e) {
            log.error("发送邮件发生异常", e);
            throw new ServiceException("发送邮件失败, 请检查");
        } catch (IOException e) {
            throw new RuntimeException("文件下载发生异常");
        }
    }
@@ -167,31 +198,6 @@
                return new PasswordAuthentication(userName, password);
            }
        };
    }
    private Multipart createMultipart(List<Map<String, String>> list) throws MessagingException, UnsupportedEncodingException, MalformedURLException {
        Multipart multipart = new MimeMultipart();
        // 添加文本消息部分
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setHeader("Content-Type", "text/plain;charset=utf-8");
        messageBodyPart.setContent("您在小程序提交的开票申请已开票成功,请查看附件内容","text/html;charset=UTF-8");
        multipart.addBodyPart(messageBodyPart);
        // 添加附件部分
        for (Map<String, String> map : list) {
            messageBodyPart = new MimeBodyPart();
            String url = map.get("url");
            String fileName = map.get("fileName");
            URLDataSource source = new URLDataSource(new URL(url));
            messageBodyPart.setDataHandler(new DataHandler(source));
            String filenameEncode = MimeUtility.encodeText(fileName, "UTF-8", "base64");
            messageBodyPart.setFileName(filenameEncode);
            messageBodyPart.setHeader("Content-Transfer-Encoding", "base64");
            messageBodyPart.setHeader("Content-Disposition", "attachment");
            messageBodyPart.setHeader("Content-Type", "application/octet-stream;name=\"" + filenameEncode + "\"");
            multipart.addBodyPart(messageBodyPart);
        }
        return multipart;
    }
   // public static void main(String[] args) throws UnsupportedEncodingException {
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TBillMapper.java
@@ -5,9 +5,9 @@
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.query.TBillQuery;
import com.ruoyi.system.vo.ScreenRentRankVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.math.BigDecimal;
import java.util.List;
@@ -46,4 +46,9 @@
    BigDecimal statisticsOverdue();
    Integer batchBillCount(@Param("userId")String userId, @Param("billIds")List<String> billIds);
    /**
     * 街道租金排行
     * @return
     */
    List<ScreenRentRankVO> getStreetRentRank();
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TContractMapper.java
@@ -28,4 +28,9 @@
    List<BillVO> contractBillList(@Param("query") TContractBillQuery query, @Param("pageInfo") PageInfo<BillVO> pageInfo);
    List<TContract> contractExportList(@Param("query")TContractQuery query);
    /**
     * 本月新增租户数
     * @return
     */
    Integer getCurrentMonthRentCount();
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/THouseMapper.java
@@ -24,4 +24,5 @@
    List<HouseVO> userHistoryList(@Param("req")TUserHistoryQuery query, @Param("pageInfo")PageInfo<HouseVO> pageInfo);
    Double getHouseRentedArea();
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TStreetMapper.java
New file
@@ -0,0 +1,16 @@
package com.ruoyi.system.mapper;
import com.ruoyi.system.model.TStreet;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
 * <p>
 * 街道 Mapper 接口
 * </p>
 *
 * @author mitao
 * @since 2025-03-19
 */
public interface TStreetMapper extends BaseMapper<TStreet> {
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TContract.java
@@ -149,6 +149,15 @@
    @ApiModelProperty(value = "合同状态 1=待提交 2=待审批 3=未签订 4=已签订 5=已驳回 6=已终止 7=待结算 8=已结算 9 = 签订待审核")
    @TableField("status")
    private String status;
    /**
     * 签订时间
     */
    @ApiModelProperty(value = "签订时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField("sign_time")
    private LocalDateTime signTime;
    @ApiModelProperty(value = "内存大小多个文件逗号拼接")
    @TableField("memory")
    private String memory;
ruoyi-system/src/main/java/com/ruoyi/system/model/THouse.java
@@ -1,18 +1,18 @@
package com.ruoyi.system.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
@@ -94,4 +94,16 @@
    @ApiModelProperty(value = "住户类型 1月租 2季租 3年租")
    @TableField(exist = false)
    private String tenantType;
    @ApiModelProperty(value = "所属街道id")
    @TableField("street_id")
    private String streetId;
    @ApiModelProperty(value = "经度")
    @TableField("longitude")
    private BigDecimal longitude;
    @ApiModelProperty(value = "纬度")
    @TableField("latitude")
    private BigDecimal latitude;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TStreet.java
New file
@@ -0,0 +1,38 @@
package com.ruoyi.system.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
 * <p>
 * 街道
 * </p>
 *
 * @author mitao
 * @since 2025-03-19
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_street")
@ApiModel(value="TStreet对象", description="街道")
public class TStreet extends BaseModel implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;
    @ApiModelProperty(value = "物品名称")
    private String streetName;
}
ruoyi-system/src/main/java/com/ruoyi/system/model/TTenant.java
@@ -1,14 +1,9 @@
package com.ruoyi.system.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseModel;
import io.swagger.annotations.ApiModel;
@@ -18,6 +13,7 @@
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
/**
 * <p>
@@ -92,4 +88,12 @@
    @TableField("open_id")
    private String openId;
    @ApiModelProperty(value = "法人")
    @TableField("legal_person")
    private String legalPerson;
    @ApiModelProperty(value = "社会统一信用代码")
    @TableField("credit_code")
    private String creditCode;
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ITStreetService.java
New file
@@ -0,0 +1,16 @@
package com.ruoyi.system.service;
import com.ruoyi.system.model.TStreet;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * 街道 服务类
 * </p>
 *
 * @author mitao
 * @since 2025-03-19
 */
public interface ITStreetService extends IService<TStreet> {
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TBillService.java
@@ -2,18 +2,21 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.system.dto.*;
import com.ruoyi.system.dto.BillStatisticsDto;
import com.ruoyi.system.dto.CachPayDto;
import com.ruoyi.system.dto.OfflinePayCheckDto;
import com.ruoyi.system.dto.SmsByBillDto;
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.dto.TbillSaveDto;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.query.TBillQuery;
import com.ruoyi.system.vo.ScreenRentRankVO;
import com.taxi591.bankapi.dto.ChargeBillRequest;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.List;
/**
 * <p>
@@ -87,4 +90,10 @@
    BillStatisticsDto statistics();
    Integer batchBillCount(String userId, List<String> billIds);
    /**
     * 查询街道租金排行
     * @return
     */
    List<ScreenRentRankVO> getStreetRentRank();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TContractService.java
@@ -43,4 +43,9 @@
    Boolean updateContractAuditStatus(String projectId, Integer submitStatus);
    /**
     * 本月新增租户数
     * @return
     */
    Integer getCurrentMonthRentCount();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/TInvoiceService.java
@@ -7,6 +7,7 @@
import com.ruoyi.system.query.TInvoiceQuery;
import java.util.List;
import java.util.Map;
/**
 * <p>
@@ -19,5 +20,5 @@
public interface TInvoiceService extends IService<TInvoice> {
    PageInfo<TInvoice> pageList(TInvoiceQuery query);
    List<TInvoice> makeQuery(TInvoiceQuery query);
    Boolean uploadVoucher(TInvoiceQuery query);
    Boolean uploadVoucher(TInvoiceQuery query, List<Map<String, String>> map);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ScreenService.java
New file
@@ -0,0 +1,129 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.THouse;
import com.ruoyi.system.service.ITStreetService;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TContractService;
import com.ruoyi.system.service.THouseService;
import com.ruoyi.system.vo.ScreenRentIncomeTrendVO;
import com.ruoyi.system.vo.ScreenRentRankVO;
import com.ruoyi.system.vo.ScreenTopStaticsDataVO;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Calendar;
import java.util.ArrayList;
/**
 * @author mitao
 * @date 2025/3/19
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class ScreenService {
    private final THouseService tHouseService;
    private final TContractService tContractService;
    private final TBillService tBillService;
    private final ITStreetService tStreetService;
    /**
     * 获取顶部统计数据
     * @return
     */
    public ScreenTopStaticsDataVO getTopStaticsData() {
        ScreenTopStaticsDataVO vo = new ScreenTopStaticsDataVO();
        //房屋总面积
        List<THouse> houseList = tHouseService.list();
        Double totalArea = houseList.stream().map(item -> Double.parseDouble(item.getHouseArea())).reduce(0D, Double::sum);
        vo.setHouseTotalArea(totalArea);
        //已出租面积
        Double totalRentedArea = houseList.stream().filter(item -> !item.getLeaseStatus().equals("1"))
                .map(item -> Double.parseDouble(item.getHouseArea())).reduce(0D, Double::sum);
        vo.setHouseRentedArea(totalRentedArea);
        //总计应收租金
        List<TBill> billList = tBillService.list();
        BigDecimal totalReceivableRent = billList.stream().filter(item -> !item.getPayFeesStatus().equals("5"))
                .map(TBill::getPayableFeesMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        vo.setTotalReceivableRent(totalReceivableRent);
        //总计已收租金
        BigDecimal totalReceivedRent = billList.stream().map(TBill::getPayFeesMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        vo.setTotalReceivedRent(totalReceivedRent);
        //本月新增租户数
        Integer newTenantCount = tContractService.getCurrentMonthRentCount();
        vo.setNewTenantCount(newTenantCount);
        //总计租户数 系统租户列表里有生效合同绑定的租户总数。
        Long count = tContractService.lambdaQuery().in(TContract::getStatus, "4", "5", "6", "7", "8", "9").groupBy(TContract::getTenantId).count();
        vo.setTotalTenantCount(count.intValue());
        Map<String, Date> quarterDate = DateUtils.getQuarterDate(new Date());
        Date first = quarterDate.get("first");
        Date last = quarterDate.get("last");
        List<TBill> currentQuarterBillList = tBillService.lambdaQuery().between(TBill::getPayableFeesTime, first, last).list();
        //本季度已交租金
        BigDecimal totalRentPaid = currentQuarterBillList.stream().map(TBill::getPayFeesMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        vo.setTotalRentPaid(totalRentPaid);
        //本季度应交租金
        BigDecimal totalRentShould = currentQuarterBillList.stream().filter(item -> !item.getPayFeesStatus().equals("5"))
                .map(TBill::getPayableFeesMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        vo.setTotalRentShould(totalRentShould);
        return vo;
    }
    /**
     * 区域租金排名
     * @return
     */
    public List<ScreenRentRankVO> streetRentRank() {
        return  tBillService.getStreetRentRank();
    }
    /**
     * 租金收入趋势
     * @return
     */
    public ScreenRentIncomeTrendVO rentIncomeTrend() {
        ScreenRentIncomeTrendVO vo = new ScreenRentIncomeTrendVO();
        // 获取当前日期
        Date currentDate = new Date();
        List<String> quarterLabels = new ArrayList<>();
        List<BigDecimal> incomeData = new ArrayList<>();
        // 获取最近7个季度的数据
        for (int i = 6; i >= 0; i--) {
            // 计算对应季度的起止时间
            Date targetDate = DateUtils.addMonths(currentDate, -3 * i);
            Map<String, Date> quarterDate = DateUtils.getQuarterDate(targetDate);
            Date quarterStart = quarterDate.get("first");
            Date quarterEnd = quarterDate.get("last");
            // 获取该季度的账单数据并计算总和
            BigDecimal quarterIncome = tBillService.lambdaQuery()
                .between(TBill::getPayableFeesTime, quarterStart, quarterEnd)
                .list()
                .stream()
                .map(TBill::getPayFeesMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 生成季度标签 (格式: YY-MM月)
            Calendar cal = Calendar.getInstance();
            cal.setTime(quarterEnd);
            String label = String.format("%02d-%d月",
                cal.get(Calendar.YEAR) % 100,
                cal.get(Calendar.MONTH) + 1);
            quarterLabels.add(label);
            incomeData.add(quarterIncome);
        }
        vo.setQuarters(quarterLabels);
        vo.setIncomeData(incomeData);
        return vo;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TBillServiceImpl.java
@@ -1,21 +1,42 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.config.SmsProperties;
import com.ruoyi.common.constant.AmountConstant;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.OrderNos;
import com.ruoyi.common.utils.SmsUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TencentMailUtil;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.dto.*;
import com.ruoyi.system.dto.BillStatisticsDto;
import com.ruoyi.system.dto.CachPayDto;
import com.ruoyi.system.dto.OfflinePayCheckDto;
import com.ruoyi.system.dto.SmsByBillDto;
import com.ruoyi.system.dto.TBillDto;
import com.ruoyi.system.dto.TbillSaveDto;
import com.ruoyi.system.mapper.TBillMapper;
import com.ruoyi.system.model.*;
import com.ruoyi.system.model.TBankFlow;
import com.ruoyi.system.model.TBill;
import com.ruoyi.system.model.TBillDetail;
import com.ruoyi.system.model.TFlowManagement;
import com.ruoyi.system.model.TInvoiceToBill;
import com.ruoyi.system.model.TOrderBill;
import com.ruoyi.system.model.TPayOrder;
import com.ruoyi.system.query.TBillQuery;
import com.ruoyi.system.query.TInvoiceToBillQuery;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.TBankFlowService;
import com.ruoyi.system.service.TBillConfirmService;
import com.ruoyi.system.service.TBillDetailService;
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TFlowManagementService;
import com.ruoyi.system.service.TInvoiceToBillService;
import com.ruoyi.system.service.TOrderBillService;
import com.ruoyi.system.service.TPayOrderService;
import com.ruoyi.system.vo.ScreenRentRankVO;
import com.taxi591.bankapi.dto.ChargeBillRequest;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
@@ -28,7 +49,6 @@
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
@@ -552,5 +572,12 @@
        return this.baseMapper.batchBillCount(userId,billIds);
    }
    /**
     * 街道租金排行
     * @return
     */
    @Override
    public List<ScreenRentRankVO> getStreetRentRank() {
        return baseMapper.getStreetRentRank();
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TContractServiceImpl.java
@@ -4,6 +4,7 @@
import com.aizuda.bpm.mybatisplus.mapper.FlwHisTaskMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.core.domain.R;
@@ -17,7 +18,9 @@
import com.ruoyi.system.mapper.TCheckAcceptRecordMapper;
import com.ruoyi.system.mapper.TContractMapper;
import com.ruoyi.system.mapper.THouseMapper;
import com.ruoyi.system.model.*;
import com.ruoyi.system.model.TCheckAcceptRecord;
import com.ruoyi.system.model.TContract;
import com.ruoyi.system.model.THouse;
import com.ruoyi.system.query.TContractAppletQuery;
import com.ruoyi.system.query.TContractBillQuery;
import com.ruoyi.system.query.TContractQuery;
@@ -25,21 +28,17 @@
import com.ruoyi.system.service.TBillService;
import com.ruoyi.system.service.TContractRentTypeService;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * <p>
@@ -195,7 +194,19 @@
    @Override
    public Boolean updateContractAuditStatus(String projectId, Integer status) {
        LambdaUpdateWrapper<TContract> contractLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        contractLambdaUpdateWrapper.eq(TContract::getId, projectId).set(TContract::getStatus, status);
        contractLambdaUpdateWrapper
                .eq(TContract::getId, projectId)
                .set(TContract::getStatus, status)
                .set(TContract::getSignTime, LocalDateTime.now());
        return this.update(contractLambdaUpdateWrapper);
    }
    /**
     * 本月新增租户数
     * @return
     */
    @Override
    public Integer getCurrentMonthRentCount() {
        return baseMapper.getCurrentMonthRentCount();
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/THouseServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.constant.DictConstants;
import com.ruoyi.common.utils.DictUtils;
@@ -12,7 +13,6 @@
import com.ruoyi.system.query.THouseQuery;
import com.ruoyi.system.query.TUserHistoryQuery;
import com.ruoyi.system.service.THouseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.vo.HouseVO;
import org.springframework.stereotype.Service;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TInvoiceServiceImpl.java
@@ -58,7 +58,7 @@
    }
    @Override
    public Boolean uploadVoucher(TInvoiceQuery query) {
    public Boolean uploadVoucher(TInvoiceQuery query, List<Map<String, String>> map) {
        // 检查是否存在对应的发票记录
        TInvoice preexist = getById(query.getId());
        if (preexist == null) {
@@ -74,17 +74,11 @@
        tInvoice.setInvoiceTime(query.getInvoiceTime());
        tInvoice.setStatus(2);
        // 处理附件信息
        List<Map<String, String>> attachments = buildAttachments(query.getInvoiceVoucher(), query.getInvoiceVoucherName());
        if (attachments.isEmpty()) {
            log.warn("未找到有效的附件信息");
            return updateById(tInvoice);
        }
        // 异步发送邮件
        CompletableFuture.runAsync(() -> {
            try {
                mailUtil.sendInvoice(preexist.getEmail(), attachments);
                mailUtil.sendInvoice(preexist.getEmail(), map);
            } catch (ServiceException e) {
                log.error("邮件发送失败", e);
            }
@@ -93,57 +87,4 @@
        // 更新数据库
        return updateById(tInvoice);
    }
    private List<Map<String, String>> buildAttachments(String invoiceVoucher, String invoiceVoucherName) {
        if (invoiceVoucher == null || invoiceVoucherName == null) {
            return Collections.emptyList();
        }
        String[] voucherUrls = invoiceVoucher.split(",");
        String[] voucherNames = invoiceVoucherName.split(",");
        // 确保两个数组长度一致
        int length = Math.min(voucherUrls.length, voucherNames.length);
        if (length == 0) {
            return Collections.emptyList();
        }
        // 构建附件列表
        List<Map<String, String>> attachments = new ArrayList<>(length);
        for (int i = 0; i < length; i++) {
            Map<String, String> attachment = new HashMap<>(2); // 初始容量为2,避免扩容
            attachment.put("url", voucherUrls[i]);
            attachment.put("fileName", voucherNames[i]);
            attachments.add(attachment);
        }
        return attachments;
    }
    // @Override
    // public Boolean uploadVoucher(TInvoiceQuery query) {
    //     TInvoice preexist = getById(query.getId());
    //     if (preexist == null){
    //         return false;
    //     }
    //     TInvoice tInvoice = new TInvoice();
    //     tInvoice.setId(query.getId());
    //     tInvoice.setInvoiceVoucher(query.getInvoiceVoucher());
    //     tInvoice.setInvoiceVoucherName(query.getInvoiceVoucherName());
    //     tInvoice.setInvoiceTime(query.getInvoiceTime());
    //     tInvoice.setStatus(2);
    //     List<Map<String, String>> mapArrayList = new ArrayList<>();
    //     String invoiceVoucher = query.getInvoiceVoucher();
    //     String invoiceVoucherName = query.getInvoiceVoucherName();
    //
    //     List<String> list = Arrays.stream(invoiceVoucher.split(",")).collect(Collectors.toList());
    //     for (int i = 0; i < list.size()-1; i++) {
    //         Map<String, String> map = new HashMap<>();
    //         map.put("url", list.get(i));
    //         map.put("fileName",invoiceVoucherName.split(",")[i]);
    //         mapArrayList.add(map);
    //     }
    //     mailUtil.sendInvoice(preexist.getEmail(),mapArrayList);
    //     return updateById(tInvoice);
    // }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TStreetServiceImpl.java
New file
@@ -0,0 +1,20 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.system.model.TStreet;
import com.ruoyi.system.mapper.TStreetMapper;
import com.ruoyi.system.service.ITStreetService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 街道 服务实现类
 * </p>
 *
 * @author mitao
 * @since 2025-03-19
 */
@Service
public class TStreetServiceImpl extends ServiceImpl<TStreetMapper, TStreet> implements ITStreetService {
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenRentIncomeTrendVO.java
New file
@@ -0,0 +1,23 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * @author mitao
 * @date 2025/3/20
 */
@Data
@ApiModel("租金收入区域视图对象")
public class ScreenRentIncomeTrendVO {
    @ApiModelProperty("x轴 时间列表")
    private List<String> quarters;
    @ApiModelProperty("y轴 收入列表")
    private List<BigDecimal> incomeData;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenRentRankVO.java
New file
@@ -0,0 +1,21 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author mitao
 * @date 2025/3/19
 */
@Data
@ApiModel("区域租金排名")
public class ScreenRentRankVO {
    @ApiModelProperty("街道名称")
    private String streetName;
    @ApiModelProperty("租金")
    private BigDecimal rentAmount;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/ScreenTopStaticsDataVO.java
New file
@@ -0,0 +1,41 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author mitao
 * @date 2025/3/19
 */
@Data
@ApiModel("顶部统计数据")
public class ScreenTopStaticsDataVO {
    @ApiModelProperty("房屋总面积")
    private Double houseTotalArea;
    @ApiModelProperty("已出租面积")
    private Double houseRentedArea;
    @ApiModelProperty("总计应收租金")
    private BigDecimal totalReceivableRent;
    @ApiModelProperty("总计已收租金")
    private BigDecimal totalReceivedRent;
    @ApiModelProperty("本月新增租户数")
    private Integer newTenantCount;
    @ApiModelProperty("总计租户数")
    private Integer totalTenantCount;
    @ApiModelProperty("本季度已交租金")
    private BigDecimal totalRentPaid;
    @ApiModelProperty("本季度应交租金")
    private BigDecimal totalRentShould;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TenantCountTrendVO.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("租户数量趋势统计")
public class TenantCountTrendVO {
    @ApiModelProperty(value = "日期")
    private String date;
    @ApiModelProperty(value = "租户数量")
    private Long count;
    public TenantCountTrendVO(String date, Long count) {
        this.date = date;
        this.count = count;
    }
    public TenantCountTrendVO() {
    }
}
ruoyi-system/src/main/resources/mapper/system/TBillMapper.xml
@@ -186,4 +186,15 @@
            AND b.bill_type = 3
        </where>
    </select>
    <select id="getStreetRentRank" resultType="com.ruoyi.system.vo.ScreenRentRankVO">
        SELECT
            ts.street_name,ROUND(COALESCE(SUM(tb.pay_fees_money),0) /10000,2) AS rentAmount
        FROM
            t_street ts
                LEFT JOIN t_house th ON ts.id = th.street_id
                LEFT JOIN t_contract tc ON tc.house_id = th.id
                LEFT JOIN t_bill tb ON tc.id = tb.contract_id
        GROUP BY ts.id
        ORDER BY rentAmount DESC
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/TContractMapper.xml
@@ -124,5 +124,19 @@
        </where>
    </select>
    <select id="getCurrentMonthRentCount" resultType="java.lang.Integer">
        SELECT COUNT(DISTINCT tc.tenant_id) AS new_tenant_count
        FROM t_contract tc
        WHERE
        -- 筛选本月签订的合同
        DATE_FORMAT(tc.sign_time, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m') AND tc.status IN ("4", "5", "6", "7", "8", "9")
        -- 且租户在本月前从未签订过任何合同
        AND NOT EXISTS (
        SELECT 1
        FROM t_contract tc_hist
        WHERE tc_hist.tenant_id = tc.tenant_id
        AND tc_hist.sign_time <![CDATA[ < ]]> DATE_FORMAT(CURDATE(), '%Y-%m-01') AND tc_hist.status IN ("4", "5", "6", "7", "8", "9")
        )
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/TStreetMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.TStreetMapper">
</mapper>