1. 指标子集映射
This commit is contained in:
parent
75328fc0c5
commit
92fb41f419
|
|
@ -1,274 +1,189 @@
|
||||||
<!-- Page body -->
|
<div class="page-body" data-page="metric">
|
||||||
<style>
|
|
||||||
#tree-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 600px;
|
|
||||||
overflow: auto;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: .5rem;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,.08);
|
|
||||||
padding: 1rem;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.node-rect {
|
|
||||||
fill: #fff;
|
|
||||||
stroke: #206bc4;
|
|
||||||
stroke-width: 2px;
|
|
||||||
rx: 8;
|
|
||||||
ry: 8;
|
|
||||||
filter: drop-shadow(0px 2px 6px #206bc420);
|
|
||||||
}
|
|
||||||
.node-text {
|
|
||||||
font-size: 15px;
|
|
||||||
fill: #206bc4;
|
|
||||||
text-anchor: middle;
|
|
||||||
font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
|
|
||||||
dominant-baseline: middle;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.link {
|
|
||||||
fill: none;
|
|
||||||
stroke: #b7c4d2;
|
|
||||||
stroke-width: 2px;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
#tree-container {
|
|
||||||
height: 400px;
|
|
||||||
padding: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.center-btn {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 45%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
.context-menu {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 9999;
|
|
||||||
min-width: 140px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0 4px 18px rgba(60,72,88,0.12);
|
|
||||||
border: 1px solid #e9ecef;
|
|
||||||
font-size: 15px;
|
|
||||||
padding: 4px 0;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.context-menu-item {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 8px 18px;
|
|
||||||
transition: background 0.18s;
|
|
||||||
color: #206bc4;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
text-align: left;
|
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.context-menu-item:hover {
|
|
||||||
background: #f1f7fe;
|
|
||||||
color: #206bc4;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link href="https://unpkg.com/@tabler/core@1.0.0-beta24/dist/css/tabler.min.css" rel="stylesheet">
|
|
||||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
||||||
<div class="page-body">
|
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
|
||||||
|
<!-- 面包屑 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<nav aria-label="breadcrumb" class="mb-4">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item"><a href="#">能力评估</a></li>
|
||||||
<a href="#">指标管理</a>
|
<li class="breadcrumb-item"><a href="#">映射集</a></li>
|
||||||
</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="row g-4 mb-4">
|
|
||||||
<div class="col-md-12" id="tree-container"></div>
|
<div class="row row-cards">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">指标数据映射集设置</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<!-- 1. 选择指标(根指标)- 下拉 -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">1. 选择指标(根指标)</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<label class="form-label m-0">根指标</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<select id="rootSelect" class="form-select">
|
||||||
|
<option value="quality" selected>质量指标</option>
|
||||||
|
<option value="safety">安全指标</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small mt-2">切换根指标会刷新下面的“子指标映射表”。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. 上传 CSV(模拟解析结果) -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">2. 上传 CSV 文件</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<input type="file" class="form-control mb-3" accept=".csv">
|
||||||
|
<div class="fw-bold mb-2">已解析表头(模拟 50 列)</div>
|
||||||
|
<div id="csvHeads" class="list-group list-group-flush csv-heads"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. 子指标映射设置 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">3. 子指标映射设置</div>
|
||||||
|
<div class="ms-auto">
|
||||||
|
<div class="btn-list">
|
||||||
|
<button class="btn btn-outline-primary" id="allFormBtn">全部切到 Form</button>
|
||||||
|
<button class="btn btn-outline-primary" id="allCsvBtn">全部切到 CSV</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="map-scroller">
|
||||||
|
<table class="table table-vcenter map-table" id="mapTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sticky-top" style="width:48px;">#</th>
|
||||||
|
<th class="indicator-col sticky-top" style="width:200px;">子指标名称</th>
|
||||||
|
<th class="sticky-top" style="width:130px;">来源</th>
|
||||||
|
<th class="sticky-top" style="width:320px;">表单字段</th>
|
||||||
|
<th class="sticky-top" style="width:320px;">CSV 表头</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="mapTableBody"><!-- JS 渲染 --></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- /card-body -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右键菜单 -->
|
<!-- 样式:滚动与粘性 -->
|
||||||
<div id="context-menu" class="context-menu"></div>
|
<style>
|
||||||
|
.csv-heads{ max-height:150px; overflow:auto; }
|
||||||
|
.map-scroller{ max-height:65vh; overflow:auto; border-radius:.5rem; }
|
||||||
|
.map-table{ table-layout:fixed; width:max-content; min-width:1200px; border-collapse:separate; border-spacing:0; }
|
||||||
|
.map-table th, .map-table td{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||||
|
.sticky-top{ position:sticky; top:0; z-index:3; background:#fff; }
|
||||||
|
.indicator-col{ position:sticky; left:0; z-index:4; background:#fff; box-shadow:2px 0 0 rgba(0,0,0,.06); }
|
||||||
|
.btn-group .btn{ min-width:52px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- 依赖:若你项目里已全局引入,可删掉下面两行 CDN -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select/dist/css/tom-select.bootstrap5.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/tom-select/dist/js/tom-select.complete.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let treeData = null;
|
// ===== 静态数据 =====
|
||||||
|
const formFields = ["qualifiedRate","defectCount","inspectionDate","checkPerson","location","comment"];
|
||||||
|
const csvCols = Array.from({length:50}, (_,i)=>`col_${i+1}`);
|
||||||
|
const indicatorsByRoot = {
|
||||||
|
quality: Array.from({length:20}, (_,i)=>({ id:i+1, name:`质量_子指标_${i+1}` })),
|
||||||
|
safety: Array.from({length:20}, (_,i)=>({ id:i+1, name:`安全_子指标_${i+1}` })),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
// CSV 表头预览
|
||||||
* 右键菜单渲染
|
document.getElementById('csvHeads').innerHTML =
|
||||||
*/
|
csvCols.map(c=>`<div class="list-group-item">${c}</div>`).join('');
|
||||||
function showContextMenu(x, y, nodeData) {
|
|
||||||
// 定义菜单项
|
|
||||||
const menuItems = [
|
|
||||||
{ text: "添加子节点", action: "add" },
|
|
||||||
{ text: "编辑", action: "edit" },
|
|
||||||
{ text: "删除", action: "delete" }
|
|
||||||
];
|
|
||||||
|
|
||||||
const menu = document.getElementById("context-menu");
|
// 渲染子指标表格
|
||||||
menu.innerHTML = "";
|
function renderTable(rootKey){
|
||||||
menuItems.forEach(item => {
|
const tbody = document.getElementById('mapTableBody');
|
||||||
const btn = document.createElement("button");
|
tbody.innerHTML = indicatorsByRoot[rootKey].map((it,idx)=>`
|
||||||
btn.className = "context-menu-item";
|
<tr data-id="${it.id}">
|
||||||
btn.textContent = item.text;
|
<td>${idx+1}</td>
|
||||||
btn.onclick = function(e) {
|
<td class="indicator-col">${it.name}</td>
|
||||||
e.stopPropagation();
|
<td>
|
||||||
menu.style.display = "none";
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
handleMenuAction(item.action, nodeData);
|
<input type="radio" class="btn-check" name="src-${it.id}" id="src-form-${it.id}" value="FORM" checked>
|
||||||
};
|
<label class="btn btn-outline-primary" for="src-form-${it.id}">Form</label>
|
||||||
menu.appendChild(btn);
|
<input type="radio" class="btn-check" name="src-${it.id}" id="src-csv-${it.id}" value="CSV">
|
||||||
|
<label class="btn btn-outline-primary" for="src-csv-${it.id}">CSV</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="form-select form-select-sm form-sel">
|
||||||
|
<option value="">— 选择表单字段 —</option>
|
||||||
|
${formFields.map(f=>`<option>${f}</option>`).join('')}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="form-select form-select-sm csv-sel" disabled>
|
||||||
|
<option value="">— 选择 CSV 表头 —</option>
|
||||||
|
${csvCols.map(c=>`<option>${c}</option>`).join('')}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
// 绑定单行切换
|
||||||
|
tbody.querySelectorAll('input[type=radio][name^=src-]').forEach(r=>{
|
||||||
|
r.addEventListener('change', onSourceChange);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 适应视窗,避免溢出
|
// 重新初始化所有下拉的搜索(TomSelect)
|
||||||
const winW = window.innerWidth, winH = window.innerHeight;
|
document.querySelectorAll('#mapTableBody select').forEach(sel=>{
|
||||||
menu.style.left = (x + 150 > winW ? winW - 160 : x) + "px";
|
if(sel.tomselect){ sel.tomselect.destroy(); }
|
||||||
menu.style.top = (y + 120 > winH ? winH - 130 : y) + "px";
|
new TomSelect(sel, { create:false, sortField:{field:"text",direction:"asc"} });
|
||||||
menu.style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideContextMenu() {
|
|
||||||
document.getElementById("context-menu").style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 右键菜单回调
|
|
||||||
function handleMenuAction(action, nodeData) {
|
|
||||||
if (action === "add") {
|
|
||||||
// 简单示例: 添加子节点
|
|
||||||
if (!nodeData.children) nodeData.children = [];
|
|
||||||
const n = (nodeData.children.length || 0) + 1;
|
|
||||||
nodeData.children.push({ name: `新节点${n}`, weight: "0%" });
|
|
||||||
renderTree();
|
|
||||||
} else if (action === "edit") {
|
|
||||||
// 弹窗简单编辑
|
|
||||||
const newName = prompt("请输入节点名称:", nodeData.name);
|
|
||||||
if (newName && newName.trim()) {
|
|
||||||
nodeData.name = newName.trim();
|
|
||||||
renderTree();
|
|
||||||
}
|
|
||||||
} else if (action === "delete") {
|
|
||||||
// 删除节点(防止删根)
|
|
||||||
if (!nodeData.parent) {
|
|
||||||
alert("根节点不能删除!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const children = nodeData.parent.children;
|
|
||||||
const idx = children.indexOf(nodeData);
|
|
||||||
if (idx >= 0) {
|
|
||||||
children.splice(idx, 1);
|
|
||||||
renderTree();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// D3渲染
|
|
||||||
function renderTree() {
|
|
||||||
const container = d3.select("#tree-container");
|
|
||||||
container.selectAll("*").remove();
|
|
||||||
|
|
||||||
hideContextMenu();
|
|
||||||
|
|
||||||
if (!treeData) {
|
|
||||||
container.append("button")
|
|
||||||
.attr("type", "button")
|
|
||||||
.attr("class", "btn btn-primary center-btn")
|
|
||||||
.text("添加根节点")
|
|
||||||
.on("click", function() {
|
|
||||||
treeData = {
|
|
||||||
name: "根节点",
|
|
||||||
weight: "100%",
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
renderTree();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const width = Math.max(600, window.innerWidth * 0.9);
|
|
||||||
const height = Math.max(400, window.innerHeight * 0.65);
|
|
||||||
|
|
||||||
const svg = container.append("svg")
|
|
||||||
.attr("width", "100%")
|
|
||||||
.attr("height", height)
|
|
||||||
.attr("viewBox", [0, 0, width, height]);
|
|
||||||
|
|
||||||
// d3.hierarchy
|
|
||||||
const root = d3.hierarchy(treeData);
|
|
||||||
root.each(d => d.id = Math.random().toString(36).slice(2)); // 给每个节点一个唯一id
|
|
||||||
|
|
||||||
// 需要保留parent引用以便删除
|
|
||||||
function setParent(d, parent) {
|
|
||||||
d.parent = parent;
|
|
||||||
if (d.children) d.children.forEach(c => setParent(c, d));
|
|
||||||
}
|
|
||||||
setParent(treeData, null);
|
|
||||||
|
|
||||||
const treeLayout = d3.tree()
|
|
||||||
.size([width - 80, height - 100])
|
|
||||||
.separation((a, b) => a.parent === b.parent ? 1.2 : 1.8);
|
|
||||||
|
|
||||||
treeLayout(root);
|
|
||||||
|
|
||||||
// 连线
|
|
||||||
svg.append("g")
|
|
||||||
.selectAll("path")
|
|
||||||
.data(root.links())
|
|
||||||
.join("path")
|
|
||||||
.attr("class", "link")
|
|
||||||
.attr("d", d3.linkVertical()
|
|
||||||
.x(d => d.x + 40)
|
|
||||||
.y(d => d.y)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 节点
|
|
||||||
const node = svg.append("g")
|
|
||||||
.selectAll("g")
|
|
||||||
.data(root.descendants())
|
|
||||||
.join("g")
|
|
||||||
.attr("transform", d => `translate(${d.x},${d.y})`);
|
|
||||||
|
|
||||||
const rectW = 80, rectH = 40;
|
|
||||||
|
|
||||||
// 方框
|
|
||||||
node.append("rect")
|
|
||||||
.attr("class", "node-rect")
|
|
||||||
.attr("width", rectW)
|
|
||||||
.attr("height", rectH)
|
|
||||||
.attr("x", 0)
|
|
||||||
.attr("y", 0)
|
|
||||||
.on("contextmenu", (event, d) => {
|
|
||||||
event.preventDefault();
|
|
||||||
showContextMenu(event.clientX, event.clientY, d.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 名称
|
|
||||||
node.append("text")
|
|
||||||
.attr("class", "node-text")
|
|
||||||
.attr("x", rectW / 2)
|
|
||||||
.attr("y", rectH / 2 - 6)
|
|
||||||
.text(d => d.data.name);
|
|
||||||
|
|
||||||
// 权重
|
|
||||||
node.append("text")
|
|
||||||
.attr("class", "node-text")
|
|
||||||
.attr("x", rectW / 2)
|
|
||||||
.attr("y", rectH / 2 + 12)
|
|
||||||
.attr("font-size", "12px")
|
|
||||||
.attr("fill", "#425466")
|
|
||||||
.text(d => d.data.weight ? d.data.weight : "");
|
|
||||||
|
|
||||||
// 高亮交互
|
|
||||||
node.style("cursor", "pointer")
|
|
||||||
.on("mouseover", function() {
|
|
||||||
d3.select(this).select("rect").attr("stroke", "#2fb344").attr("stroke-width", 3);
|
|
||||||
})
|
|
||||||
.on("mouseout", function() {
|
|
||||||
d3.select(this).select("rect").attr("stroke", "#206bc4").attr("stroke-width", 2);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击其它地方关闭菜单
|
function onSourceChange(e){
|
||||||
|
const tr = e.target.closest('tr');
|
||||||
|
const formSel = tr.querySelector('.form-sel');
|
||||||
|
const csvSel = tr.querySelector('.csv-sel');
|
||||||
|
const formTS = formSel.tomselect;
|
||||||
|
const csvTS = csvSel.tomselect;
|
||||||
|
|
||||||
|
if(e.target.value === 'FORM'){
|
||||||
|
formSel.disabled=false; formTS.enable();
|
||||||
|
csvSel.disabled=true; csvTS.disable(); csvTS.clear(true);
|
||||||
|
}else{
|
||||||
|
csvSel.disabled=false; csvTS.enable();
|
||||||
|
formSel.disabled=true; formTS.disable(); formTS.clear(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量切换
|
||||||
|
document.getElementById('allFormBtn').addEventListener('click', ()=>{
|
||||||
|
document.querySelectorAll('input[id^="src-form-"]').forEach(r=>{ r.checked=true; r.dispatchEvent(new Event('change')); });
|
||||||
|
});
|
||||||
|
document.getElementById('allCsvBtn').addEventListener('click', ()=>{
|
||||||
|
document.querySelectorAll('input[id^="src-csv-"]').forEach(r=>{ r.checked=true; r.dispatchEvent(new Event('change')); });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 根指标选择(下拉)
|
||||||
|
document.getElementById('rootSelect').addEventListener('change', (e)=>{
|
||||||
|
renderTable(e.target.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始
|
||||||
|
renderTable('quality');
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -73,6 +73,7 @@ public class DataController extends BaseController {
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
@Operation(summary = "导航到数据管理页面", description = "导航到数据管理页面")
|
@Operation(summary = "导航到数据管理页面", description = "导航到数据管理页面")
|
||||||
public String index(PaginationBean request, Model model) {
|
public String index(PaginationBean request, Model model) {
|
||||||
|
setNavigateTitle(model, "/data/list");
|
||||||
List<ModelDefine> modelDefineList = modelDefineService.list(); //查询所有数据模型列表
|
List<ModelDefine> modelDefineList = modelDefineService.list(); //查询所有数据模型列表
|
||||||
modelDefineList.sort(Comparator.comparing(ModelDefine::getSortOrder)); //对模型数据列表排序
|
modelDefineList.sort(Comparator.comparing(ModelDefine::getSortOrder)); //对模型数据列表排序
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,35 @@
|
||||||
package com.hshh.indicator.controller;
|
package com.hshh.indicator.controller;
|
||||||
|
|
||||||
import com.hshh.indicator.entity.Indicator;
|
import com.hshh.indicator.entity.Indicator;
|
||||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
import com.hshh.indicator.entity.IndicatorBottomCsvMapper;
|
||||||
import com.hshh.indicator.service.IndicatorEvalItemService;
|
import com.hshh.indicator.entity.IndicatorBottomFormMapper;
|
||||||
|
import com.hshh.indicator.entity.IndicatorCsv;
|
||||||
|
import com.hshh.indicator.entity.IndicatorFormMapper;
|
||||||
|
import com.hshh.indicator.service.IndicatorBottomCsvMapperService;
|
||||||
|
import com.hshh.indicator.service.IndicatorBottomFormMapperService;
|
||||||
|
import com.hshh.indicator.service.IndicatorCsvColumnService;
|
||||||
|
import com.hshh.indicator.service.IndicatorCsvService;
|
||||||
|
import com.hshh.indicator.service.IndicatorFromMapperService;
|
||||||
import com.hshh.indicator.service.IndicatorService;
|
import com.hshh.indicator.service.IndicatorService;
|
||||||
|
import com.hshh.model.entity.FormFieldConfig;
|
||||||
import com.hshh.model.entity.ModelDefine;
|
import com.hshh.model.entity.ModelDefine;
|
||||||
|
import com.hshh.model.service.FormFieldConfigService;
|
||||||
import com.hshh.model.service.ModelDefineService;
|
import com.hshh.model.service.ModelDefineService;
|
||||||
import com.hshh.system.common.bean.BaseController;
|
import com.hshh.system.common.bean.BaseController;
|
||||||
|
import com.hshh.system.common.bean.CheckedBean;
|
||||||
import com.hshh.system.common.bean.OperateResult;
|
import com.hshh.system.common.bean.OperateResult;
|
||||||
import com.hshh.system.common.enums.ErrorCode;
|
import com.hshh.system.common.enums.ErrorCode;
|
||||||
import com.hshh.system.common.enums.ErrorMessage;
|
import com.hshh.system.common.enums.ErrorMessage;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
|
@ -23,7 +39,9 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指标接口服务接口.
|
* 指标接口服务接口.
|
||||||
|
|
@ -37,20 +55,46 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
public class IndicatorController extends BaseController {
|
public class IndicatorController extends BaseController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指标服务类.
|
* 指标服务类. 查询所有指标列表
|
||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private IndicatorService indicatorService;
|
private IndicatorService indicatorService;
|
||||||
/**
|
/**
|
||||||
* 模型定义服务类.
|
* 模型定义服务类. 查询所有表单
|
||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private ModelDefineService modelDefineService;
|
private ModelDefineService modelDefineService;
|
||||||
/**
|
/**
|
||||||
* 评价集服务类.
|
* 顶级指标对应的form和csv记录服务.
|
||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private IndicatorEvalItemService indicatorEvalItemService;
|
private IndicatorFromMapperService indicatorTopMapperService;
|
||||||
|
/**
|
||||||
|
* 表单中字段服务类.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private FormFieldConfigService formFieldConfigService;
|
||||||
|
/**
|
||||||
|
* 顶级指标和csv的对应服务类.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IndicatorCsvService indicatorCsvService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指标csv列服务.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IndicatorCsvColumnService indicatorCsvColumnService;
|
||||||
|
/**
|
||||||
|
* 底部指标和表单的的对应服务类.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IndicatorBottomFormMapperService bottomFormMapperService;
|
||||||
|
/**
|
||||||
|
* 底部指标和csv的对应关系.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private IndicatorBottomCsvMapperService bottomCsvMapperService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导航到列表页面. 获取所有的root指标,显示到页面左侧.
|
* 导航到列表页面. 获取所有的root指标,显示到页面左侧.
|
||||||
|
|
@ -61,6 +105,7 @@ public class IndicatorController extends BaseController {
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/list")
|
@RequestMapping("/list")
|
||||||
public String list(Model model, Indicator indicator) {
|
public String list(Model model, Indicator indicator) {
|
||||||
|
setNavigateTitle(model, "/indicator/list");
|
||||||
List<Indicator> rootList = indicatorService.queryRootList();
|
List<Indicator> rootList = indicatorService.queryRootList();
|
||||||
if (rootList != null && !rootList.isEmpty()) {
|
if (rootList != null && !rootList.isEmpty()) {
|
||||||
if (indicator.getId() != null) {
|
if (indicator.getId() != null) {
|
||||||
|
|
@ -179,6 +224,7 @@ public class IndicatorController extends BaseController {
|
||||||
*/
|
*/
|
||||||
@GetMapping("/evaluationList")
|
@GetMapping("/evaluationList")
|
||||||
public String evaluationList(Integer topIndicatorId, Integer indicatorId, Model model) {
|
public String evaluationList(Integer topIndicatorId, Integer indicatorId, Model model) {
|
||||||
|
setNavigateTitle(model, "/indicator/evaluationList");
|
||||||
List<Indicator> rootList = indicatorService.queryRootList();
|
List<Indicator> rootList = indicatorService.queryRootList();
|
||||||
if (rootList != null && !rootList.isEmpty()) {
|
if (rootList != null && !rootList.isEmpty()) {
|
||||||
if (topIndicatorId != null) {
|
if (topIndicatorId != null) {
|
||||||
|
|
@ -227,16 +273,142 @@ public class IndicatorController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存评价集.
|
* 导航到mapper页面. 1. 顶级指标放入session . 2. 底层指标放入session容器. 3. form表单字段放入session容器 .
|
||||||
|
* 4.form表单列表放入session容器 5. csv对应session容器 6. csv字段session容器 7. 底部指标对应form字段session容器 8.
|
||||||
|
* 底部指标对应csv列session容器.
|
||||||
*
|
*
|
||||||
* @param item
|
* @param model session容器
|
||||||
* @param bindingResult
|
* @param formId 表单ID
|
||||||
* @return
|
* @param csvId csvID
|
||||||
|
* @param indicatorTopId 指标顶级ID
|
||||||
|
* @return /indicator/mapper.html
|
||||||
*/
|
*/
|
||||||
// @PostMapping("/evalItem/save")
|
|
||||||
// @ResponseBody
|
@GetMapping("/mapper")
|
||||||
// public OperateResult<IndicatorEvalItem> saveEval(@Valid @RequestBody IndicatorEvalItem item,
|
public String mapper(Model model, final Integer indicatorTopId, final Integer formId,
|
||||||
// BindingResult bindingResult) {
|
final Integer csvId) {
|
||||||
//
|
|
||||||
// }
|
setNavigateTitle(model, "/indicator/mapper"); //设置导航
|
||||||
|
|
||||||
|
List<Indicator> rootList = indicatorService.queryRootList(); //查询所有根指标
|
||||||
|
setChecked(rootList, indicatorTopId); //设置根指标的选中状态
|
||||||
|
model.addAttribute("rootList", rootList); // 1. 顶级指标放入session容器
|
||||||
|
model.addAttribute("childrenIndicator",
|
||||||
|
indicatorService.selectNoChildByTopId(indicatorTopId)); // 2. 底层指标放入session容器
|
||||||
|
//处理form表单
|
||||||
|
modelForm(model, indicatorTopId, formId); // 3. form表单字段放入session容器.4.form表单列表放入session容器
|
||||||
|
//处理csv file
|
||||||
|
csvFile(model, indicatorTopId); // 5. csv对应session容器 6. csv字段session容器
|
||||||
|
|
||||||
|
//放入底部指标和form表单字段对应关系到容器
|
||||||
|
List<IndicatorBottomFormMapper> bottomList = bottomFormMapperService.queryListByIndicatorId(
|
||||||
|
indicatorTopId);
|
||||||
|
Map<Integer, IndicatorBottomFormMapper> bottomFormMap = bottomList.stream()
|
||||||
|
.collect(Collectors.toMap(IndicatorBottomFormMapper::getFormFieldId, a -> a));
|
||||||
|
model.addAttribute("bottomFormMap", bottomFormMap); // 7. 底部指标对应form字段session容器
|
||||||
|
|
||||||
|
//放入底部指标和csv列对应关系到容器
|
||||||
|
List<IndicatorBottomCsvMapper> bottomCsvColumnList = bottomCsvMapperService.queryListByIndicatorTopId(
|
||||||
|
indicatorTopId);
|
||||||
|
Map<Integer, IndicatorBottomCsvMapper> bottomCsvColumnMap = bottomCsvColumnList.stream()
|
||||||
|
.collect(Collectors.toMap(IndicatorBottomCsvMapper::getCsvColumnId, a -> a));
|
||||||
|
model.addAttribute("bottomCsvColumnMap", bottomCsvColumnMap); // 8.底部指标对应csv列session容器
|
||||||
|
|
||||||
|
return "/indicator/mapper";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void modelForm(Model model, final Integer indicatorTopId, Integer formId) {
|
||||||
|
//表单相关
|
||||||
|
List<IndicatorFormMapper> mapperList = indicatorTopMapperService.selectModelAndCsvNameByIndicator(
|
||||||
|
indicatorTopId); //查看form和顶指标映射关系
|
||||||
|
//查询form表单字段
|
||||||
|
if (formId != null) {
|
||||||
|
|
||||||
|
model.addAttribute("formFieldList",
|
||||||
|
formFieldConfigService.getFormFieldConfigByModelId(formId));//3.form表单字段放入session容器
|
||||||
|
} else if (!mapperList.isEmpty()) {
|
||||||
|
List<FormFieldConfig> formFieldList = formFieldConfigService.getFormFieldConfigByModelId(
|
||||||
|
mapperList.get(0).getIndicatorModelId());
|
||||||
|
model.addAttribute("formFieldList", formFieldList); //3.form表单字段放入session容器
|
||||||
|
}
|
||||||
|
List<ModelDefine> modelList = modelDefineService.list(); //查询所有form表单列表
|
||||||
|
setChecked(modelList, mapperList.isEmpty() ? null
|
||||||
|
: (formId != null ? formId : mapperList.get(0).getIndicatorModelId())); //设置form表单列表的选中状态
|
||||||
|
model.addAttribute("modelList", modelList); //4.所有form表单放入session容器
|
||||||
|
}
|
||||||
|
|
||||||
|
private void csvFile(Model model, final Integer id) {
|
||||||
|
IndicatorCsv csvMapper = indicatorCsvService.selectByIndicatorId(id); //5.csv对应放入session
|
||||||
|
model.addAttribute("csvMapper", csvMapper);
|
||||||
|
//查询csv列的列表
|
||||||
|
model.addAttribute("csvColumns",
|
||||||
|
indicatorCsvColumnService.listByIdOrderByColumn(csvMapper == null ? 0 : csvMapper.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载上一次的csv模板.
|
||||||
|
*
|
||||||
|
* @param id csv映射ID
|
||||||
|
* @param response 响应
|
||||||
|
* @throws IOException 异常
|
||||||
|
*/
|
||||||
|
@GetMapping("/download/{id}")
|
||||||
|
public void downloadFile(@PathVariable Integer id, HttpServletResponse response)
|
||||||
|
throws IOException {
|
||||||
|
IndicatorCsv csvFile = indicatorCsvService.getById(id);
|
||||||
|
|
||||||
|
// 设置响应头
|
||||||
|
response.setContentType("text/csv; charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition",
|
||||||
|
"attachment; filename=\"" + java.net.URLEncoder.encode(csvFile.getCsvName(),
|
||||||
|
StandardCharsets.UTF_8) + "\"");
|
||||||
|
|
||||||
|
// 写入文件流
|
||||||
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
os.write(csvFile.getCsvData());
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传csv文件.记录顶级指标和文件及表单id的映射关系,记录在表m_data_indicator_top_mapper.
|
||||||
|
*
|
||||||
|
* @param file 文件
|
||||||
|
* @param indicatorTopId 指标
|
||||||
|
* @param formId modelID
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/uploadCsvAndSetTopMapper")
|
||||||
|
public OperateResult<Void> uploadCsvAndSetTopMapper(@RequestParam("file") MultipartFile file,
|
||||||
|
Integer indicatorTopId, Integer formId) {
|
||||||
|
indicatorService.saveIndicatorTopCsvMapper(indicatorTopId, formId, file);
|
||||||
|
return OperateResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存指标和form表单ID的映射关系.
|
||||||
|
*
|
||||||
|
* @param indicatorTopId 指标顶级ID
|
||||||
|
* @param formId 表单ID
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/indicatorFormMapper")
|
||||||
|
public OperateResult<Void> saveIndicatorFormMapper(Integer indicatorTopId, Integer formId) {
|
||||||
|
indicatorTopMapperService.saveFormMapper(indicatorTopId, formId);
|
||||||
|
return OperateResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends CheckedBean> void setChecked(List<T> list, Integer id) {
|
||||||
|
if (list != null && !list.isEmpty()) {
|
||||||
|
if (id == null || id.equals(0)) {
|
||||||
|
list.get(0).setChecked(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (T bean : list) {
|
||||||
|
if (bean.getId().equals(id)) {
|
||||||
|
bean.setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package com.hshh.indicator.controller;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 指标规则表 前端控制器
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author liDongYu
|
|
||||||
* @since 2025-08-04
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
@RequestMapping("/indicator/indicatorEvalItem")
|
|
||||||
public class IndicatorEvalItemController {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.hshh.system.common.bean.CheckedBean;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
@ -20,7 +21,7 @@ import lombok.Data;
|
||||||
*/
|
*/
|
||||||
@TableName("m_data_indicator")
|
@TableName("m_data_indicator")
|
||||||
@Data
|
@Data
|
||||||
public class Indicator implements Serializable {
|
public class Indicator extends CheckedBean {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
@ -39,9 +40,8 @@ public class Indicator implements Serializable {
|
||||||
|
|
||||||
private Integer topId; //顶级父ID
|
private Integer topId; //顶级父ID
|
||||||
private Integer sortOrder;
|
private Integer sortOrder;
|
||||||
@TableField(exist = false)
|
|
||||||
private boolean checked;
|
|
||||||
private Integer modelId;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.hshh.indicator.service;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.hshh.indicator.entity.Indicator;
|
import com.hshh.indicator.entity.Indicator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指标表 服务类.
|
* 指标表 服务类.
|
||||||
|
|
@ -53,4 +54,13 @@ public interface IndicatorService extends IService<Indicator> {
|
||||||
* @return 指标集
|
* @return 指标集
|
||||||
*/
|
*/
|
||||||
List<Indicator> selectNoChildByTopId(Integer topId);
|
List<Indicator> selectNoChildByTopId(Integer topId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存顶级映射关系;记录对应的表单ID和csv信息.
|
||||||
|
*
|
||||||
|
* @param topId 顶级指标ID
|
||||||
|
* @param modelId 表单ID
|
||||||
|
* @param file csv文件
|
||||||
|
*/
|
||||||
|
void saveIndicatorTopCsvMapper(Integer topId, Integer modelId, MultipartFile file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|
@ -82,4 +84,19 @@ public class IndicatorServiceImpl extends ServiceImpl<IndicatorMapper, Indicator
|
||||||
public List<Indicator> selectNoChildByTopId(Integer topId) {
|
public List<Indicator> selectNoChildByTopId(Integer topId) {
|
||||||
return this.baseMapper.selectNoChildByTopId(topId);
|
return this.baseMapper.selectNoChildByTopId(topId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void saveIndicatorTopCsvMapper(Integer topId, Integer modelId, MultipartFile file) {
|
||||||
|
//删除表中m_data_indicator_csv原来topID对应记录
|
||||||
|
|
||||||
|
|
||||||
|
//添加m_data_indicator_csv记录
|
||||||
|
|
||||||
|
//删除m_data_indicator_csv_column 原topID对应的记录
|
||||||
|
|
||||||
|
|
||||||
|
//添加对应记录
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package com.hshh.model.controller;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 动态表单实际对象记录表 前端控制器
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author liDongYu
|
|
||||||
* @since 2025-08-01
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
@RequestMapping("/model/formValue")
|
|
||||||
public class FormValueController {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -82,6 +82,7 @@ public class ModelDefineController extends BaseController {
|
||||||
@Operation(summary = "导航到数据模型定义页面", description = "导航到数据模型定义页面")
|
@Operation(summary = "导航到数据模型定义页面", description = "导航到数据模型定义页面")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public String list(ModelDefine modelDefine, Model model) {
|
public String list(ModelDefine modelDefine, Model model) {
|
||||||
|
setNavigateTitle(model, "/model/list");
|
||||||
List<ModelDefine> modelList = modelDefineService.list();
|
List<ModelDefine> modelList = modelDefineService.list();
|
||||||
List<FormFieldConfig> fieldList = new ArrayList<>();
|
List<FormFieldConfig> fieldList = new ArrayList<>();
|
||||||
if (modelList != null) {
|
if (modelList != null) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.hshh.system.common.bean.CheckedBean;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.Pattern;
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
@ -20,7 +21,7 @@ import lombok.Data;
|
||||||
*/
|
*/
|
||||||
@TableName("m_data_model_define")
|
@TableName("m_data_model_define")
|
||||||
@Data
|
@Data
|
||||||
public class ModelDefine implements Serializable {
|
public class ModelDefine extends CheckedBean {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
@ -37,8 +38,7 @@ public class ModelDefine implements Serializable {
|
||||||
private String modelName;
|
private String modelName;
|
||||||
|
|
||||||
|
|
||||||
@TableField(exist = false)
|
|
||||||
private boolean checked;
|
|
||||||
private Integer sortOrder;
|
private Integer sortOrder;
|
||||||
/**
|
/**
|
||||||
* 每行显示几个字段.
|
* 每行显示几个字段.
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ public class FormFieldConfigServiceImpl extends
|
||||||
public List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId) {
|
public List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId) {
|
||||||
QueryWrapper<FormFieldConfig> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<FormFieldConfig> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("data_model_id", modelId);
|
queryWrapper.eq("data_model_id", modelId);
|
||||||
|
queryWrapper.orderByAsc("sort_order");
|
||||||
return this.list(queryWrapper);
|
return this.list(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">数据管理</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|
|
||||||
|
|
@ -184,4 +184,16 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div th:fragment="navigateDialog(naviList)" id="navigateDialog">
|
||||||
|
<!-- 面包屑导航 -->
|
||||||
|
<nav aria-label="breadcrumb" class="mb-4">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
|
||||||
|
<li class="breadcrumb-item" th:each="m:${naviList}">
|
||||||
|
<a href="#" th:text="${m.title}">系统管理</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,7 @@
|
||||||
<input type="hidden" name="parentId" id="parentId" >
|
<input type="hidden" name="parentId" id="parentId" >
|
||||||
<input type="hidden" name="topId" id="topId" >
|
<input type="hidden" name="topId" id="topId" >
|
||||||
|
|
||||||
<div class="mb-3" th:if="${modelDefineList != null}">
|
|
||||||
<label class="form-label required">基础设施:</label>
|
|
||||||
<select class="form-select" name="modelId" id="modelId" >
|
|
||||||
<option th:each="item:${modelDefineList}" th:value="${item.id}" th:text="${item.getModelName()}"></option>
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback" id="modelId_error_tip"></div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label required">指标名称:</label>
|
<label class="form-label required">指标名称:</label>
|
||||||
<input type="text" class="form-control" name="name" id="name"
|
<input type="text" class="form-control" name="name" id="name"
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,7 @@
|
||||||
</style>
|
</style>
|
||||||
<div class="page-body" data-page="metric">
|
<div class="page-body" data-page="metric">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">指标管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">评价集</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row row-cards">
|
<div class="row row-cards">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|
@ -35,13 +28,16 @@
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 新增:上次上传文件 -->
|
||||||
|
<div class="text-muted small mt-2">说明: 切换不同的指标可以设置当前指标子项的评价标准</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">指标子集</h3>
|
<h3 class="card-title" th:each="item : ${rootList}"
|
||||||
|
th:if="${item.checked == true}">[[${item.name}]]子集</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group list-group-flush overflow-auto" style="max-height: 35rem">
|
<div class="list-group list-group-flush overflow-auto" style="max-height: 35rem">
|
||||||
<div class="list-group-item" th:each="item:${indicatorListWithoutChildren}">
|
<div class="list-group-item" th:each="item:${indicatorListWithoutChildren}">
|
||||||
|
|
|
||||||
|
|
@ -128,14 +128,7 @@
|
||||||
|
|
||||||
<div class="page-body" data-page="metric">
|
<div class="page-body" data-page="metric">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">指标管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">指标数据</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-0 mb-4">
|
<div class="row g-0 mb-4">
|
||||||
<div class="col-md-3" style="min-height: 40em">
|
<div class="col-md-3" style="min-height: 40em">
|
||||||
<div class="card mb-4">
|
<div class="card mb-4">
|
||||||
|
|
|
||||||
246
manager-admin/src/main/resources/templates/indicator/mapper.html
Normal file
246
manager-admin/src/main/resources/templates/indicator/mapper.html
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
<!-- ====== 页面主体(纯静态,无 JS/Thymeleaf) ====== -->
|
||||||
|
<div class="page-body" data-page="mapper">
|
||||||
|
<div class="container-xl">
|
||||||
|
|
||||||
|
<!-- 面包屑(静态示例) -->
|
||||||
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
|
|
||||||
|
<div class="row row-cards">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">指标数据映射集设置</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<a href="#" class="btn btn-primary">
|
||||||
|
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24"
|
||||||
|
viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M12 5l0 14"></path>
|
||||||
|
<path d="M5 12l14 0"></path>
|
||||||
|
</svg>
|
||||||
|
保存映射关系
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<!-- 1. 根指标(静态下拉) -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">1. 选择指标(根指标)</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<label for="indicationId" class="form-label m-0">根指标</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<select id="indicationId" class="form-select" name="indicationId">
|
||||||
|
<option value="0">-选择根指标-</option>
|
||||||
|
<option th:each="item:${rootList}" th:value="${item.id}"
|
||||||
|
th:text="${item.getName()}" th:selected="${item.checked}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 1. 根指标(静态下拉) -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">2. 选择form表单</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<label for="modelId" class="form-label m-0">form名称</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<select id="modelId" class="form-select" onchange="formModelChange(this)">
|
||||||
|
<option value="0">-选择form表单-</option>
|
||||||
|
<option th:each="item:${modelList}" th:value="${item.id}"
|
||||||
|
th:text="${item.getModelName()}" th:selected="${item.checked}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. CSV 表头(静态 50 列) -->
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">3. 上传 CSV 文件</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<input type="file" class="form-control mb-3" accept=".csv">
|
||||||
|
<!-- 新增:上次上传文件 -->
|
||||||
|
<div class="mb-2" th:if="${csvMapper!=null}">
|
||||||
|
<span class="fw-bold">上次上传文件:</span>
|
||||||
|
<a th:href="@{/indicator/download/{id}(id=${csvMapper.getId()})" target="_blank"
|
||||||
|
th:text="${csvMapper.getCsvName()}"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. 子指标映射(静态 20 行;首两列粘左;自动编号) -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">4. 子指标映射设置</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="map-scroller">
|
||||||
|
<table class="table table-vcenter table-striped table-hover align-middle map-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sticky-header sticky-col-1" style="width:48px;">#</th>
|
||||||
|
<th class="sticky-header sticky-col-2" style="width:200px;">子指标名称</th>
|
||||||
|
|
||||||
|
<th class="sticky-header" style="width:320px;">表单字段</th>
|
||||||
|
<th class="sticky-header" style="width:320px;">CSV 表头</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<!-- 自动编号 tbody(不用写数字,CSS 计数器会生成 1..20) -->
|
||||||
|
<tbody class="autonum">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 02~20:同上复制即可(编号与名称尾号自动增长) -->
|
||||||
|
<tr th:each="item:${childrenIndicator}">
|
||||||
|
<td class="sticky-body-col-1 col-index"></td>
|
||||||
|
<td class="sticky-body-col-2 col-name" th:text="${item.getName()}"></td>
|
||||||
|
|
||||||
|
<td><select class="form-select form-select-sm">
|
||||||
|
<option>— 选择表单字段 —</option>
|
||||||
|
<option th:if="${formFieldList.size()>0}"
|
||||||
|
th:each="field:${formFieldList}" th:value="${field.id}"
|
||||||
|
th:text="${field.getFieldName()}"></option>
|
||||||
|
>
|
||||||
|
</option>
|
||||||
|
|
||||||
|
</select></td>
|
||||||
|
<td><select class="form-select form-select-sm">
|
||||||
|
<option>— 选择 CSV 表头 —</option>
|
||||||
|
<option th:if="${csvColumns.size()>0}" th:each="column:${csvColumns}"
|
||||||
|
th:value="${column.id}"
|
||||||
|
th:text="${column.getCsvColumnName()}"></option>
|
||||||
|
>
|
||||||
|
|
||||||
|
</option>
|
||||||
|
|
||||||
|
</select></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small mt-2">说明:选择子指标,对应表单字段或者CSV某列</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- /card-body -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ====== 样式(关键:表头与表体分层;首两列分别粘左) ====== -->
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--col-index-w: 48px; /* 首列宽度(与 th/td 一致) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSV 预览区域 */
|
||||||
|
.csv-heads {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动容器 */
|
||||||
|
.map-scroller {
|
||||||
|
max-height: 65vh;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: .5rem;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格与单元格 */
|
||||||
|
.map-table {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: max-content;
|
||||||
|
min-width: 1200px;
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-table th, .map-table td {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding-top: .55rem;
|
||||||
|
padding-bottom: .55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 表头:粘顶 + 粘左(前两列) —— 层级最高 ===== */
|
||||||
|
.sticky-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
box-shadow: 0 2px 0 rgba(0, 0, 0, .04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-header.sticky-col-1 {
|
||||||
|
left: 0;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-header.sticky-col-2 {
|
||||||
|
left: var(--col-index-w);
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 表体:粘左(前两列) —— 层级低于表头 ===== */
|
||||||
|
.sticky-body-col-1 {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
z-index: 4;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-body-col-2 {
|
||||||
|
position: sticky;
|
||||||
|
left: var(--col-index-w);
|
||||||
|
z-index: 4;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 2px 0 0 rgba(0, 0, 0, .06); /* 分隔线效果 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自动编号:tbody 开始计数,tr 自增;序号/名称自动输出数值 */
|
||||||
|
.autonum {
|
||||||
|
counter-reset: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autonum tr {
|
||||||
|
counter-increment: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autonum .col-index::before {
|
||||||
|
content: counter(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
.autonum .col-name::after {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function formModelChange(object) {
|
||||||
|
document.getElementById("_indicator_mapper").setAttribute("hx-vals",
|
||||||
|
JSON.stringify({indicatorTopId: $('#indicationId').val(), formId: object.value}))
|
||||||
|
document.getElementById("_indicator_mapper").click();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">基础设施</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<!-- 左侧字典类型 -->
|
<!-- 左侧字典类型 -->
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">系统管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">字典管理</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<!-- 左侧字典类型 -->
|
<!-- 左侧字典类型 -->
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl" data-page="menu-list">
|
<div class="container-xl" data-page="menu-list">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">系统管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">菜单管理</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">系统管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">权限管理</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">系统管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">角色管理</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<nav aria-label="breadcrumb" class="mb-4">
|
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="#">系统管理</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item"><a href="#">用户管理</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import java.util.List;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
|
@ -46,6 +47,7 @@ public class DictItemController extends BaseController {
|
||||||
@Operation(summary = "获取字典条目增加页面内容", description = "用户点击新增字典条目时执行")
|
@Operation(summary = "获取字典条目增加页面内容", description = "用户点击新增字典条目时执行")
|
||||||
@GetMapping("/add")
|
@GetMapping("/add")
|
||||||
public String add() {
|
public String add() {
|
||||||
|
|
||||||
return "system/dict/add_dict_item";
|
return "system/dict/add_dict_item";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,9 @@ public class DictTypeController extends BaseController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@Operation(summary = "导航到列表页面", description = "用户点击菜单时,执行")
|
@Operation(summary = "导航到列表页面", description = "用户点击菜单时,执行")
|
||||||
public String index(Model model, DictType type) {
|
public String index(Model model, DictType type) {
|
||||||
|
|
||||||
|
setNavigateTitle(model, "/base/dict/");
|
||||||
|
|
||||||
List<DictType> dictList = dictTypeService.list();
|
List<DictType> dictList = dictTypeService.list();
|
||||||
dictList.sort(Comparator.comparingInt(DictType::getSortOrder));
|
dictList.sort(Comparator.comparingInt(DictType::getSortOrder));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import javax.validation.Valid;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
|
@ -53,7 +54,9 @@ public class MenuController extends BaseController {
|
||||||
*/
|
*/
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@Operation(summary = "菜单首页", description = "导航到默认页")
|
@Operation(summary = "菜单首页", description = "导航到默认页")
|
||||||
public String list() {
|
public String list(Model model) {
|
||||||
|
setNavigateTitle(model, "/base/menu/");
|
||||||
|
|
||||||
return "system/menu/list";
|
return "system/menu/list";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ public class PermissionController extends BaseController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@Operation(summary = "权限首页", description = "导航到默认页")
|
@Operation(summary = "权限首页", description = "导航到默认页")
|
||||||
public String list(PaginationBean request, Model model) {
|
public String list(PaginationBean request, Model model) {
|
||||||
|
setNavigateTitle(model, "/base/permission/");
|
||||||
List<Permissions> list = permissionsService.list(request);
|
List<Permissions> list = permissionsService.list(request);
|
||||||
Long total = permissionsService.count(request);
|
Long total = permissionsService.count(request);
|
||||||
//设置分页信息
|
//设置分页信息
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ public class RoleController extends BaseController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@Operation(summary = "角色首页", description = "导航到默认页")
|
@Operation(summary = "角色首页", description = "导航到默认页")
|
||||||
public String list(PaginationBean request, Model model) {
|
public String list(PaginationBean request, Model model) {
|
||||||
|
setNavigateTitle(model, "/base/role/");
|
||||||
List<Roles> list = rolesService.list(request);
|
List<Roles> list = rolesService.list(request);
|
||||||
Long total = rolesService.count(request);
|
Long total = rolesService.count(request);
|
||||||
//设置分页信息
|
//设置分页信息
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package com.hshh.system.base.controller;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 前端控制器
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author liDongYu
|
|
||||||
* @since 2025-07-29
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
@RequestMapping("/base/tableRelations")
|
|
||||||
public class TableRelationsController {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -66,6 +66,7 @@ public class UserController extends BaseController {
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@Operation(summary = "用户首页", description = "导航到默认页")
|
@Operation(summary = "用户首页", description = "导航到默认页")
|
||||||
public String list(PaginationBean request, Model model) {
|
public String list(PaginationBean request, Model model) {
|
||||||
|
setNavigateTitle(model, "/base/user/");
|
||||||
List<Users> list = usersService.list(request);
|
List<Users> list = usersService.list(request);
|
||||||
Long total = usersService.count(request);
|
Long total = usersService.count(request);
|
||||||
//设置分页信息
|
//设置分页信息
|
||||||
|
|
|
||||||
|
|
@ -42,4 +42,12 @@ public interface MenusService extends IService<Menus> {
|
||||||
* @return 菜单列表
|
* @return 菜单列表
|
||||||
*/
|
*/
|
||||||
List<Menus> queryListByPid(Integer parentId);
|
List<Menus> queryListByPid(Integer parentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据菜单地址获取菜单对象. 比如,菜单A,父亲时B,B的父亲是C.则返回列表 C,B,A.
|
||||||
|
*
|
||||||
|
* @param href 菜单连接地址
|
||||||
|
* @return 菜单对象列表;从父-父...-孩子
|
||||||
|
*/
|
||||||
|
List<Menus> getMenus(String href);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.hshh.system.base.entity.Menus;
|
||||||
import com.hshh.system.base.mapper.MenusMapper;
|
import com.hshh.system.base.mapper.MenusMapper;
|
||||||
import com.hshh.system.base.service.MenusService;
|
import com.hshh.system.base.service.MenusService;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -125,4 +126,38 @@ public class MenusServiceImpl extends ServiceImpl<MenusMapper, Menus> implements
|
||||||
queryWrapper.eq("parent_id", parentId);
|
queryWrapper.eq("parent_id", parentId);
|
||||||
return this.list(queryWrapper);
|
return this.list(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Menus> getMenus(String href) {
|
||||||
|
List<Menus> resultList = new ArrayList<>();
|
||||||
|
List<Menus> menuList = this.list();
|
||||||
|
menuList.forEach(a -> {
|
||||||
|
if (a.getParentId() == null) {
|
||||||
|
a.setParentId(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//用key=path
|
||||||
|
Map<String, Menus> keyIsPathMenusMap = menuList.stream().filter(a -> a.getPath() != null)
|
||||||
|
.collect(Collectors.toMap(Menus::getPath, a -> a));
|
||||||
|
Menus menus = keyIsPathMenusMap.get(href);
|
||||||
|
if (menus == null) {
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
resultList.add(menus);
|
||||||
|
//key=id
|
||||||
|
Map<Integer, Menus> idMap = menuList.stream()
|
||||||
|
.collect(Collectors.toMap(Menus::getId, a -> a));
|
||||||
|
addParent(resultList, menus.getParentId(), idMap);
|
||||||
|
//反转
|
||||||
|
Collections.reverse(resultList);
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addParent(List<Menus> resultList, Integer parentId, Map<Integer, Menus> allMenuMap) {
|
||||||
|
if (parentId != null && allMenuMap.get(parentId) != null) {
|
||||||
|
resultList.add(allMenuMap.get(parentId));
|
||||||
|
addParent(resultList, allMenuMap.get(parentId).getParentId(), allMenuMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页基础参数
|
* 分页基础参数.
|
||||||
*/
|
*/
|
||||||
public class BaseBean implements Serializable {
|
public class BaseBean implements Serializable {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.hshh.system.common.bean;
|
package com.hshh.system.common.bean;
|
||||||
|
|
||||||
|
|
||||||
|
import com.hshh.system.base.entity.Menus;
|
||||||
|
import com.hshh.system.base.service.impl.MenusServiceImpl;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
|
@ -45,4 +47,15 @@ public class BaseController {
|
||||||
model.addAttribute("condition", request);
|
model.addAttribute("condition", request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置页面上的导航信息.
|
||||||
|
*
|
||||||
|
* @param model session容器.
|
||||||
|
* @param href 页面地址
|
||||||
|
*/
|
||||||
|
protected void setNavigateTitle(Model model, String href) {
|
||||||
|
MenusServiceImpl menuService = SpringContextHolder.getBean(MenusServiceImpl.class);
|
||||||
|
List<Menus> menuList = menuService.getMenus(href);
|
||||||
|
model.addAttribute("chainMenuList", menuList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.hshh.system.common.bean;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记checked.
|
||||||
|
*
|
||||||
|
* @author LiDongYU
|
||||||
|
* @since 2025/7/22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CheckedBean {
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private boolean checked;
|
||||||
|
private Integer id;
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ public class CodeGenerator {
|
||||||
basePath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
|
basePath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
|
||||||
})
|
})
|
||||||
.strategyConfig(builder -> {
|
.strategyConfig(builder -> {
|
||||||
builder.addInclude("m_data_indicator_eval_item") // 设置需要生成的表名(多个用逗号分隔)
|
builder.addInclude("m_data_indicator_bottom_csv_mapper") // 设置需要生成的表名(多个用逗号分隔)
|
||||||
.addTablePrefix("m_data_"); // 设置过滤表前缀
|
.addTablePrefix("m_data_"); // 设置过滤表前缀
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user