其实每个内容里,最麻烦的就是新增和修改的这张表单,以及之后需要编写的一层一层汇总查询。以后都按照新增-列出-修改-删除的顺序来开发各个内容。
列出合同
列出合同其实最重要的是列出合同的付款情况,以及提示是否超付。不过由于目前没有编写到明细记录也就是Journal
类,所以只能暂且列出来合同的部分信息;而且列出合同我设计了两个功能,一个是列出这个项目的所有合同,一个是列出某个预算对应的合同。
列出一个项目的所有合同
我们首先要解决的就是如何查询一个项目的所有合同,由于预算条目都从属于同一个项目,因此比较简单的办法就是查出所有的某个项目的预算,由于我们必须要去重,所以在给Dao
编写方法的时候,不能使用List
,而要使用Set
:
public interface ContractDao extends JpaRepository<Contract, Integer> {
List<Contract> findContractsByBudgetsContains(Budget budget);
boolean existsByNumber(String number);
Set<Contract> findContractsByBudgetsIn(List<Budget> budgets);
}
这样我们先查出某个项目的所有预算条目,然后将这些预算条目所属的合同全部找出来,也就找到了这个项目的所有合同。
然后看我们的URL
,给Project
类再加上一条生成URL
的方法:
public String contractListUrl() {
return "/pms/contract/project/" + id + "/list";
}
之后就是控制器了,比较简单:
@GetMapping("/project/{pid}/list")
public String contractListByProject(@PathVariable("pid") int pid, Model model) {
Project project = projectService.findById(pid);
List<Budget> budgets = budgetService.getBudgetByProjectId(pid);
Set<Contract> contracts = contractService.getContractsByBudgets(budgets);
model.addAttribute("contracts", contracts);
model.addAttribute("project", project);
model.addAttribute("count", contracts.size());
return "pms/contract/contractListProject";
}
这里就利用了刚刚编写的方法,找到一个项目对应的所有合同然后传入页面,页面现在写了一个最简单的迭代展示,还有一些字段需要之后来展示:
<main class="container">
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb" class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/project/list}" class="link-secondary">项目管理</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
th:href="${project.absoluteUrl()}"
class="link-secondary">[[${project.projectName}]]</a>
</li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
th:href="${project.contractListUrl()}"
class="link-secondary">合同列表</a>
</li>
</ol>
</nav>
<div class="row py-1" >
<div class="col-sm-4"></div>
<div th:if="${created}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${created}]]
</div>
<div th:if="${updated}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${updated}]]
</div>
<div th:if="${deleted}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${deleted}]]
</div>
<div class="col-sm-4"></div>
</div>
<p>
<a class="btn btn-primary" href="/pms/project/add" th:href="${project.addContractUrl()}"><i class="fas fa-plus"></i> 新增合同</a>
</p>
<table class="table table-hover" th:if="${count != 0}">
<thead>
<tr>
<th>合同编号</th>
<th>合同名称</th>
<th>合同总价</th>
</tr>
</thead>
<tbody>
<tr th:each="contract, control:${contracts}">
<td th:text="${contract.number}"></td>
<td th:text="${contract.name}"></td>
<td th:text="${#numbers.formatDecimal(contract.totalPrice,0,'COMMA',2,'POINT')}"></td>
</tr>
</tbody>
</table>
</main>
列出一个预算条目对应的所有合同
由于这个URL
中的变量是bid
,自然就把生成URL
的方法写在Budget
类中:
public String contractListUrl() {
return "/pms/contract/budget/" + id + "/list";
}
控制器稍稍有所不同,需要将Budget
对象也传入模型中:
@GetMapping("/budget/{bid}/list")
public String contractListByBudget(@PathVariable("bid") int bid, Model model) {
Budget budget = budgetService.findById(bid);
Project project = budget.getProject();
Set<Contract> contracts = contractService.getContractBySingleBudget(budget);
model.addAttribute("budget", budget);
model.addAttribute("contracts", contracts);
model.addAttribute("project", project);
model.addAttribute("count", contracts.size());
return "pms/contract/contractListBudget";
}
这里把原来Dao
中的List<?>
都改成了Set
,直接就等于去重了。页面只要使用项目列表的页面稍加修改:
<main class="container">
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb" class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/project/list}" class="link-secondary">项目管理</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
th:href="${project.absoluteUrl()}"
class="link-secondary">[[${project.projectName}]]</a>
</li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/budget/detail"
th:href="${'/pms/budget/' + project.getId() +'/detail/'+ budget.getId()}"
class="link-secondary">[[${budget.budgetName}]]</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
th:href="${budget.contractListUrl()}"
class="link-secondary">合同列表</a>
</li>
</ol>
</nav>
<div class="row py-1" >
<div class="col-sm-4"></div>
<div th:if="${created}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${created}]]
</div>
<div th:if="${updated}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${updated}]]
</div>
<div th:if="${deleted}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
[[${deleted}]]
</div>
<div class="col-sm-4"></div>
</div>
<p>
<a class="btn btn-primary" href="/pms/project/add" th:href="${project.addContractUrl()}"><i class="fas fa-plus"></i> 新增合同</a>
</p>
<table class="table table-hover" th:if="${count != 0}">
<thead>
<tr>
<th>合同编号</th>
<th>合同名称</th>
<th>合同总价</th>
</tr>
</thead>
<tbody>
<tr th:each="contract, control:${contracts}">
<td th:text="${contract.number}"></td>
<td th:text="${contract.name}"></td>
<td th:text="${#numbers.formatDecimal(contract.totalPrice,0,'COMMA',2,'POINT')}"></td>
</tr>
</tbody>
</table>
</main>
做完上述步骤后,记得到项目和预算条目的详情页,将功能导航中的功能链接修改成实际可用的链接,这样就写好了两种列出合同的方式。