1. 指标子集映射
This commit is contained in:
parent
e2d86ae384
commit
ba1a3bcae4
|
|
@ -25,6 +25,11 @@
|
|||
<artifactId>system</artifactId>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,206 +1,670 @@
|
|||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<!--
|
||||
* Tabler - Premium and Open Source dashboard template with responsive and high quality UI.
|
||||
* @version 1.0.0-beta19
|
||||
* @link https://tabler.io
|
||||
* Copyright 2018-2023 The Tabler Authors
|
||||
* Copyright 2018-2023 codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>指标设置 Demo</title>
|
||||
|
||||
<!-- Tabler 样式(也可换成你项目内置的 tabler.min.css) -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css"/>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||
<title>Logs - Tabler - Premium and Open Source dashboard template with responsive and high quality UI.</title>
|
||||
<!-- CSS files -->
|
||||
<link href="./dist/css/tabler.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./dist/css/tabler-flags.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./dist/css/tabler-payments.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./dist/css/tabler-vendors.min.css?1684106062" rel="stylesheet"/>
|
||||
<link href="./dist/css/demo.min.css?1684106062" rel="stylesheet"/>
|
||||
<style>
|
||||
:root{
|
||||
/* 你的主题主色,可按项目实际调整 */
|
||||
--accent: #206bc4;
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
:root {
|
||||
--tblr-font-sans-serif: 'Inter Var', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
/* 强调卡片 */
|
||||
.card-priority{
|
||||
border: 2px solid var(--accent);
|
||||
box-shadow: 0 10px 30px rgba(32,107,196,.16);
|
||||
background: linear-gradient(180deg, rgba(32,107,196,.04), rgba(32,107,196,.02));
|
||||
position: sticky; /* 吸顶 */
|
||||
top: 12px;
|
||||
z-index: 3;
|
||||
transition: box-shadow .18s ease, transform .18s ease;
|
||||
}
|
||||
.card-priority .card-header{
|
||||
background: linear-gradient(90deg, rgba(32,107,196,.10), rgba(32,107,196,0));
|
||||
border-bottom: 1px solid rgba(32,107,196,.2);
|
||||
}
|
||||
.priority-dot{
|
||||
width: 10px; height: 10px; border-radius: 999px;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 0 4px rgba(32,107,196,.15);
|
||||
margin-right: .5rem;
|
||||
}
|
||||
.card-priority:hover,
|
||||
.card-priority:focus-within{
|
||||
box-shadow: 0 14px 40px rgba(32,107,196,.24);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 切换时的短暂高亮 */
|
||||
@keyframes flashHighlight{
|
||||
0% { box-shadow: 0 0 0 0 rgba(32,107,196,0); }
|
||||
20% { box-shadow: 0 0 0 6px rgba(32,107,196,.25); }
|
||||
100% { box-shadow: 0 10px 30px rgba(32,107,196,.16); }
|
||||
}
|
||||
.card-priority.flash{ animation: flashHighlight .9s ease-out; }
|
||||
|
||||
/* 次级卡片更弱一些,拉开层级 */
|
||||
.card-secondary{
|
||||
border: 1px solid rgba(0,0,0,.06);
|
||||
box-shadow: 0 4px 14px rgba(0,0,0,.06);
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="theme-light">
|
||||
<body >
|
||||
<script src="./dist/js/demo-theme.min.js?1684106062"></script>
|
||||
<div class="page">
|
||||
<header class="navbar navbar-expand-md navbar-light d-print-none" style="border-bottom:1px solid rgba(0,0,0,.06);">
|
||||
<!-- Navbar -->
|
||||
<header class="navbar navbar-expand-md d-print-none" >
|
||||
<div class="container-xl">
|
||||
<h2 class="navbar-brand">海上评估系统</h2>
|
||||
<div class="ms-auto text-muted">管理员</div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu" aria-controls="navbar-menu" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<h1 class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
||||
<a href=".">
|
||||
<img src="./static/logo.svg" width="110" height="32" alt="Tabler" class="navbar-brand-image">
|
||||
</a>
|
||||
</h1>
|
||||
<div class="navbar-nav flex-row order-md-last">
|
||||
<div class="nav-item d-none d-md-flex me-3">
|
||||
<div class="btn-list">
|
||||
<a href="https://github.com/tabler/tabler" class="btn" target="_blank" rel="noreferrer">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/brand-github -->
|
||||
<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 d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" /></svg>
|
||||
Source code
|
||||
</a>
|
||||
<a href="https://github.com/sponsors/codecalm" class="btn" target="_blank" rel="noreferrer">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-pink" 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 d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" /></svg>
|
||||
Sponsor
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-flex">
|
||||
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/moon -->
|
||||
<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 d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" /></svg>
|
||||
</a>
|
||||
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/sun -->
|
||||
<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 d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /><path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" /></svg>
|
||||
</a>
|
||||
<div class="nav-item dropdown d-none d-md-flex me-3">
|
||||
<a href="#" class="nav-link px-0" data-bs-toggle="dropdown" tabindex="-1" aria-label="Show notifications">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/bell -->
|
||||
<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 d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6" /><path d="M9 17v1a3 3 0 0 0 6 0v-1" /></svg>
|
||||
<span class="badge bg-red"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Last updates</h3>
|
||||
</div>
|
||||
<div class="list-group list-group-flush list-group-hoverable">
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-red d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 1</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
Change deprecated html tags to text decoration classes (#29604)
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" 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 d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 2</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
justify-content:between ⇒ justify-content:space-between (#29734)
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions show">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-yellow" 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 d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 3</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
Update change-version.js (#29736)
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" 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 d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-green d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 4</a>
|
||||
<div class="d-block text-muted text-truncate mt-n1">
|
||||
Regenerate package-lock.json (#29730)
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-muted" 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 d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-item dropdown">
|
||||
<a href="#" class="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown" aria-label="Open user menu">
|
||||
<span class="avatar avatar-sm" style="background-image: url(./static/avatars/000m.jpg)"></span>
|
||||
<div class="d-none d-xl-block ps-2">
|
||||
<div>Paweł Kuna</div>
|
||||
<div class="mt-1 small text-muted">UI Designer</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||
<a href="#" class="dropdown-item">Status</a>
|
||||
<a href="./profile.html" class="dropdown-item">Profile</a>
|
||||
<a href="#" class="dropdown-item">Feedback</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="./settings.html" class="dropdown-item">Settings</a>
|
||||
<a href="./sign-in.html" class="dropdown-item">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
|
||||
<!-- 重点卡片:选择指标 -->
|
||||
<div class="card card-priority mb-3" id="cardPriority">
|
||||
<div class="card-header d-flex align-items-center">
|
||||
<span class="priority-dot"></span>
|
||||
<h3 class="card-title mb-0">选择指标
|
||||
<span class="badge bg-primary ms-2">必填</span>
|
||||
</h3>
|
||||
<div class="ms-auto">
|
||||
<button class="btn btn-primary" id="btnNext">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-center">
|
||||
<div class="col-auto">
|
||||
<label for="metricSelect" class="col-form-label">指标列表</label>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-lg-4">
|
||||
<select id="metricSelect" class="form-select">
|
||||
<option value="" selected disabled>请选择一个指标</option>
|
||||
<option value="aaa">AAA</option>
|
||||
<option value="bbb">BBB</option>
|
||||
<option value="ccc">CCC</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-lg-auto">
|
||||
<span class="form-hint">选择后将影响下方所有设置。</span>
|
||||
</div>
|
||||
<header class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse" id="navbar-menu">
|
||||
<div class="navbar">
|
||||
<div class="container-xl">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/home -->
|
||||
<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 d="M5 12l-2 0l9 -9l9 9l-2 0" /><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" /><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Home
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#navbar-base" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/package -->
|
||||
<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 d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5" /><path d="M12 12l8 -4.5" /><path d="M12 12l0 9" /><path d="M12 12l-8 -4.5" /><path d="M16 5.25l-8 4.5" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Interface
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<div class="dropdown-menu-columns">
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item" href="./accordion.html">
|
||||
Accordion
|
||||
</a>
|
||||
<a class="dropdown-item" href="./blank.html">
|
||||
Blank page
|
||||
</a>
|
||||
<a class="dropdown-item" href="./badges.html">
|
||||
Badges
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./buttons.html">
|
||||
Buttons
|
||||
</a>
|
||||
<div class="dropend">
|
||||
<a class="dropdown-item dropdown-toggle" href="#sidebar-cards" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
Cards
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a href="./cards.html" class="dropdown-item">
|
||||
Sample cards
|
||||
</a>
|
||||
<a href="./card-actions.html" class="dropdown-item">
|
||||
Card actions
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a href="./cards-masonry.html" class="dropdown-item">
|
||||
Cards Masonry
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="dropdown-item" href="./colors.html">
|
||||
Colors
|
||||
</a>
|
||||
<a class="dropdown-item" href="./datagrid.html">
|
||||
Data grid
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./datatables.html">
|
||||
Datatables
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./dropdowns.html">
|
||||
Dropdowns
|
||||
</a>
|
||||
<a class="dropdown-item" href="./modals.html">
|
||||
Modals
|
||||
</a>
|
||||
<a class="dropdown-item" href="./maps.html">
|
||||
Maps
|
||||
</a>
|
||||
<a class="dropdown-item" href="./map-fullsize.html">
|
||||
Map fullsize
|
||||
</a>
|
||||
<a class="dropdown-item" href="./maps-vector.html">
|
||||
Vector maps
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./navigation.html">
|
||||
Navigation
|
||||
</a>
|
||||
<a class="dropdown-item" href="./charts.html">
|
||||
Charts
|
||||
</a>
|
||||
<a class="dropdown-item" href="./pagination.html">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/pie-chart -->
|
||||
Pagination
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item" href="./placeholder.html">
|
||||
Placeholder
|
||||
</a>
|
||||
<a class="dropdown-item" href="./steps.html">
|
||||
Steps
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./stars-rating.html">
|
||||
Stars rating
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./tabs.html">
|
||||
Tabs
|
||||
</a>
|
||||
<a class="dropdown-item" href="./tables.html">
|
||||
Tables
|
||||
</a>
|
||||
<a class="dropdown-item" href="./carousel.html">
|
||||
Carousel
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./lists.html">
|
||||
Lists
|
||||
</a>
|
||||
<a class="dropdown-item" href="./typography.html">
|
||||
Typography
|
||||
</a>
|
||||
<a class="dropdown-item" href="./offcanvas.html">
|
||||
Offcanvas
|
||||
</a>
|
||||
<a class="dropdown-item" href="./markdown.html">
|
||||
Markdown
|
||||
</a>
|
||||
<a class="dropdown-item" href="./dropzone.html">
|
||||
Dropzone
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./lightbox.html">
|
||||
Lightbox
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./tinymce.html">
|
||||
TinyMCE
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./inline-player.html">
|
||||
Inline player
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<div class="dropend">
|
||||
<a class="dropdown-item dropdown-toggle" href="#sidebar-authentication" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
Authentication
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a href="./sign-in.html" class="dropdown-item">
|
||||
Sign in
|
||||
</a>
|
||||
<a href="./sign-in-link.html" class="dropdown-item">
|
||||
Sign in link
|
||||
</a>
|
||||
<a href="./sign-in-illustration.html" class="dropdown-item">
|
||||
Sign in with illustration
|
||||
</a>
|
||||
<a href="./sign-in-cover.html" class="dropdown-item">
|
||||
Sign in with cover
|
||||
</a>
|
||||
<a href="./sign-up.html" class="dropdown-item">
|
||||
Sign up
|
||||
</a>
|
||||
<a href="./forgot-password.html" class="dropdown-item">
|
||||
Forgot password
|
||||
</a>
|
||||
<a href="./terms-of-service.html" class="dropdown-item">
|
||||
Terms of service
|
||||
</a>
|
||||
<a href="./auth-lock.html" class="dropdown-item">
|
||||
Lock screen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropend">
|
||||
<a class="dropdown-item dropdown-toggle" href="#sidebar-error" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/file-minus -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-inline me-1" 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 d="M14 3v4a1 1 0 0 0 1 1h4" /><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" /><path d="M9 14l6 0" /></svg>
|
||||
Error pages
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a href="./error-404.html" class="dropdown-item">
|
||||
404 page
|
||||
</a>
|
||||
<a href="./error-500.html" class="dropdown-item">
|
||||
500 page
|
||||
</a>
|
||||
<a href="./error-maintenance.html" class="dropdown-item">
|
||||
Maintenance page
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./form-elements.html" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/checkbox -->
|
||||
<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 d="M9 11l3 3l8 -8" /><path d="M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Form elements
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#navbar-extra" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/star -->
|
||||
<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 d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Extra
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<div class="dropdown-menu-columns">
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item" href="./empty.html">
|
||||
Empty page
|
||||
</a>
|
||||
<a class="dropdown-item" href="./cookie-banner.html">
|
||||
Cookie banner
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./activity.html">
|
||||
Activity
|
||||
</a>
|
||||
<a class="dropdown-item" href="./gallery.html">
|
||||
Gallery
|
||||
</a>
|
||||
<a class="dropdown-item" href="./invoice.html">
|
||||
Invoice
|
||||
</a>
|
||||
<a class="dropdown-item" href="./search-results.html">
|
||||
Search results
|
||||
</a>
|
||||
<a class="dropdown-item" href="./pricing.html">
|
||||
Pricing cards
|
||||
</a>
|
||||
<a class="dropdown-item" href="./pricing-table.html">
|
||||
Pricing table
|
||||
</a>
|
||||
<a class="dropdown-item" href="./faq.html">
|
||||
FAQ
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./users.html">
|
||||
Users
|
||||
</a>
|
||||
<a class="dropdown-item" href="./license.html">
|
||||
License
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item active" href="./logs.html">
|
||||
Logs
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./music.html">
|
||||
Music
|
||||
</a>
|
||||
<a class="dropdown-item" href="./photogrid.html">
|
||||
Photogrid
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./tasks.html">
|
||||
Tasks
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./uptime.html">
|
||||
Uptime monitor
|
||||
</a>
|
||||
<a class="dropdown-item" href="./widgets.html">
|
||||
Widgets
|
||||
</a>
|
||||
<a class="dropdown-item" href="./wizard.html">
|
||||
Wizard
|
||||
</a>
|
||||
<a class="dropdown-item" href="./settings.html">
|
||||
Settings
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./trial-ended.html">
|
||||
Trial ended
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./job-listing.html">
|
||||
Job listing
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./page-loader.html">
|
||||
Page loader
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#navbar-layout" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/layout-2 -->
|
||||
<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 d="M4 4m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v1a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" /><path d="M4 13m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" /><path d="M14 4m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" /><path d="M14 15m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v1a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Layout
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<div class="dropdown-menu-columns">
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item" href="./layout-horizontal.html">
|
||||
Horizontal
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-boxed.html">
|
||||
Boxed
|
||||
<span class="badge badge-sm bg-green-lt text-uppercase ms-auto">New</span>
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-vertical.html">
|
||||
Vertical
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-vertical-transparent.html">
|
||||
Vertical transparent
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-vertical-right.html">
|
||||
Right vertical
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-condensed.html">
|
||||
Condensed
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-combo.html">
|
||||
Combined
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-menu-column">
|
||||
<a class="dropdown-item" href="./layout-navbar-dark.html">
|
||||
Navbar dark
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-navbar-sticky.html">
|
||||
Navbar sticky
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-navbar-overlap.html">
|
||||
Navbar overlap
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-rtl.html">
|
||||
RTL mode
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-fluid.html">
|
||||
Fluid
|
||||
</a>
|
||||
<a class="dropdown-item" href="./layout-fluid-vertical.html">
|
||||
Fluid vertical
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./icons.html" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/ghost -->
|
||||
<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 d="M5 11a7 7 0 0 1 14 0v7a1.78 1.78 0 0 1 -3.1 1.4a1.65 1.65 0 0 0 -2.6 0a1.65 1.65 0 0 1 -2.6 0a1.65 1.65 0 0 0 -2.6 0a1.78 1.78 0 0 1 -3.1 -1.4v-7" /><path d="M10 10l.01 0" /><path d="M14 10l.01 0" /><path d="M10 14a3.5 3.5 0 0 0 4 0" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
4158 icons
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#navbar-help" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false" >
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><!-- Download SVG icon from http://tabler-icons.io/i/lifebuoy -->
|
||||
<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 d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" /><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M15 15l3.35 3.35" /><path d="M9 15l-3.35 3.35" /><path d="M5.65 5.65l3.35 3.35" /><path d="M18.35 5.65l-3.35 3.35" /></svg>
|
||||
</span>
|
||||
<span class="nav-link-title">
|
||||
Help
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="https://tabler.io/docs" target="_blank" rel="noopener">
|
||||
Documentation
|
||||
</a>
|
||||
<a class="dropdown-item" href="./changelog.html">
|
||||
Changelog
|
||||
</a>
|
||||
<a class="dropdown-item" href="https://github.com/tabler/tabler" target="_blank" rel="noopener">
|
||||
Source code
|
||||
</a>
|
||||
<a class="dropdown-item text-pink" href="https://github.com/sponsors/codecalm" target="_blank" rel="noopener">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-inline me-1" 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 d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" /></svg>
|
||||
Sponsor project!
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="my-2 my-md-0 flex-grow-1 flex-md-grow-0 order-first order-md-last">
|
||||
<form action="./" method="get" autocomplete="off" novalidate>
|
||||
<div class="input-icon">
|
||||
<span class="input-icon-addon">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
|
||||
<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 d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" /><path d="M21 21l-6 -6" /></svg>
|
||||
</span>
|
||||
<input type="text" value="" class="form-control" placeholder="Search…" aria-label="Search in website">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 次级卡片:评价集设置 -->
|
||||
<div class="card card-secondary">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title mb-0">评价集设置</h3>
|
||||
<div class="ms-auto">
|
||||
<button class="btn btn-outline-primary" id="btnAdd">增加评价</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<!-- 左侧:子集列表 -->
|
||||
<div class="col-12 col-md-3">
|
||||
<div class="list-group">
|
||||
<label class="list-group-item">
|
||||
<input class="form-check-input me-2" type="radio" name="subset" value="x1"> x1
|
||||
</label>
|
||||
<label class="list-group-item">
|
||||
<input class="form-check-input me-2" type="radio" name="subset" value="c2" checked> c2
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:表格占位 -->
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>名称</th>
|
||||
<th>符号</th>
|
||||
<th>下限值</th>
|
||||
<th>符号</th>
|
||||
<th>上限值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rulesBody">
|
||||
<tr class="text-muted">
|
||||
<td colspan="6">尚未添加评价规则,点击右上角“增加评价”。</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- row -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 占位内容,方便滚动测试吸顶 -->
|
||||
<div style="height: 40vh;"></div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Logs
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4>
|
||||
Checked URL
|
||||
</h4>
|
||||
<div>
|
||||
<pre><code>GET <a class="text-reset" target="_blank" href="https://preview.tabler.io">https://preview.tabler.io</a></code></pre>
|
||||
</div>
|
||||
<h4>Request Timing</h4>
|
||||
<div>
|
||||
<pre>Effective URL <a class="text-reset" target="_blank" href="https://preview.tabler.io">https://preview.tabler.io</a><br>Redirect count 0<br>Name lookup time 3.4e-05<br>Connect time 0.000521<br>Pre-transfer time 0.0<br>Start-transfer time 0.0<br>App connect time 0.0<br>Redirect time 0.0<br>Total time 28.000601<br>Response code 0<br>Return keyword operation_timedout</pre>
|
||||
</div>
|
||||
<h4>Response Headers</h4>
|
||||
<div>
|
||||
<pre>HTTP/1.1 200 Connection established</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<h4>Escalation</h4>
|
||||
<div>Entire team</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer footer-transparent d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row text-center align-items-center flex-row-reverse">
|
||||
<div class="col-lg-auto ms-lg-auto">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item"><a href="https://tabler.io/docs" target="_blank" class="link-secondary" rel="noopener">Documentation</a></li>
|
||||
<li class="list-inline-item"><a href="./license.html" class="link-secondary">License</a></li>
|
||||
<li class="list-inline-item"><a href="https://github.com/tabler/tabler" target="_blank" class="link-secondary" rel="noopener">Source code</a></li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://github.com/sponsors/codecalm" target="_blank" class="link-secondary" rel="noopener">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/heart -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon text-pink icon-filled icon-inline" 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 d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" /></svg>
|
||||
Sponsor
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item">
|
||||
Copyright © 2023
|
||||
<a href="." class="link-secondary">Tabler</a>.
|
||||
All rights reserved.
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="./changelog.html" class="link-secondary" rel="noopener">
|
||||
v1.0.0-beta19
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 切换指标时,给重点卡片一个轻微高亮动画
|
||||
const card = document.getElementById('cardPriority');
|
||||
const select = document.getElementById('metricSelect');
|
||||
select.addEventListener('change', () => {
|
||||
card.classList.add('flash');
|
||||
setTimeout(() => card.classList.remove('flash'), 900);
|
||||
});
|
||||
|
||||
// 下一步按钮:如果未选择则聚焦并闪烁
|
||||
document.getElementById('btnNext').addEventListener('click', () => {
|
||||
if (!select.value) {
|
||||
select.focus();
|
||||
card.classList.add('flash');
|
||||
setTimeout(() => card.classList.remove('flash'), 900);
|
||||
} else {
|
||||
// 这里写你的跳转或展开逻辑
|
||||
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
|
||||
// 增加评价:简单追加一行示例
|
||||
document.getElementById('btnAdd').addEventListener('click', () => {
|
||||
const body = document.getElementById('rulesBody');
|
||||
if (body.firstElementChild && body.firstElementChild.classList.contains('text-muted')) {
|
||||
body.innerHTML = '';
|
||||
}
|
||||
const idx = body.children.length + 1;
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${idx}</td>
|
||||
<td><input class="form-control form-control-sm" placeholder="名称"/></td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm">
|
||||
<option>>=</option><option>></option><option>=</option>
|
||||
<option><=</option><option><</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="form-control form-control-sm" placeholder="下限"/></td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm">
|
||||
<option><=</option><option><</option><option>=</option>
|
||||
<option>>=</option><option>></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="form-control form-control-sm" placeholder="上限"/></td>
|
||||
`;
|
||||
body.appendChild(tr);
|
||||
});
|
||||
</script>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="./dist/js/tabler.min.js?1684106062" defer></script>
|
||||
<script src="./dist/js/demo.min.js?1684106062" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -24,4 +24,5 @@ public class Application {
|
|||
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
40
manager-admin/src/main/java/com/hshh/Init.java
Normal file
40
manager-admin/src/main/java/com/hshh/Init.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package com.hshh;
|
||||
|
||||
import com.hshh.system.common.threadpool.ThreadPools;
|
||||
import com.hshh.thread.HandleCmdThread;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 系统初始化类.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class Init {
|
||||
|
||||
private static final ExecutorService cpu = ThreadPools.newCpuBoundPool("cpu-pool");
|
||||
private static final int evaluationThreadNum = 5;
|
||||
|
||||
/**
|
||||
* 初始化系统相关函数.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
startEvaluationThread();
|
||||
}
|
||||
|
||||
private void startEvaluationThread() {
|
||||
try {
|
||||
for (int i = 0; i < evaluationThreadNum; i++) {
|
||||
cpu.execute(new Thread(new HandleCmdThread()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("error::", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ public class DataController extends BaseController {
|
|||
if (!modelDefineList.isEmpty()) {
|
||||
|
||||
List<FormFieldConfig> formConfigList = formFieldConfigService.getFormFieldConfigByModelId(
|
||||
modelDefineList.get(0).getId()); //查询模型表头
|
||||
(request.getId() == null ? modelDefineList.get(0).getId() : request.getId())); //查询模型表头
|
||||
sortFieldList(formConfigList); //排序
|
||||
Map<String, String> headerMap = new LinkedHashMap<>(); //定义表头兑现
|
||||
formConfigList.forEach(formFieldConfig -> {
|
||||
|
|
@ -131,10 +131,13 @@ public class DataController extends BaseController {
|
|||
model.addAttribute("currentModelDefine", activeModelDefine.get());
|
||||
} else {
|
||||
//设置默认第一个选中
|
||||
modelDefineList.get(0).setChecked(true);
|
||||
//设置查询参数为第一个
|
||||
request.setId(modelDefineList.get(0).getId());
|
||||
model.addAttribute("currentModelDefine", modelDefineList.get(0));
|
||||
if (!modelDefineList.isEmpty()) {
|
||||
modelDefineList.get(0).setChecked(true);
|
||||
//设置查询参数为第一个
|
||||
request.setId(modelDefineList.get(0).getId());
|
||||
model.addAttribute("currentModelDefine", modelDefineList.get(0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述请求数据到类型类.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class DatasourceRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
//数据源类型 数据库||Csv文件
|
||||
private String datasourceType;
|
||||
//工程ID
|
||||
private Integer projectId;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述评估字段对应的信息,包含权重和评价集.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class EvalItemToFieldInfo {
|
||||
|
||||
/**
|
||||
* 字段名称.
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 权重.
|
||||
*/
|
||||
private double weight;
|
||||
/**
|
||||
* 评价集列表.
|
||||
*/
|
||||
private List<IndicatorEvalItem> evalItemList;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 描述评估请求对象.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class EvaluationRequest {
|
||||
|
||||
/**
|
||||
* database | csv.
|
||||
*/
|
||||
private String datasourceType;
|
||||
/**
|
||||
* 基础设施ID.
|
||||
*/
|
||||
private Integer modelId;
|
||||
/**
|
||||
* 工程ID.
|
||||
*/
|
||||
private Integer projectId;
|
||||
/**
|
||||
* 查询关键子.
|
||||
*/
|
||||
private String search;
|
||||
/**
|
||||
* 模板ID.
|
||||
*/
|
||||
private Integer templateId;
|
||||
/**
|
||||
* 随机字符.
|
||||
*/
|
||||
private String randomKey;
|
||||
/**
|
||||
* 计算方式
|
||||
*/
|
||||
private String method;
|
||||
}
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationProject;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.service.EvaluationProjectService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.model.entity.FormValue;
|
||||
import com.hshh.model.service.FormFieldConfigService;
|
||||
import com.hshh.model.service.FormValueService;
|
||||
import com.hshh.system.base.entity.TableRelations;
|
||||
import com.hshh.system.base.service.TableRelationsService;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
|
|
@ -13,7 +19,9 @@ import com.hshh.system.common.enums.ErrorCode;
|
|||
import com.hshh.system.common.enums.ErrorMessage;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
|
@ -38,17 +46,36 @@ public class EvaluationProjectController extends BaseController {
|
|||
|
||||
@Resource
|
||||
private EvaluationProjectService evaluationProjectService;
|
||||
|
||||
/**
|
||||
* 模板服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateService evaluationTemplateService;
|
||||
|
||||
/**
|
||||
* 数据库引用关系记录服务类.
|
||||
*/
|
||||
@Resource
|
||||
private TableRelationsService tableRelationsService;
|
||||
|
||||
/**
|
||||
* 基础设施服务类.
|
||||
*/
|
||||
@Resource
|
||||
private FormFieldConfigService formFieldConfigService;
|
||||
/**
|
||||
* 数据查询服务类.
|
||||
*/
|
||||
@Resource
|
||||
private FormValueService formValueService;
|
||||
/**
|
||||
* 指标服务类.
|
||||
*/
|
||||
@Resource
|
||||
private IndicatorService indicatorService;
|
||||
|
||||
|
||||
/**
|
||||
* 默认页.
|
||||
*
|
||||
|
|
@ -120,8 +147,7 @@ public class EvaluationProjectController extends BaseController {
|
|||
@ResponseBody
|
||||
@GetMapping("/remove/{id}")
|
||||
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
|
||||
List<TableRelations> reList = tableRelationsService.queryRel(id,
|
||||
"m_data_evaluation_project");
|
||||
List<TableRelations> reList = tableRelationsService.queryRel(id, "m_data_evaluation_project");
|
||||
if (!reList.isEmpty()) {
|
||||
return OperateResult.error(null, ErrorMessage.OBJ_ALREADY_TAKEN.getMessage(),
|
||||
ErrorCode.BUSINESS_ERROR.getCode());
|
||||
|
|
@ -130,4 +156,106 @@ public class EvaluationProjectController extends BaseController {
|
|||
return OperateResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择数据源类型.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @param model session容器
|
||||
* @return project/datasource_select.html
|
||||
*/
|
||||
@GetMapping("/selectDatasourceType")
|
||||
public String selectDatasourceType(Integer projectId, String randomKey, Model model) {
|
||||
model.addAttribute("projectId", projectId);
|
||||
model.addAttribute("randomKey", randomKey);
|
||||
return "project/datasource_select";
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航到数据库记录展现界面.
|
||||
*
|
||||
* @param request 查询请求
|
||||
* @param model session容器
|
||||
* @return project/datasource_db.html
|
||||
*/
|
||||
@GetMapping("/database")
|
||||
public String databasePage(PaginationBean request, Model model) {
|
||||
//获取工程
|
||||
|
||||
//获取基础设施ID
|
||||
Long modelId = evaluationProjectService.selectModelIdByProjectId(request.getId());
|
||||
//设置数据源页面中的隐藏属性
|
||||
addDatasourceModelAttribute(modelId, request, model);
|
||||
//获取表头
|
||||
Map<String, String> headerMap = formFieldConfigService.getHeaderMap(modelId.intValue());
|
||||
model.addAttribute("headerMap", headerMap);
|
||||
//查询数据
|
||||
//替换为modelId查询
|
||||
request.setId(modelId.intValue());
|
||||
List<FormValue> formDataList = formValueService.list(request);
|
||||
List<Map<String, Object>> listMap = new ArrayList<>();
|
||||
formDataList.forEach(formData -> {
|
||||
|
||||
listMap.add(formData.toMap()); //转为map对象放入listMap中
|
||||
});
|
||||
|
||||
Long total = formValueService.count(request);
|
||||
setPaginationInfo(request, listMap, total, model);
|
||||
return "project/datasource_db";
|
||||
}
|
||||
|
||||
private void addDatasourceModelAttribute(Long modelId, PaginationBean request, Model model) {
|
||||
EvaluationProject project = evaluationProjectService.getById(request.getId());
|
||||
if (project != null) {
|
||||
model.addAttribute("templateId", project.getTemplateId());
|
||||
}
|
||||
//缓存modelId,projectId
|
||||
model.addAttribute("modelId", modelId);
|
||||
model.addAttribute("projectId", request.getId());
|
||||
model.addAttribute("search", request.getSearch());
|
||||
model.addAttribute("randomKey", request.getRandomKey());
|
||||
model.addAttribute("method", request.getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航到csv记录呈现界面.
|
||||
*
|
||||
* @param request 查询请求
|
||||
* @param model session容器
|
||||
* @return project/datasource_csv.html
|
||||
*/
|
||||
@GetMapping("/csv")
|
||||
public String csvPage(PaginationBean request, Model model) {
|
||||
return "project/datasource_csv";
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航的数据评估执行页面.
|
||||
*
|
||||
* @param request 评估请求
|
||||
* @param model session容器
|
||||
* @return 评估处理页面
|
||||
*/
|
||||
@PostMapping("/processEvaluation")
|
||||
public String processEvaluationPage(@RequestBody EvaluationRequest request, Model model) {
|
||||
|
||||
addProcessEvaluationModelAttribute(request, model);
|
||||
return "project/project_evaluation_process";
|
||||
}
|
||||
|
||||
private void addProcessEvaluationModelAttribute(EvaluationRequest request, Model model) {
|
||||
//获取工程名称
|
||||
EvaluationProject project = evaluationProjectService.getById(request.getProjectId());
|
||||
if (project != null) {
|
||||
model.addAttribute("projectName", project.getProjectName());
|
||||
}
|
||||
Indicator indicator = indicatorService.selectByTemplateId(
|
||||
request.getTemplateId());
|
||||
//获取指标名称
|
||||
if (indicator != null) {
|
||||
model.addAttribute("indicatorName", indicator.getName());
|
||||
}
|
||||
//设置数据源类型
|
||||
model.addAttribute("datasourceName",
|
||||
(request.getDatasourceType().equals("database") ? "数据库" : "CSV文件"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.hshh.evaluation.bean.MetricMapperWeightBean;
|
|||
import com.hshh.evaluation.bean.MetricTableHeaderBean;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateIndicatorWeightService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateWeightService;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
|
|
@ -74,10 +75,16 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
private TableRelationsService tableRelationsService;
|
||||
|
||||
/**
|
||||
* 权重服务类.
|
||||
* 权重服务详情类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateWeightService evaluationTemplateWeightService;
|
||||
private EvaluationTemplateWeightService evaluationTemplateDetailWeightService;
|
||||
/**
|
||||
* 指标权重类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateIndicatorWeightService evaluationTemplateIndicatorWeightService;
|
||||
|
||||
|
||||
/**
|
||||
* 默认页.
|
||||
|
|
@ -111,16 +118,40 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
/**
|
||||
* 获取指标树.
|
||||
*
|
||||
* @param id 项目ID
|
||||
* @param id 指标ID
|
||||
* @return 指标树
|
||||
*/
|
||||
@GetMapping("/metricTree/{id}")
|
||||
@GetMapping("/metricTree/{id}/{templateId}")
|
||||
@ResponseBody
|
||||
public OperateResult<List<JsTree>> metricTree(@PathVariable("id") Integer id, Model model) {
|
||||
|
||||
return OperateResult.success(indicatorService.metricTree(id));
|
||||
public OperateResult<List<JsTree>> metricTree(@PathVariable("id") Integer id,
|
||||
@PathVariable("templateId") Integer templateId) {
|
||||
if (id == null) {
|
||||
return OperateResult.success(new ArrayList<>());
|
||||
}
|
||||
//查询指标权重树
|
||||
Map<Integer, Double> weightMap = evaluationTemplateIndicatorWeightService.getEvaluationTemplateIndicatorWeightMap(
|
||||
id, templateId);
|
||||
Map<Integer, List<EvaluationTemplateWeight>> weightDetailMap = evaluationTemplateDetailWeightService.groupByParentIndicatorId(
|
||||
id, templateId);
|
||||
List<JsTree> jsTreeList = indicatorService.metricTree(id);
|
||||
//开始给指标设置权重,指标名称后挂在权重信息;并在data属性中,增加子节点-子节点的权重信息
|
||||
setWeightToTree(jsTreeList, weightMap, weightDetailMap);
|
||||
return OperateResult.success(jsTreeList);
|
||||
}
|
||||
|
||||
private void setWeightToTree(List<JsTree> jsTreeList, Map<Integer, Double> weightMap,
|
||||
Map<Integer, List<EvaluationTemplateWeight>> weightDetailMap) {
|
||||
jsTreeList.forEach(tree -> {
|
||||
if (weightMap.containsKey((int) tree.getOriginalId())) {
|
||||
tree.getData().put("weight", weightMap.get((int) tree.getOriginalId()));
|
||||
|
||||
}
|
||||
if(weightDetailMap.containsKey((int) tree.getOriginalId())) {
|
||||
tree.getData().put("weightDetail", weightDetailMap.get((int) tree.getOriginalId()));
|
||||
}
|
||||
setWeightToTree(tree.getChildren(), weightMap, weightDetailMap);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存模板. 必须设置指标;设置完成权重,才成成功提交
|
||||
|
|
@ -207,157 +238,7 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
return OperateResult.success(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂存权重数据.
|
||||
*
|
||||
* @param data 权重数据 页面传入的权重map数据key为rowId_colId(from指标id_to指标ID)
|
||||
* value为{rowId:a,colId:b,value:0.1}类似
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/receiveDraft")
|
||||
@ResponseBody
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized OperateResult<Void> receiveDraft(@RequestBody DraftWeightData data) {
|
||||
log.info("receive draft data: pId= {}", data.getParentIndicationId());
|
||||
//根据key获取已经缓存的信息
|
||||
Map<Integer, DraftWeightData> dataMap = DraftStore.get(data.getKey(), Map.class);
|
||||
//如果缓存不存在
|
||||
if (dataMap == null) {
|
||||
dataMap = new HashMap<>();
|
||||
}
|
||||
//key为上级指标
|
||||
dataMap.put(data.getParentIndicationId(), data);
|
||||
//更新缓存
|
||||
DraftStore.put(data.getKey(), dataMap);
|
||||
return OperateResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取暂存数据.
|
||||
*
|
||||
* @param requestData 请求数据.
|
||||
* @return 表格和数据
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@PostMapping("/getDraftData")
|
||||
public synchronized String getDraftData(@RequestBody DraftWeightData requestData, Model model) {
|
||||
//查看key 是否有缓存记录
|
||||
Map<Integer, Object> cacheData = DraftStore.get(requestData.getKey(), Map.class);
|
||||
//如果没有记录
|
||||
if (cacheData == null) { //从数据库中获取
|
||||
model.addAttribute("data", createNewDynamicFromDatabase(requestData));
|
||||
return "project_template/table";
|
||||
}
|
||||
//如果有记录查看对应的指标是否有记录
|
||||
Object cacheWeightObj = cacheData.get(requestData.getParentIndicationId());
|
||||
//如果对应指标没有记录
|
||||
if (cacheWeightObj == null) { //从数据库读取
|
||||
model.addAttribute("data", createNewDynamicFromDatabase(requestData));
|
||||
return "project_template/table";
|
||||
}
|
||||
DraftWeightData data = (DraftWeightData) cacheWeightObj;
|
||||
|
||||
model.addAttribute("data", createDynamicFromCache(data));
|
||||
return "project_template/table";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据库创建动态表.
|
||||
*
|
||||
* @param requestData 用户请求数据
|
||||
* @return 动态表
|
||||
*/
|
||||
private DynamicTable createNewDynamicFromDatabase(DraftWeightData requestData) {
|
||||
DynamicTable dynamicTable = new DynamicTable();
|
||||
//查询当前指标的子指标
|
||||
List<Indicator> children = indicatorService.queryChildren(requestData.getParentIndicationId());
|
||||
//获取指标权重信息
|
||||
List<EvaluationTemplateWeight> weightInDbList = evaluationTemplateWeightService.queryListByIndicatorParentIdAndTemplateId(
|
||||
requestData.getParentIndicationId(), requestData.getTemplateId());
|
||||
//转化为key=fromId+"_"+toId,value=self
|
||||
Map<String, EvaluationTemplateWeight> weightInMap = weightInDbList.stream()
|
||||
.collect(
|
||||
Collectors.toMap(a -> a.getFromIndicatorId() + "_" + a.getToIndicatorId(), a -> a));
|
||||
//设置头信息
|
||||
dynamicTable.setHeaderMap(createTableHeaderMap(children));
|
||||
|
||||
//设置权重信息
|
||||
List<List<MetricMapperWeightBean>> weight = new ArrayList<>();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
List<MetricMapperWeightBean> innerList = createEmptyMapperList(requestData, children, i,
|
||||
weightInMap);
|
||||
weight.add(innerList);
|
||||
}
|
||||
|
||||
dynamicTable.setWeight(weight);
|
||||
return dynamicTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表格头.
|
||||
*
|
||||
* @param children 子指标
|
||||
* @return 表格头信息
|
||||
*/
|
||||
private Map<Integer, MetricTableHeaderBean> createTableHeaderMap(List<Indicator> children) {
|
||||
List<MetricTableHeaderBean> headerBeans = new ArrayList<>();
|
||||
children.forEach(a -> {
|
||||
MetricTableHeaderBean bean = new MetricTableHeaderBean();
|
||||
bean.setId(a.getId());
|
||||
bean.setName(a.getName());
|
||||
headerBeans.add(bean);
|
||||
});
|
||||
Map<Integer, MetricTableHeaderBean> headerMap = new LinkedHashMap<>();
|
||||
headerBeans.forEach(header -> {
|
||||
headerMap.put(header.getId(), header);
|
||||
});
|
||||
return headerMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据库创建一个空的默认映射列表.
|
||||
*
|
||||
* @param requestData 请求数据
|
||||
* @param children 子指标
|
||||
* @param i 行号
|
||||
* @return 默认映射列表
|
||||
*/
|
||||
private static List<MetricMapperWeightBean> createEmptyMapperList(DraftWeightData requestData,
|
||||
List<Indicator> children, int i, Map<String, EvaluationTemplateWeight> weightInMap) {
|
||||
List<MetricMapperWeightBean> innerList = new ArrayList<>();
|
||||
for (Indicator child : children) {
|
||||
MetricMapperWeightBean weightBean = new MetricMapperWeightBean();
|
||||
//行ID
|
||||
weightBean.setRowId(children.get(i).getId());
|
||||
//列Id
|
||||
weightBean.setColId(child.getId());
|
||||
EvaluationTemplateWeight evaluationTemplateWeight = weightInMap.get(
|
||||
weightBean.getRowId() + "_" + weightBean.getColId());
|
||||
//初始默认为1
|
||||
weightBean.setValue(
|
||||
evaluationTemplateWeight == null ? "1" : evaluationTemplateWeight.getWeight() + "");
|
||||
|
||||
weightBean.setRowNum(evaluationTemplateWeight == null ? (i + 1)
|
||||
: evaluationTemplateWeight.getRowNum());
|
||||
weightBean.setParentId(requestData.getParentIndicationId());
|
||||
innerList.add(weightBean);
|
||||
}
|
||||
return innerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中创建动态表.
|
||||
*
|
||||
* @param data 缓存数据
|
||||
* @return 动态表
|
||||
*/
|
||||
protected DynamicTable createDynamicFromCache(DraftWeightData data) {
|
||||
DynamicTable dynamicTable = new DynamicTable();
|
||||
dynamicTable.setHeaderMap(data.getHeaderMap());
|
||||
dynamicTable.setWeight(data.getWeight());
|
||||
return dynamicTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指标,当设置变化时触发.
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import lombok.Data;
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* 模板指标权重表
|
||||
* 模板指标权重详情表.
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-14
|
||||
*/
|
||||
@TableName("m_data_evaluation_template_weight")
|
||||
@TableName("m_data_evaluation_template_weight_detail")
|
||||
@Data
|
||||
public class EvaluationTemplateWeight implements Serializable {
|
||||
|
||||
|
|
|
|||
|
|
@ -28,4 +28,12 @@ public interface EvaluationProjectMapper extends BaseMapper<EvaluationProject> {
|
|||
* @return 总条数
|
||||
*/
|
||||
Long count(PaginationBean paginationBean);
|
||||
|
||||
/**
|
||||
* 根据工程ID获取到对应的基础设施ID.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return 基础设施ID
|
||||
*/
|
||||
Long selectModelIdByProjectId(Integer projectId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,4 +28,6 @@ public interface EvaluationTemplateMapper extends BaseMapper<EvaluationTemplate>
|
|||
* @return 总数
|
||||
*/
|
||||
Long count(PaginationBean search);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationProject;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.List;
|
||||
|
|
@ -43,4 +44,20 @@ public interface EvaluationProjectService extends IService<EvaluationProject> {
|
|||
* @param evaluationProject 工程数据
|
||||
*/
|
||||
void saveWhole(EvaluationProject evaluationProject);
|
||||
|
||||
/**
|
||||
* 根据工程ID获取到对应的基础设施ID.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return 基础设施ID
|
||||
*/
|
||||
Long selectModelIdByProjectId(Integer projectId);
|
||||
|
||||
/**
|
||||
* 评估动作.
|
||||
*
|
||||
* @param request 评估请求
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void evaluate(EvaluationRequest request, Integer userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.hshh.evaluation.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.DraftWeightData;
|
||||
import com.hshh.evaluation.bean.MetricMapperWeightBean;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.List;
|
||||
|
|
@ -48,5 +47,13 @@ public interface EvaluationTemplateService extends IService<EvaluationTemplate>
|
|||
* @return 模板列表
|
||||
*/
|
||||
List<EvaluationTemplate> queryByName(String name);
|
||||
|
||||
/**
|
||||
* 删除模板(事务删除).
|
||||
*
|
||||
* @param evaluationTemplate 模板数据
|
||||
*/
|
||||
void deleteTemplate(EvaluationTemplate evaluationTemplate);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.hshh.evaluation.service;
|
|||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 模板指标权重表 服务类.
|
||||
|
|
@ -40,4 +41,14 @@ public interface EvaluationTemplateWeightService extends IService<EvaluationTemp
|
|||
*/
|
||||
List<EvaluationTemplateWeight> queryListByIndicatorParentIdAndTemplateId(
|
||||
Integer indicatorParentId, Integer templateId);
|
||||
|
||||
/**
|
||||
* 指标对应的权重详情,按照父指标ID分类.
|
||||
*
|
||||
* @param indicatorParentId 父指标ID
|
||||
* @param templateId 模板ID
|
||||
* @return 权重map信息
|
||||
*/
|
||||
Map<Integer, List<EvaluationTemplateWeight>> groupByParentIndicatorId(Integer indicatorParentId,
|
||||
Integer templateId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,27 @@ package com.hshh.evaluation.service.impl;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import com.hshh.evaluation.entity.EvaluationProject;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.mapper.EvaluationProjectMapper;
|
||||
import com.hshh.evaluation.service.EvaluationHistoryService;
|
||||
import com.hshh.evaluation.service.EvaluationProjectService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.model.entity.FormValue;
|
||||
import com.hshh.model.service.FormValueService;
|
||||
import com.hshh.system.base.service.TableRelationsService;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import com.hshh.system.ws.WsEvaluationServer;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
|
@ -20,15 +33,33 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @since 2025-08-11
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class EvaluationProjectServiceImpl extends
|
||||
ServiceImpl<EvaluationProjectMapper, EvaluationProject> implements
|
||||
EvaluationProjectService {
|
||||
ServiceImpl<EvaluationProjectMapper, EvaluationProject> implements EvaluationProjectService {
|
||||
|
||||
private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
//每次评估一批数据的长度
|
||||
private static final int pageSize = 100;
|
||||
/**
|
||||
* 数据库引用关系记录服务类.
|
||||
*/
|
||||
@Resource
|
||||
private TableRelationsService tableRelationsService;
|
||||
/**
|
||||
* 评估历史服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationHistoryService evaluationHistoryService;
|
||||
/**
|
||||
* 评估模板服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateService evaluationTemplateService;
|
||||
/**
|
||||
* 数据查询服务类.
|
||||
*/
|
||||
@Resource
|
||||
private FormValueService formValueService;
|
||||
|
||||
@Override
|
||||
public List<EvaluationProject> list(PaginationBean paginationBean) {
|
||||
|
|
@ -58,4 +89,139 @@ public class EvaluationProjectServiceImpl extends
|
|||
tableRelationsService.addRel(evaluationProject.getId(), "m_data_evaluation_project", relList,
|
||||
"m_data_evaluation_template");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long selectModelIdByProjectId(Integer projectId) {
|
||||
return this.baseMapper.selectModelIdByProjectId(projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 评估操作.
|
||||
*
|
||||
* @param request 评估请求
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void evaluate(EvaluationRequest request, Integer userId) {
|
||||
|
||||
//查询模板然后获取指标ID
|
||||
EvaluationTemplate template = evaluationTemplateService.getById(request.getTemplateId());
|
||||
|
||||
//发送开始处理消息
|
||||
sendTips("开始处理", request.getRandomKey());
|
||||
|
||||
//插入评估历史表
|
||||
Integer historyId = insertEvaluationHistory(request, userId);
|
||||
//处理来自于数据库的记录
|
||||
if (request.getDatasourceType().equals("database")) {
|
||||
handleDataBaseData(request, template.getIndicatorTopId(), historyId, userId);
|
||||
}
|
||||
//处理来自于 csv导入的记录
|
||||
if (request.getDatasourceType().equals("csv")) {
|
||||
handleCsvData(request, template.getIndicatorTopId(), historyId, userId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//根据searchKey查询
|
||||
|
||||
/**
|
||||
* 处理数据库的记录.
|
||||
*
|
||||
* @param request 评估请求.
|
||||
* @param indicatorTopId 指标ID
|
||||
* @param historyId 历史记录ID
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
private void handleDataBaseData(EvaluationRequest request, Integer indicatorTopId,
|
||||
Integer historyId, Integer userId) {
|
||||
|
||||
sendTips("数据来源:数据库记录", request.getRandomKey());
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
//查询记录总条数
|
||||
PaginationBean pageBean = new PaginationBean();
|
||||
pageBean.setId(request.getModelId());
|
||||
pageBean.setSearch(request.getSearch());
|
||||
Long total = formValueService.count(pageBean);
|
||||
|
||||
sendTips("数据记录条数" + total, request.getRandomKey());
|
||||
|
||||
int totalPage = (int) Math.ceil(total / (double) pageSize);
|
||||
//开始循坏评估
|
||||
for (int i = 1; i <= totalPage; i++) {
|
||||
pageBean.setCurrentPage(1);
|
||||
pageBean.setPageSize(pageSize);
|
||||
pageBean.setSearch(request.getSearch());
|
||||
//查询
|
||||
List<FormValue> originalList = formValueService.list(pageBean);
|
||||
count.addAndGet(originalList.size());
|
||||
|
||||
//把表单数据映射为一个列表
|
||||
List<String> dataList = originalList.stream()
|
||||
.map(FormValue::getModelData).collect(Collectors.toList());
|
||||
evaluationOneBatchData(dataList, request, indicatorTopId, historyId, userId);
|
||||
|
||||
sendTips(originalList.size() + "数据评估完成,累计完成(" + count.get() + ")",
|
||||
request.getRandomKey());
|
||||
}
|
||||
|
||||
sendTips("数据全部评估完成,累计评估(" + count.get() + ")", request.getRandomKey());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理CSV的记录.
|
||||
*
|
||||
* @param request 评估请求.
|
||||
* @param indicatorTopId 指标ID
|
||||
* @param historyId 历史记录ID
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
private void handleCsvData(EvaluationRequest request, Integer indicatorTopId, Integer historyId,
|
||||
Integer userId) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 评估一批数据.
|
||||
*
|
||||
* @param data 待评估数据
|
||||
* @param request 请求信息
|
||||
* @param indicatorTopId 指标ID
|
||||
* @param historyId 历史记录ID
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
private void evaluationOneBatchData(List<String> data, EvaluationRequest request,
|
||||
Integer indicatorTopId, Integer historyId, Integer userId) {
|
||||
//结果集定义
|
||||
List<String> resultList = new ArrayList<>();
|
||||
for (String rawData : data) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 插入评估历史表,返回ID.
|
||||
*
|
||||
* @param request 评估请求
|
||||
*/
|
||||
private Integer insertEvaluationHistory(EvaluationRequest request, Integer userId) {
|
||||
EvaluationHistory history = new EvaluationHistory();
|
||||
history.setProjectId(request.getProjectId());
|
||||
history.setCreateTime(LocalDateTime.now());
|
||||
history.setUserId(userId);
|
||||
history.setRandomKey(request.getRandomKey());
|
||||
evaluationHistoryService.save(history);
|
||||
return history.getId();
|
||||
}
|
||||
|
||||
void sendTips(String message, String randomKey) {
|
||||
//发送开始处理消息
|
||||
LocalDateTime start = LocalDateTime.now();
|
||||
WsEvaluationServer.sendToKey(randomKey, start.format(df) + " " + message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,4 +92,6 @@ public class EvaluationTemplateServiceImpl extends
|
|||
evaluationTemplate.getId());
|
||||
this.removeById(evaluationTemplate.getId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
|||
import com.hshh.evaluation.mapper.EvaluationTemplateWeightMapper;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateWeightService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
|
@ -51,4 +53,16 @@ public class EvaluationTemplateWeightServiceImpl extends
|
|||
queryWrapper.eq("indicator_parent_id", indicatorParentId);
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, List<EvaluationTemplateWeight>> groupByParentIndicatorId(
|
||||
Integer indicatorParentId, Integer templateId) {
|
||||
List<EvaluationTemplateWeight> list = this.queryListByIndicatorParentIdAndTemplateId(
|
||||
indicatorParentId, templateId);
|
||||
if (!list.isEmpty()) {
|
||||
return list.stream()
|
||||
.collect(Collectors.groupingBy(EvaluationTemplateWeight::getIndicatorParentId));
|
||||
}
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,38 +56,36 @@ public class EvaluationController extends BaseController {
|
|||
if (topIndicatorId != null) {
|
||||
for (Indicator indicator : rootList) {
|
||||
if (indicator.getId().equals(topIndicatorId)) {
|
||||
//回显上次选择的
|
||||
indicator.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
topIndicatorId = rootList.get(0).getId();
|
||||
rootList.get(0).setChecked(true);
|
||||
|
||||
}
|
||||
}
|
||||
//查询所有没有孩子的子节点
|
||||
List<Indicator> indicatorListWithoutChildren = indicatorService.selectNoChildByTopId(
|
||||
topIndicatorId);
|
||||
if (!indicatorListWithoutChildren.isEmpty()) {
|
||||
if (indicatorId != null) {
|
||||
for (Indicator indicator : indicatorListWithoutChildren) {
|
||||
if (indicator.getId().equals(indicatorId)) {
|
||||
indicator.setChecked(true);
|
||||
if (topIndicatorId != null) {
|
||||
List<Indicator> indicatorListWithoutChildren = indicatorService.selectNoChildByTopId(
|
||||
topIndicatorId);
|
||||
if (!indicatorListWithoutChildren.isEmpty()) {
|
||||
{
|
||||
for (Indicator indicator : indicatorListWithoutChildren) {
|
||||
if (indicator.getId().equals(indicatorId)) {
|
||||
indicator.setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
indicatorListWithoutChildren.get(0).setChecked(true);
|
||||
|
||||
//查询子指标的评价集
|
||||
List<IndicatorEvalItem> evaluationList = indicatorEvalItemService.queryListByIndicatorId(
|
||||
(indicatorId == null ? indicatorListWithoutChildren.get(0).getId() : indicatorId)
|
||||
);
|
||||
model.addAttribute("evaluationList", evaluationList);
|
||||
model.addAttribute("indicatorListWithoutChildren", indicatorListWithoutChildren);
|
||||
}
|
||||
|
||||
}
|
||||
//查询子指标的评价集
|
||||
List<IndicatorEvalItem> evaluationList = indicatorEvalItemService.queryListByIndicatorId(
|
||||
indicatorId == null ? (indicatorListWithoutChildren.isEmpty() ? 0
|
||||
: indicatorListWithoutChildren.get(0).getId()) : indicatorId);
|
||||
model.addAttribute("evaluationList", evaluationList);
|
||||
|
||||
model.addAttribute("rootList", rootList);
|
||||
model.addAttribute("indicatorListWithoutChildren", indicatorListWithoutChildren);
|
||||
|
||||
return "indicator/evaluation_list";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ public class IndicatorController extends BaseController {
|
|||
}
|
||||
}
|
||||
model.addAttribute("rootList", rootList);
|
||||
return "/indicator/list";
|
||||
return "indicator/list";
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -236,14 +236,15 @@ public class IndicatorController extends BaseController {
|
|||
List<Indicator> rootList = indicatorService.queryRootList();
|
||||
|
||||
//设置根指标的选中状态
|
||||
setChecked(rootList, indicatorTopId, true);
|
||||
setChecked(rootList, indicatorTopId, false);
|
||||
|
||||
// 顶级指标放入session容器
|
||||
model.addAttribute("rootList", rootList);
|
||||
// 底层指标放入session容器
|
||||
model.addAttribute("childrenIndicator", indicatorService.selectNoChildByTopId(
|
||||
indicatorTopId == null ? (rootList.isEmpty() ? 0 : rootList.get(0).getId())
|
||||
: indicatorTopId));
|
||||
if (indicatorTopId != null) {
|
||||
model.addAttribute("childrenIndicator", indicatorService.selectNoChildByTopId(
|
||||
indicatorTopId));
|
||||
}
|
||||
|
||||
// form表单和顶级指标对应列表放入session容器
|
||||
modelForm(model, (indicatorTopId == null ? (rootList.isEmpty() ? 0 : rootList.get(0).getId())
|
||||
|
|
|
|||
|
|
@ -45,5 +45,7 @@ public class Indicator extends CheckedBean {
|
|||
return this.name;
|
||||
}
|
||||
|
||||
@TableField(exist = false)
|
||||
private double weight;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public class IndicatorEvalItem implements Serializable {
|
|||
@NotNull(message = "值不能为空")
|
||||
@Size(max = 10, message = "值不能超过10字符")
|
||||
private String maxValue;
|
||||
|
||||
@NotNull(message = "值不能为空")
|
||||
private Double grade;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,5 +19,13 @@ public interface IndicatorMapper extends BaseMapper<Indicator> {
|
|||
* @param topId 祖先指标ID
|
||||
* @return 指标集
|
||||
*/
|
||||
public List<Indicator> selectNoChildByTopId(@Param("topId") Integer topId);
|
||||
List<Indicator> selectNoChildByTopId(@Param("topId") Integer topId);
|
||||
|
||||
/**
|
||||
* 根据评估模板获取指标.
|
||||
*
|
||||
* @param templateId 模板 ID
|
||||
* @return 指标列表
|
||||
*/
|
||||
List<Indicator> selectByTemplateId(@Param("templateId") Integer templateId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.hshh.indicator.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.EvalItemToFieldInfo;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 指标规则表 服务类.
|
||||
|
|
@ -28,4 +30,20 @@ public interface IndicatorEvalItemService extends IService<IndicatorEvalItem> {
|
|||
* @return 评价集
|
||||
*/
|
||||
List<IndicatorEvalItem> queryListByIndicatorId(Integer indicatorId);
|
||||
|
||||
/**
|
||||
* 查询数据类型为从数据库读取的字段评价集及权重.
|
||||
*
|
||||
* @param indicatorTopId 指标顶级ID
|
||||
* @return 对应map key为字段名称
|
||||
*/
|
||||
Map<String, EvalItemToFieldInfo> evalMapForDatabaseTypeData(Integer indicatorTopId);
|
||||
|
||||
/**
|
||||
* 查询数据类型为从csv读取的字段评价集及权重.
|
||||
*
|
||||
* @param indicatorTopId 指标顶级ID
|
||||
* @return 对应map key为字段名称
|
||||
*/
|
||||
Map<String, EvalItemToFieldInfo> evalMapForCsvType(Integer indicatorTopId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.hshh.indicator.entity.IndicatorCsvColumn;
|
|||
import com.hshh.system.common.bean.JsTree;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
|
|
@ -99,4 +100,14 @@ public interface IndicatorService extends IService<Indicator> {
|
|||
* @return 指标列表,topId一致
|
||||
*/
|
||||
List<Indicator> queryByTopId(Integer topId);
|
||||
|
||||
/**
|
||||
* 根据评估模板获取指标.
|
||||
*
|
||||
* @param templateId 模板 ID
|
||||
* @return 指标列表
|
||||
*/
|
||||
Indicator selectByTemplateId(@Param("templateId") Integer templateId);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package com.hshh.indicator.service.impl;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hshh.evaluation.bean.EvalItemToFieldInfo;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import com.hshh.indicator.mapper.IndicatorEvalItemMapper;
|
||||
import com.hshh.indicator.service.IndicatorEvalItemService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
|
|
@ -35,4 +37,19 @@ public class IndicatorEvalItemServiceImpl extends
|
|||
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, EvalItemToFieldInfo> evalMapForDatabaseTypeData(Integer indicatorTopId) {
|
||||
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, EvalItemToFieldInfo> evalMapForCsvType(Integer indicatorTopId) {
|
||||
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,4 +187,15 @@ public class IndicatorServiceImpl extends ServiceImpl<IndicatorMapper, Indicator
|
|||
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Indicator selectByTemplateId(Integer templateId) {
|
||||
List<Indicator> list = this.baseMapper.selectByTemplateId(templateId);
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,10 +99,13 @@ public class ModelDefineController extends BaseController {
|
|||
modelDefine.getId()));
|
||||
|
||||
} else {
|
||||
fieldList.addAll(formFieldConfigService.getFormFieldConfigByModelId(
|
||||
modelList.get(0).getId()));
|
||||
if (!modelList.isEmpty()) {
|
||||
fieldList.addAll(formFieldConfigService.getFormFieldConfigByModelId(
|
||||
modelList.get(0).getId()));
|
||||
|
||||
modelList.get(0).setChecked(true);
|
||||
}
|
||||
|
||||
modelList.get(0).setChecked(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,10 @@ public class FormFieldConfig implements Serializable {
|
|||
|
||||
@NotBlank(message = "字段名称不能为空")
|
||||
@Size(max = 50, message = "字段名称不能超过50字符")
|
||||
@Pattern(regexp = "^[A-Za-z_]+$", message = "字段ID只能包含英文字符")
|
||||
@Pattern(regexp = "^[A-Za-z_0-9]+$", message = "字段ID只能包含英文和数字字符")
|
||||
private String fieldName;
|
||||
|
||||
@NotBlank(message = "字段ID不能为空")
|
||||
@Size(max = 50, message = "字段ID不能超过50字符")
|
||||
@Pattern(regexp = "^[A-Za-z_]+$", message = "字段ID只能包含英文字符")
|
||||
|
||||
private String fieldId;
|
||||
@NotBlank(message = "字段标签不能为空")
|
||||
@Size(max = 50, message = "字段标签不能超过50字符")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.hshh.model.service;
|
|||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.model.entity.FormFieldConfig;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
|
|
@ -19,7 +20,7 @@ public interface FormFieldConfigService extends IService<FormFieldConfig> {
|
|||
* @param modelId 模型ID
|
||||
* @return 字段列表
|
||||
*/
|
||||
public List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId);
|
||||
List<FormFieldConfig> getFormFieldConfigByModelId(Integer modelId);
|
||||
|
||||
/**
|
||||
* 查询符合条件的字段列表.
|
||||
|
|
@ -30,6 +31,14 @@ public interface FormFieldConfigService extends IService<FormFieldConfig> {
|
|||
* @param id id
|
||||
* @return 结果列表
|
||||
*/
|
||||
public List<FormFieldConfig> getFormFieldConfigByLabelOrNameOrId(@NotNull Integer modelId,
|
||||
List<FormFieldConfig> getFormFieldConfigByLabelOrNameOrId(@NotNull Integer modelId,
|
||||
@NotNull String label, @NotNull String name, @NotNull String id);
|
||||
|
||||
/**
|
||||
* 获取基础设施的字段信息,按照map返回,linkedHashMap key=fieldName,value=fieldLabel.
|
||||
*
|
||||
* @param modelId 基础设施ID
|
||||
* @return 字段map
|
||||
*/
|
||||
Map<String, String> getHeaderMap(Integer modelId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||
import com.hshh.model.entity.FormFieldConfig;
|
||||
import com.hshh.model.mapper.FormFieldConfigMapper;
|
||||
import com.hshh.model.service.FormFieldConfigService;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
|
|
@ -36,4 +38,14 @@ public class FormFieldConfigServiceImpl extends
|
|||
.eq("field_id", id));
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getHeaderMap(Integer modelId) {
|
||||
Map<String, String> headerMap = new HashMap<>();
|
||||
List<FormFieldConfig> list = getFormFieldConfigByModelId(modelId);
|
||||
list.forEach(formFieldConfig -> {
|
||||
headerMap.put(formFieldConfig.getFieldName(), formFieldConfig.getFieldLabel());
|
||||
});
|
||||
return headerMap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package com.hshh.thread;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.service.impl.EvaluationProjectServiceImpl;
|
||||
import com.hshh.system.Global;
|
||||
import com.hshh.system.common.bean.SpringContextHolder;
|
||||
import com.hshh.system.common.cmd.CmdEnum;
|
||||
import com.hshh.system.common.cmd.CmdInfo;
|
||||
import java.util.Objects;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 处理系统中的任务线程.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Slf4j
|
||||
public class HandleCmdThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.interrupted()) {
|
||||
try {
|
||||
CmdInfo cmd = Global.cmdQueue.take();
|
||||
if (Objects.requireNonNull(cmd.getType()) == CmdEnum.EVALUATION) {
|
||||
evaluation(cmd);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("error:", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//评估
|
||||
private void evaluation(CmdInfo cmd) {
|
||||
|
||||
SpringContextHolder.getBean(EvaluationProjectServiceImpl.class)
|
||||
.evaluate(JSON.parseObject(cmd.getCmd(),
|
||||
EvaluationRequest.class), cmd.getUserId());
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ mybatis-plus:
|
|||
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
configuration:
|
||||
database-id: mysql
|
||||
database-id: mysql
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,4 +50,12 @@
|
|||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<select id="selectModelIdByProjectId" resultType="java.lang.Long">
|
||||
SELECT t3.indicator_model_id
|
||||
FROM m_data_evaluation_project t1
|
||||
LEFT JOIN m_data_evaluation_template t2 ON t1.template_id = t2.id
|
||||
LEFT JOIN m_data_indicator_form t3 ON t2.indicator_top_id = t3.indicator_top_id
|
||||
where t1.id = #{projectId}
|
||||
and t3.indicator_model_id is not null
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -50,4 +50,5 @@
|
|||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -10,4 +10,12 @@
|
|||
WHERE t2.top_id = #{topId} and t2.parent_id IS NOT NULL)
|
||||
order by sort_order
|
||||
</select>
|
||||
<select id="selectByTemplateId" resultType="com.hshh.indicator.entity.Indicator">
|
||||
SELECT
|
||||
t1.*
|
||||
FROM
|
||||
m_data_indicator t1
|
||||
inner join m_data_evaluation_template t2 ON t1.id = t2.indicator_top_id
|
||||
where t2.id=#{templateId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
function removeValidCss(formId) {
|
||||
|
||||
|
||||
let form = document.getElementById(formId);
|
||||
let elements = form.elements;
|
||||
for (const element of elements) {
|
||||
|
|
@ -63,17 +62,19 @@ function openDialog(id) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function disabledForm(formId) {
|
||||
let form = document.getElementById(formId);
|
||||
// 只读 input 和 textarea
|
||||
form.querySelectorAll('input, textarea').forEach(function(el) {
|
||||
form.querySelectorAll('input, textarea').forEach(function (el) {
|
||||
el.readOnly = true;
|
||||
});
|
||||
// 禁用 select 和 button
|
||||
form.querySelectorAll('select').forEach(function(el) {
|
||||
form.querySelectorAll('select').forEach(function (el) {
|
||||
el.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动填充表单,根据 JSON 数据中的 key 和嵌套对象自动拼接 name 属性进行匹配
|
||||
* @param {string} formId - 表单的 ID,例如 "myForm"
|
||||
|
|
@ -88,8 +89,6 @@ function fillForm(formId, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 递归处理 JSON 对象, 将嵌套对象的 key 拼接为点连接的形式
|
||||
* @param {Object} obj - 当前处理的 JSON 对象
|
||||
|
|
@ -102,7 +101,6 @@ function fillForm(formId, data) {
|
|||
var fullKey = prefix ? prefix + "." + key : key;
|
||||
var value = obj[key];
|
||||
|
||||
|
||||
// 如果值为对象,但不为数组,则递归处理
|
||||
if (value && typeof value === "object" && !Array.isArray(value)) {
|
||||
|
||||
|
|
@ -130,7 +128,7 @@ function fillForm(formId, data) {
|
|||
|
||||
field.value = value;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -220,7 +218,7 @@ function common_batchRemove() {
|
|||
|
||||
}
|
||||
|
||||
//分页相关
|
||||
//普通静态数据分页相关
|
||||
function _next() {
|
||||
let currentPageNum = document.getElementById("_currentPage").value;
|
||||
_setPage(parseInt(currentPageNum) + 1);
|
||||
|
|
@ -246,6 +244,17 @@ function _resetPageNoSearch() {
|
|||
_search();
|
||||
}
|
||||
|
||||
//动态数据,动态表头,动态表格 header=map record=list(map)
|
||||
function _dynamic_next(form) {
|
||||
|
||||
}
|
||||
function _dynamic_pre(form) {
|
||||
|
||||
}
|
||||
function _dynamic_resetPageNoSearch(form){
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (document.getElementById('uploadIcon') && document.getElementById(
|
||||
'fileInput')) {
|
||||
|
|
@ -352,13 +361,15 @@ function hideContextMenu() {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
function generateDraftKey() {
|
||||
// 优先用 crypto.randomUUID 生成
|
||||
if (window.crypto && window.crypto.randomUUID) {
|
||||
return 'tpl:new:' + window.crypto.randomUUID();
|
||||
}
|
||||
// 兼容老浏览器
|
||||
return 'tpl:new:' + Date.now().toString(36) + Math.random().toString(36).substring(2, 10);
|
||||
return 'tpl:new:' + Date.now().toString(36) + Math.random().toString(
|
||||
36).substring(2, 10);
|
||||
}
|
||||
|
||||
function mapToObject(map) {
|
||||
|
|
@ -368,10 +379,33 @@ function mapToObject(map) {
|
|||
}
|
||||
return obj;
|
||||
}
|
||||
function showFieldErrorTip(formId,fieldId,message){
|
||||
|
||||
function showFieldErrorTip(formId, fieldId, message) {
|
||||
let formElement = document.getElementById(formId);
|
||||
formElement.elements[fieldId].classList.add(
|
||||
"is-invalid");
|
||||
document.getElementById(
|
||||
fieldId + "_error_tip").innerHTML =message;
|
||||
fieldId + "_error_tip").innerHTML = message;
|
||||
}
|
||||
|
||||
function connectWs(url, {
|
||||
onOpen = () => {},
|
||||
onClose = () => {},
|
||||
onMessage = (msg) => {},
|
||||
onError = (err) => {}
|
||||
} = {}) {
|
||||
url = wsUrl(url);
|
||||
const ws = new WebSocket(url);
|
||||
|
||||
ws.onopen = (ev) => { onOpen(ev, ws); };
|
||||
ws.onclose = (ev) => { onClose(ev, ws); };
|
||||
ws.onmessage = (ev) => { onMessage(ev.data, ws); };
|
||||
ws.onerror = (err) => { onError(err, ws); };
|
||||
|
||||
return ws;
|
||||
}
|
||||
function wsUrl(path) {
|
||||
const loc = window.location; // 当前页面的地址
|
||||
const scheme = loc.protocol === "https:" ? "wss:" : "ws:";
|
||||
return scheme + "//" + loc.host + path;
|
||||
}
|
||||
|
|
@ -3,83 +3,82 @@
|
|||
<div class="container-xl">
|
||||
<!-- 面包屑导航 -->
|
||||
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||
<div class="row">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs" data-bs-toggle="tabs" role="tablist">
|
||||
<li class="nav-item" role="presentation" th:each="item ,stat: ${modelDefineList}">
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
th:class="'nav-link '+${item.checked?'active':''}"
|
||||
data-bs-toggle="tab"
|
||||
th:text="${item.getModelName()}"
|
||||
th:onclick="|_tabChange('${item.id}')|"></a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="tab-Content">
|
||||
<div class="tab-pane active show" role="tabpanel">
|
||||
<div class="row">
|
||||
<div class="ms-auto text-end">
|
||||
<a href="javascript:void(0)" class="btn btn-primary"
|
||||
th:onclick="|addModeDataRecord('${currentModelDefine?.id}')|">
|
||||
<!-- 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>
|
||||
<div th:replace="fragments/dialog::searchConditionDialog(${condition})"></div>
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter text-nowrap datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th class="w-1">No.
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick"
|
||||
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="M6 15l6 -6l6 6"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th th:each="item:${headerMap}" th:text="${item.value}"></th>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="item : ${result.getList()}">
|
||||
<td th:text="${item['seq']}"></td>
|
||||
<td th:each="entry : ${headerMap}" th:text="${item[entry.key]}"></td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"
|
||||
th:onclick="|editModelFieldRecord('${item['id']}')|">编辑</a>
|
||||
<a href="javascript:void(0)"
|
||||
th:onclick="|removeModelFieldRecord('${item['id']}')|">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div th:replace="fragments/dialog::paginationDialog(${result})"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-8">
|
||||
|
||||
|
||||
<div class="mb-3 row">
|
||||
<label class="col-2 col-form-label">基础设施</label>
|
||||
<div class="col-6">
|
||||
<label>
|
||||
<select class="form-select" id="modelId" onchange="_tabChange(this.value)">
|
||||
<option>--请选择基础设施--</option>
|
||||
<option th:each="item ,stat: ${modelDefineList}" th:text="${item.getModelName()}"
|
||||
th:value="${item.id}" th:selected="${item.checked}"></option>
|
||||
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
|
||||
<div class="card-actions">
|
||||
<a href="javascript:void(0)" class="btn btn-primary" onclick="addModeDataRecord()">
|
||||
<!-- 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 th:replace="fragments/dialog::searchConditionDialog(${condition})"></div>
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter text-nowrap datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th class="w-1">No.
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick"
|
||||
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="M6 15l6 -6l6 6"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th th:each="item:${headerMap}" th:text="${item.value}"></th>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="item : ${result?.getList()}">
|
||||
<td th:text="${item['seq']}"></td>
|
||||
<td th:each="entry : ${headerMap}" th:text="${item[entry.key]}"></td>
|
||||
<td>
|
||||
<a href="javascript:void(0)"
|
||||
th:onclick="|editModelFieldRecord('${item['id']}')|">编辑</a>
|
||||
<a href="javascript:void(0)"
|
||||
th:onclick="|removeModelFieldRecord('${item['id']}')|">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div th:if="${result!=null}" th:replace="fragments/dialog::paginationDialog(${result})"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -91,12 +90,12 @@
|
|||
</form>
|
||||
<form id="dataExtendForm">
|
||||
<input type="hidden" name="id" id="id">
|
||||
<input type="hidden" name="modelDefineId" id="modelDefineId" th:value="${currentModelDefine.id}">
|
||||
<input type="hidden" name="modelDefineId" id="modelDefineId" th:value="${currentModelDefine?.id}">
|
||||
</form>
|
||||
<script>
|
||||
//增加模型数据的实际表单记录
|
||||
function addModeDataRecord(modelId, data) {
|
||||
|
||||
function addModeDataRecord( data) {
|
||||
let modelId = document.getElementById( "modelId" ).value;
|
||||
let url = document.getElementById("_rootPath").value + "data/getForm/" + modelId;
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (error, res, xhr) {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,29 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div th:fragment="addFullScreenFormDialogNoBtn" id="addFormDialog-no-btn">
|
||||
|
||||
<div class="modal modal-blur fade" id="modal-full-width-no-btn" tabindex="-1" role="dialog"
|
||||
aria-hidden="true" >
|
||||
<div class="modal-dialog modal-full-width modal-dialog-centered modal-dialog-scrollable"
|
||||
role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addFormDialog-model-title-no-btn"></h5>
|
||||
<button type="button" class="btn-close"
|
||||
onclick="closeDialog('modal-full-width-no-btn')"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="add-full-screen-form-modal-body-no-btn" >
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- form add对话框 简单form操作,居中对话框-->
|
||||
<div th:fragment="addSimpleFormDialog" id="addSimpleFormDialog">
|
||||
|
|
@ -113,12 +136,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div th:fragment="paginationDialog(data)" id="paginationDialog">
|
||||
<div class="card-footer d-flex align-items-center" th:if="${data.total>0}">
|
||||
<div class="card-footer d-flex align-items-center" th:if="${data?.total>0}">
|
||||
<p class="m-0 text-muted"> 共 <span
|
||||
th:text="${data.total}"></span>条
|
||||
th:text="${data?.total}"></span>条
|
||||
记录</p>
|
||||
<ul class="pagination m-0 ms-auto">
|
||||
<li th:class="${data.isHasPrevious()}?'page-item':'page-item disabled'">
|
||||
<li th:class="${data?.isHasPrevious()}?'page-item':'page-item disabled'">
|
||||
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"
|
||||
onclick="_pre()">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
|
||||
|
|
@ -158,7 +181,7 @@
|
|||
<div class="card-body border-bottom py-3">
|
||||
<form id="searchForm">
|
||||
<input type="hidden" id="_currentPage" name="currentPage"
|
||||
th:value="${condition.currentPage}"/>
|
||||
th:value="${condition?.currentPage}"/>
|
||||
<div class="card-body border-bottom py-3">
|
||||
|
||||
<div class="d-flex">
|
||||
|
|
@ -166,16 +189,16 @@
|
|||
显示
|
||||
<div class="mx-2 d-inline-block">
|
||||
<input type="text" class="form-control form-control-sm"
|
||||
th:value="${condition.pageSize}" size="3"
|
||||
th:value="${condition?.pageSize}" size="3"
|
||||
name="pageSize">
|
||||
</div>
|
||||
对象
|
||||
记录/每页
|
||||
</div>
|
||||
<div class="ms-auto text-muted">
|
||||
|
||||
<div class="input-group mb-2">
|
||||
<input type="text" class="form-control" placeholder="名称/编码" id="search"
|
||||
name="search" th:value="${condition.search}">
|
||||
name="search" th:value="${condition?.search}">
|
||||
<button class="btn" type="button" onclick="_resetPageNoSearch()">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -196,4 +219,63 @@
|
|||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div th:fragment="datasetForListMap(formId,headerMap,result,condition)" id="dataset_list_map_table_page">
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="d-flex">
|
||||
<div class="text-muted">
|
||||
显示
|
||||
<div class="mx-2 d-inline-block">
|
||||
<input type="text" class="form-control form-control-sm" name="pageSize" th:value="${condition?.pageSize}" size="3" aria-label="Invoices count">
|
||||
</div>
|
||||
记录/每页
|
||||
</div>
|
||||
<div class="ms-auto text-muted">
|
||||
|
||||
<div class="input-group mb-2">
|
||||
<label>
|
||||
<input type="text" class="form-control" placeholder="名称/编码"
|
||||
name="search" th:value="${condition?.search}">
|
||||
</label>
|
||||
<button class="btn" type="button" th:attr="data-form-id=${#strings.escapeJavaScript(formId)}" onclick="_dynamic_resetPageNoSearch(this.dataset.formId)">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive" style="min-height: 20em;">
|
||||
<table class="table card-table table-vcenter text-nowrap datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">No. <!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick" 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 d="M6 15l6 -6l6 6" /></svg>
|
||||
</th>
|
||||
<th th:each="item:${headerMap}" th:text="${item.value}"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="item : ${result?.getList()}">
|
||||
<td th:text="${item['seq']}"></td>
|
||||
<td th:each="entry : ${headerMap}" th:text="${item[entry.key]}"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
|
||||
<ul class="pagination m-0 ms-auto">
|
||||
<li class="page-item disabled">
|
||||
<a th:class="${result?.isHasPrevious()}?'page-item':'page-item disabled'" href="javascript:void(0)" tabindex="-1" aria-disabled="true" >
|
||||
|
||||
<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 d="M15 6l-6 6l6 6" /></svg>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a th:class="${result?.isHasNext()}?'page-item':'page-item disabled'" href="javascript:void(0)" >
|
||||
|
||||
<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 d="M9 6l6 6l-6 6" /></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@
|
|||
<div id="alert-area"
|
||||
style="position: fixed; left: 50%; top: 20px; transform: translateX(-50%); z-index: 9999; width: 400px; max-width: 90vw;">
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="_userId_" id="_userId_" th:value="${user?.id}">
|
||||
<script th:src="@{/js/jquery.min.js}"></script>
|
||||
<script th:src="@{/js/tabler.min.js}"></script>
|
||||
<script th:src="@{/js/htmx.min.js}"></script>
|
||||
|
|
@ -267,6 +267,7 @@
|
|||
<script th:src="@{/js/common/common.js}"></script>
|
||||
<script th:src="@{/js/HttpClient.js}"></script>
|
||||
<script th:src="@{/js/d3.v7.min.js}"></script>
|
||||
|
||||
<script>
|
||||
|
||||
let d3TreeData = null;
|
||||
|
|
@ -335,8 +336,23 @@
|
|||
}
|
||||
|
||||
}
|
||||
if(evt.detail.target.querySelector('[data-page="evaluation_list"]')){
|
||||
if(typeof initEvaluationList === 'function'){
|
||||
|
||||
initEvaluationList();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
document.body.addEventListener("htmx:beforeCleanupElement", (evt) => {
|
||||
console.log(1);
|
||||
// during_log 所在的根容器被清理时,关掉 WS
|
||||
// if (evt.detail.target&&evt.detail.target.querySelector('[data-page="project"]')) {
|
||||
//
|
||||
// if (evaluationWs && evaluationWs.readyState === WebSocket.OPEN) evaluationWs.close(1000, "htmx cleanup");
|
||||
// evaluationWs = null;
|
||||
// }
|
||||
}, { once: true });
|
||||
|
||||
const RECIP = {
|
||||
"9":"0.11111","8":"0.125","7":"0.14286","6":"0.16667","5":"0.2","4":"0.25","3":"0.3333","2":"0.5","1":"1",
|
||||
|
|
|
|||
|
|
@ -6,12 +6,17 @@
|
|||
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">名称:</label>
|
||||
<label class="form-label required" for="evaluationName">名称:</label>
|
||||
<input type="text" class="form-control" name="evaluationName" id="evaluationName"
|
||||
placeholder="名称">
|
||||
<div class="invalid-feedback" id="evaluationName_error_tip"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label required" for="grade">分值:</label>
|
||||
<input type="text" class="form-control" name="grade" id="grade"
|
||||
placeholder="对应分值(百分值)">
|
||||
<div class="invalid-feedback" id="grade_error_tip"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label required" for="minSymbol">符号:</label>
|
||||
<select name="minSymbol" id="minSymbol" class="form-select">
|
||||
|
|
@ -26,7 +31,7 @@
|
|||
<div class="invalid-feedback" id="minSymbol_error_tip"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">值(下限):</label>
|
||||
<label class="form-label required" for="minValue">值(下限):</label>
|
||||
<input type="text" class="form-control" name="minValue" id="minValue"
|
||||
placeholder="开始值">
|
||||
<div class="invalid-feedback" id="minValue_error_tip"></div>
|
||||
|
|
@ -45,7 +50,7 @@
|
|||
<div class="invalid-feedback" id="maxSymbol_error_tip"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">值(上限):</label>
|
||||
<label class="form-label required" for="maxValue">值(上限):</label>
|
||||
<input type="text" class="form-control" name="maxValue" id="maxValue"
|
||||
placeholder="开始值">
|
||||
<div class="invalid-feedback" id="maxValue_error_tip"></div>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
<div class="mb-3 row align-items-center">
|
||||
<label class="col-3 col-form-label fw-semibold" for="indicationTopId">指标列表</label>
|
||||
<div class="col">
|
||||
<select class="form-select" name="indicationTopId" id="indicationTopId">
|
||||
<option th:each="item:${rootList}" th:value="${item.id}" th:text="${item.name}"></option>
|
||||
<select class="form-select" name="indicationTopId" id="indicationTopId" onchange="changeIndicator()">
|
||||
<option value="">--请选择指标--</option>
|
||||
<option th:each="item:${rootList}" th:value="${item.id}" th:text="${item.name}" th:selected="${item.checked}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto text-muted small">选定后,下方“评价集设置”将随之变化</div>
|
||||
|
|
@ -105,14 +106,16 @@
|
|||
|
||||
<script>
|
||||
// 交互时给重点卡片一个轻微高亮
|
||||
(function(){
|
||||
function initEvaluationList() {
|
||||
|
||||
const card = document.querySelector('.card-priority');
|
||||
const topSel = document.getElementById('indicationTopId');
|
||||
topSel?.addEventListener('change', ()=>{
|
||||
card.classList.add('flash');
|
||||
setTimeout(()=>card.classList.remove('flash'), 900);
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
function evaluation_add(data) {
|
||||
let url = document.getElementById("_rootPath").value + "evaluation/evaluationAdd";
|
||||
|
|
@ -123,7 +126,7 @@
|
|||
if (data) {
|
||||
fillData(data);
|
||||
} else {
|
||||
let topId = $('input[name="radios-inline"]:checked').val();
|
||||
let topId =document.getElementById("indicationTopId").value;
|
||||
let indicationId = $('input[name="radios-inline-indicator-no-child"]:checked').val();
|
||||
document.getElementById("evaluationForm")['indicatorTopId'].value = topId;
|
||||
document.getElementById("evaluationForm")['indicatorId'].value = indicationId;
|
||||
|
|
@ -142,7 +145,7 @@
|
|||
let form = document.getElementById("evaluationForm");
|
||||
http.post(url, formObjToObject(form), function (err, res, xhr) {
|
||||
closeDialog("simple-form-model");
|
||||
let topId = $('input[type=radio][name="radios-inline"]:checked').val();
|
||||
let topId = document.getElementById("indicationTopId").value;
|
||||
let subId = $('input[name="radios-inline-indicator-no-child"]:checked').val();
|
||||
document.getElementById("_evaluation_evaluationList")
|
||||
.setAttribute("hx-vals", JSON.stringify({topIndicatorId: topId, indicatorId: subId}));
|
||||
|
|
@ -169,10 +172,11 @@
|
|||
}
|
||||
|
||||
function changeIndicator(){
|
||||
let topId = $('input[name="radios-inline"]:checked').val();
|
||||
let topId =document.getElementById("indicationTopId").value;
|
||||
let subId = $('input[name="radios-inline-indicator-no-child"]:checked').val();
|
||||
document.getElementById("_evaluation_evaluationList")
|
||||
.setAttribute("hx-vals", JSON.stringify({topIndicatorId: topId, indicatorId: subId}));
|
||||
document.getElementById("_evaluation_evaluationList").click();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<label for="indicationId" class="form-label m-0">根指标</label>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3">
|
||||
<select id="indicationId" class="form-select" name="indicationId">
|
||||
<select id="indicationId" class="form-select" name="indicationId" onchange="indicatorTopIdChange()">
|
||||
<option value="0">-选择根指标-</option>
|
||||
<option th:each="item:${rootList}" th:value="${item.id}"
|
||||
th:text="${item.getName()}" th:selected="${item.checked}"></option>
|
||||
|
|
@ -116,9 +116,9 @@
|
|||
</thead>
|
||||
|
||||
<tbody class="autonum">
|
||||
<tr th:each="item:${childrenIndicator}">
|
||||
<tr th:each="item,stat:${childrenIndicator}">
|
||||
<input type="hidden" name="indicatorId" th:value="${item.getId()}">
|
||||
<td class="sticky-body-col-1 w-compact col-index"></td>
|
||||
<td class="sticky-body-col-1 w-compact col-index" th:text="${stat.count}"></td>
|
||||
<td class="sticky-body-col-2 col-name" th:text="${item.getName()}"></td>
|
||||
|
||||
<td>
|
||||
|
|
@ -261,4 +261,10 @@
|
|||
hero.classList.add('flash');
|
||||
setTimeout(()=>hero.classList.remove('flash'), 900);
|
||||
}
|
||||
function indicatorTopIdChange() {
|
||||
let topId = $('#indicationId').val();
|
||||
document.getElementById("_indicator_mapper")
|
||||
.setAttribute("hx-vals", JSON.stringify({indicatorTopId: topId,}));
|
||||
document.getElementById("_indicator_mapper").click();
|
||||
}
|
||||
</script>
|
||||
|
|
@ -123,7 +123,17 @@
|
|||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-body.search-bar {
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
background: #f6f8fb; /* 可选 */
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.card-body.list-area {
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="page-body" data-page="metric">
|
||||
|
|
@ -146,7 +156,22 @@
|
|||
增加根指标
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body" id="type_list">
|
||||
<div class="card-body search-bar" >
|
||||
<div class="input-icon ">
|
||||
<input type="text" value="" class="form-control" placeholder="Search…">
|
||||
<span class="input-icon-addon">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
|
||||
<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="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0"></path><path
|
||||
d="M21 21l-6 -6"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" id="type_list" style="max-height: 50em; overflow-y: scroll;">
|
||||
|
||||
<div class="d-flex align-items-center mb-2" th:each="item, iterStat : ${rootList}"
|
||||
th:id="${item.id+'_indicator'}">
|
||||
|
|
@ -190,11 +215,13 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9" id="tree-container" style="padding-left:0; min-height: 50em ;max-height: 60em ">
|
||||
<div class="col-md-9" id="tree-container"
|
||||
style="padding-left:0; min-height: 60em ;max-height: 60em ">
|
||||
<div class="tree-toolbar" id="tree-toolbar">
|
||||
<button id="zoom-in" title="放大" class="btn btn-sm btn-outline-primary">+</button>
|
||||
<button id="zoom-out" title="缩小" class="btn btn-sm btn-outline-primary">-</button>
|
||||
<button id="zoom-reset" title="重置" class="btn btn-sm btn-outline-secondary">重置</button>
|
||||
<button id="zoom-reset" title="重置" class="btn btn-sm btn-outline-secondary">重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -206,11 +233,11 @@
|
|||
</form>
|
||||
<script>
|
||||
//编辑根指标
|
||||
function editTopIndictorData(flag,id) {
|
||||
function editTopIndictorData(flag, id) {
|
||||
let url = document.getElementById("_rootPath").value + "indicator/" + id;
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (err, res, xhr) {
|
||||
addIndicator(flag,res.result);
|
||||
addIndicator(flag, res.result);
|
||||
}, 'indicatorForm')
|
||||
}
|
||||
|
||||
|
|
@ -224,9 +251,10 @@
|
|||
}
|
||||
|
||||
//导航到增加页面
|
||||
function addIndicator(flag,data) {
|
||||
function addIndicator(flag, data) {
|
||||
|
||||
let url = document.getElementById("_rootPath").value + "indicator/indicatorAdd?rootFlag="+flag;
|
||||
let url = document.getElementById("_rootPath").value + "indicator/indicatorAdd?rootFlag="
|
||||
+ flag;
|
||||
let http = new HttpClient()
|
||||
http.get(url, function (error, res, xhr) {
|
||||
document.getElementById("simpleFormBody").innerHTML = res;
|
||||
|
|
@ -264,16 +292,16 @@
|
|||
}
|
||||
|
||||
function handleMenuAction(action, nodeData) {
|
||||
console.log(nodeData)
|
||||
|
||||
if (action === "add") {
|
||||
if (!nodeData.topId) {//根节点
|
||||
nodeData.topId = nodeData.id;
|
||||
}
|
||||
addIndicator(false,{"parentId": nodeData.id, "topId": nodeData.topId});
|
||||
addIndicator(false, {"parentId": nodeData.id, "topId": nodeData.topId});
|
||||
|
||||
} else if (action === "edit") {
|
||||
|
||||
editTopIndictorData(false,nodeData.id);
|
||||
editTopIndictorData(false, nodeData.id);
|
||||
|
||||
} else if (action === "delete") {
|
||||
removeTopIndictorData(nodeData.id);
|
||||
|
|
@ -312,7 +340,7 @@
|
|||
|
||||
const nodeCount = root.descendants().length;
|
||||
const width = Math.max(800, 120 * nodeCount);
|
||||
const height = Math.max(400, 130 * (root.height + 1));
|
||||
const height = Math.max(800, 130 * (root.height + 1));
|
||||
const marginTop = 60;
|
||||
|
||||
const treeLayout = d3.tree()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<input type="hidden" name="dataModelId" id="dataModelId" value="">
|
||||
<div class="col-md-6 ">
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">标签</label>
|
||||
<label class="form-label required">中文名称</label>
|
||||
<input type="text" name="fieldLabel" id="fieldLabel" class="form-control" placeholder="标签"
|
||||
autocomplete="off"
|
||||
value="">
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
<div class="col-md-6 ">
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">name</label>
|
||||
<label class="form-label required">英文名称</label>
|
||||
<input type="text" name="fieldName" id="fieldName" class="form-control"
|
||||
placeholder="name 必须是英文" autocomplete="off"
|
||||
value="">
|
||||
|
|
@ -29,31 +29,31 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">默认值</label>-->
|
||||
<!-- <input type="text" name="fieldDefaultValue" id="fieldDefaultValue" class="form-control"-->
|
||||
<!-- placeholder="字段默认值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldDefaultValue_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">输入提示</label>-->
|
||||
<!-- <input type="text" name="fieldPlaceholder" id="fieldPlaceholder" class="form-control"-->
|
||||
<!-- placeholder="输入提示" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldPlaceholder_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">默认值</label>-->
|
||||
<!-- <input type="text" name="fieldDefaultValue" id="fieldDefaultValue" class="form-control"-->
|
||||
<!-- placeholder="字段默认值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldDefaultValue_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">输入提示</label>-->
|
||||
<!-- <input type="text" name="fieldPlaceholder" id="fieldPlaceholder" class="form-control"-->
|
||||
<!-- placeholder="输入提示" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldPlaceholder_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="col-md-6 ">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">单位</label>
|
||||
<select name="fieldUnit" id="fieldUnit" class="form-control">
|
||||
<option value="">无</option>
|
||||
<option th:each="item: ${items}" th:value="${item.nameCn}" th:text="${item.nameCn}">
|
||||
<label class="form-label" for="fieldUnit">单位</label>
|
||||
|
||||
<input type="text" name="fieldUnit" id="fieldUnit" class="form-control"
|
||||
placeholder="输入单位" autocomplete="off"
|
||||
value="">
|
||||
<div class="invalid-feedback" id="fieldUnit_error_tip"></div>
|
||||
|
||||
</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -62,139 +62,139 @@
|
|||
<label class="form-label">类型</label>
|
||||
<select name="fieldType" id="fieldType" class="form-control">
|
||||
<option value="TEXT">单行文本输入</option>
|
||||
<!-- <option value="TEXTAREA">多行文本输入</option>-->
|
||||
<!-- <option value="PASSWORD">密码输入</option>-->
|
||||
<!-- <option value="TEXTAREA">多行文本输入</option>-->
|
||||
<!-- <option value="PASSWORD">密码输入</option>-->
|
||||
<option value="NUMBER">数字输入</option>
|
||||
<!-- <option value="EMAIL">邮箱输入</option>-->
|
||||
<!-- <option value="SELECT">下拉选择</option>-->
|
||||
<!-- <option value="RADIO">单选框</option>-->
|
||||
<!-- <option value="CHECKBOX">多选框</option>-->
|
||||
<!-- <option value="DATE">日期选择</option>-->
|
||||
<!-- <option value="DATETIME">日期时间选择</option>-->
|
||||
<!-- <option value="TIME">时间选择</option>-->
|
||||
<!-- <option value="FILE">文件上传</option>-->
|
||||
<!-- <option value="IMAGE">图片上传</option>-->
|
||||
<!-- <option value="URL">链接输入</option>-->
|
||||
<!-- <option value="COLOR">颜色选择器</option>-->
|
||||
<!-- <option value="TEL">电话输入</option>-->
|
||||
<!-- <option value="HIDDEN">隐藏字段</option>-->
|
||||
<!-- <option value="EMAIL">邮箱输入</option>-->
|
||||
<!-- <option value="SELECT">下拉选择</option>-->
|
||||
<!-- <option value="RADIO">单选框</option>-->
|
||||
<!-- <option value="CHECKBOX">多选框</option>-->
|
||||
<!-- <option value="DATE">日期选择</option>-->
|
||||
<!-- <option value="DATETIME">日期时间选择</option>-->
|
||||
<!-- <option value="TIME">时间选择</option>-->
|
||||
<!-- <option value="FILE">文件上传</option>-->
|
||||
<!-- <option value="IMAGE">图片上传</option>-->
|
||||
<!-- <option value="URL">链接输入</option>-->
|
||||
<!-- <option value="COLOR">颜色选择器</option>-->
|
||||
<!-- <option value="TEL">电话输入</option>-->
|
||||
<!-- <option value="HIDDEN">隐藏字段</option>-->
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">码表选项</label>-->
|
||||
<!-- <select name="fieldOptionsId" id="fieldOptionsId" class="form-control">-->
|
||||
<!-- <option value="0">无</option>-->
|
||||
<!-- <option th:each="type:${typeList}" th:text="${type.dictTypeName}"-->
|
||||
<!-- th:value="${type.id}"></option>-->
|
||||
<!-- </select>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">码表选项</label>-->
|
||||
<!-- <select name="fieldOptionsId" id="fieldOptionsId" class="form-control">-->
|
||||
<!-- <option value="0">无</option>-->
|
||||
<!-- <option th:each="type:${typeList}" th:text="${type.dictTypeName}"-->
|
||||
<!-- th:value="${type.id}"></option>-->
|
||||
<!-- </select>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">只读</label>-->
|
||||
<!-- <select name="readonlyFlag" id="readonlyFlag" class="form-control">-->
|
||||
<!-- <option value="0">非只读</option>-->
|
||||
<!-- <option value="1">只读</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">只读</label>-->
|
||||
<!-- <select name="readonlyFlag" id="readonlyFlag" class="form-control">-->
|
||||
<!-- <option value="0">非只读</option>-->
|
||||
<!-- <option value="1">只读</option>-->
|
||||
<!-- </select>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">禁用</label>-->
|
||||
<!-- <select name="disabledFlag" id="disabledFlag" class="form-control">-->
|
||||
<!-- <option value="0">非禁用</option>-->
|
||||
<!-- <option value="1">禁用</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">禁用</label>-->
|
||||
<!-- <select name="disabledFlag" id="disabledFlag" class="form-control">-->
|
||||
<!-- <option value="0">非禁用</option>-->
|
||||
<!-- <option value="1">禁用</option>-->
|
||||
<!-- </select>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">自动完成</label>-->
|
||||
<!-- <select name="autocompleteFlag" id="autocompleteFlag" class="form-control">-->
|
||||
<!-- <option value="0">非</option>-->
|
||||
<!-- <option value="1">是</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">自动完成</label>-->
|
||||
<!-- <select name="autocompleteFlag" id="autocompleteFlag" class="form-control">-->
|
||||
<!-- <option value="0">非</option>-->
|
||||
<!-- <option value="1">是</option>-->
|
||||
<!-- </select>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">显示</label>-->
|
||||
<!-- <select name="hiddenFlag" id="hiddenFlag" class="form-control">-->
|
||||
<!-- <option value="0">显示</option>-->
|
||||
<!-- <option value="1">不显示</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">显示</label>-->
|
||||
<!-- <select name="hiddenFlag" id="hiddenFlag" class="form-control">-->
|
||||
<!-- <option value="0">显示</option>-->
|
||||
<!-- <option value="1">不显示</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">format函数</label>-->
|
||||
<!-- <input type="text" name="formatFunc" id="formatFunc" class="form-control"-->
|
||||
<!-- placeholder="format函数" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="formatFunc_error_tip"></div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">format函数</label>-->
|
||||
<!-- <input type="text" name="formatFunc" id="formatFunc" class="form-control"-->
|
||||
<!-- placeholder="format函数" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="formatFunc_error_tip"></div>-->
|
||||
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">正则表达式</label>-->
|
||||
<!-- <input type="text" name="validateRule" id="validateRule" class="form-control"-->
|
||||
<!-- placeholder="正则表达式" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="validateRule_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">正则表达提示</label>-->
|
||||
<!-- <input type="text" name="validateRuleMessage" id="validateRuleMessage" class="form-control"-->
|
||||
<!-- placeholder="正则表达提示" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="validateRuleMessage_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">长度最小值(文本型)</label>-->
|
||||
<!-- <input type="number" name="fieldMinSize" id="fieldMinSize" class="form-control"-->
|
||||
<!-- placeholder="字段长度最小值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMinSize_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">长度最大值(文本型)</label>-->
|
||||
<!-- <input type="number" name="fieldMaxSize" id="fieldMaxSize" class="form-control"-->
|
||||
<!-- placeholder="字段长度最大值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMaxSize_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">最小值(数值型)</label>-->
|
||||
<!-- <input type="number" name="fieldMinVal" id="fieldMinVal" class="form-control"-->
|
||||
<!-- placeholder="字段最小值(数值型)" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMinVal_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">最大值(数值型)</label>-->
|
||||
<!-- <input type="number" name="fieldMaxVal" id="fieldMaxVal" class="form-control"-->
|
||||
<!-- placeholder="字段最大值(数值型)" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMaxVal_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">正则表达式</label>-->
|
||||
<!-- <input type="text" name="validateRule" id="validateRule" class="form-control"-->
|
||||
<!-- placeholder="正则表达式" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="validateRule_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">正则表达提示</label>-->
|
||||
<!-- <input type="text" name="validateRuleMessage" id="validateRuleMessage" class="form-control"-->
|
||||
<!-- placeholder="正则表达提示" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="validateRuleMessage_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">长度最小值(文本型)</label>-->
|
||||
<!-- <input type="number" name="fieldMinSize" id="fieldMinSize" class="form-control"-->
|
||||
<!-- placeholder="字段长度最小值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMinSize_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">长度最大值(文本型)</label>-->
|
||||
<!-- <input type="number" name="fieldMaxSize" id="fieldMaxSize" class="form-control"-->
|
||||
<!-- placeholder="字段长度最大值" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMaxSize_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">最小值(数值型)</label>-->
|
||||
<!-- <input type="number" name="fieldMinVal" id="fieldMinVal" class="form-control"-->
|
||||
<!-- placeholder="字段最小值(数值型)" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMinVal_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-md-6 ">-->
|
||||
<!-- <div class="mb-3">-->
|
||||
<!-- <label class="form-label">最大值(数值型)</label>-->
|
||||
<!-- <input type="number" name="fieldMaxVal" id="fieldMaxVal" class="form-control"-->
|
||||
<!-- placeholder="字段最大值(数值型)" value="" autocomplete="off">-->
|
||||
<!-- <div class="invalid-feedback" id="fieldMaxVal_error_tip"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div class="col-md-6 ">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">显示顺序</label>
|
||||
<input type="number" name="sortOrder" id="sortOrder" class="form-control"
|
||||
placeholder="显示顺序" autocomplete="off" value="1">
|
||||
placeholder="显示顺序" autocomplete="off" value="1">
|
||||
<div class="invalid-feedback" id="sortOrder_error_tip"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,17 @@
|
|||
<!-- Page body -->
|
||||
<style>
|
||||
.card-body.search-bar {
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
background: #f6f8fb; /* 可选 */
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.card-body.list-area {
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<!-- 面包屑导航 -->
|
||||
|
|
@ -21,7 +34,22 @@
|
|||
增加设施
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body" id="type_list">
|
||||
<div class="card-body search-bar" >
|
||||
<div class="input-icon ">
|
||||
<input type="text" value="" class="form-control" placeholder="Search…">
|
||||
<span class="input-icon-addon">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/search -->
|
||||
<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="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0"></path><path
|
||||
d="M21 21l-6 -6"></path></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" id="type_list" style="max-height: 50em; overflow-y: scroll;">
|
||||
|
||||
|
||||
<div class="d-flex align-items-center mb-2" th:each="item, iterStat : ${modelList}"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
<input type="hidden" name="modelId" th:value="${modelId}" />
|
||||
<input type="hidden" name="projectId" th:value="${projectId}" />
|
||||
<input type="hidden" name="datasource" value="csv" />
|
||||
<input type="hidden" name="search" th:value="${search}" />
|
||||
<input type="hidden" name="randomKey" th:value="${randomKey}" />
|
||||
<input type="hidden" name="method" th:value="${method}" />
|
||||
<div class="row align-items-center mt-3 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" style="width: 66%" role="progressbar" aria-valuenow="66" aria-valuemin="0" aria-valuemax="100" aria-label="66% Complete">
|
||||
<span class="visually-hidden">66% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="javascript:void(0)" class="btn btn-info" onclick="">
|
||||
上一步
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-success" onclick="selectedDatasource()">
|
||||
下一步
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="min-height: 20em;">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">CSV文件</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<div class="form-label">选择上传文件</div>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"></h3>
|
||||
</div>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="d-flex">
|
||||
<div class="text-muted">
|
||||
Show
|
||||
<div class="mx-2 d-inline-block">
|
||||
<input type="text" class="form-control form-control-sm" value="8" size="3" aria-label="Invoices count">
|
||||
</div>
|
||||
entries
|
||||
</div>
|
||||
<div class="ms-auto text-muted">
|
||||
Search:
|
||||
<div class="ms-2 d-inline-block">
|
||||
<input type="text" class="form-control form-control-sm" aria-label="Search invoice">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table card-table table-vcenter text-nowrap datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1"><input class="form-check-input m-0 align-middle" type="checkbox" aria-label="Select all invoices"></th>
|
||||
<th class="w-1">No. <!-- Download SVG icon from http://tabler-icons.io/i/chevron-up -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-sm icon-thick" 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 d="M6 15l6 -6l6 6" /></svg>
|
||||
</th>
|
||||
<th>Invoice Subject</th>
|
||||
<th>Client</th>
|
||||
<th>VAT No.</th>
|
||||
<th>Created</th>
|
||||
<th>Status</th>
|
||||
<th>Price</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<input type="hidden" name="modelId" th:value="${modelId}" />
|
||||
<input type="hidden" name="projectId" th:value="${projectId}" />
|
||||
<input type="hidden" name="templateId" th:value="${templateId}" />
|
||||
<input type="hidden" name="datasource" value="database" />
|
||||
<input type="hidden" name="search" th:value="${search}" />
|
||||
<input type="hidden" name="randomKey" th:value="${randomKey}" />
|
||||
<input type="hidden" name="method" th:value="${method}" />
|
||||
<div class="row align-items-center mt-3 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" style="width: 66%" role="progressbar" aria-valuenow="66" aria-valuemin="0" aria-valuemax="100" aria-label="66% Complete">
|
||||
<span class="visually-hidden">66% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="javascript:void(0)" class="btn btn-info" onclick="">
|
||||
上一步
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-success" onclick="processEvaluation()">
|
||||
下一步
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="min-height: 20em;">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">数据库记录</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"></h3>
|
||||
</div>
|
||||
<div th:replace="fragments/dialog::datasetForListMap('stepForm',${headerMap},${result},${condition})"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<div class="row align-items-center mt-3 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" style="width: 33%" role="progressbar" aria-valuenow="33" aria-valuemin="0" aria-valuemax="100" aria-label="33% Complete">
|
||||
<span class="visually-hidden">33% Complete</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
|
||||
<a href="javascript:void(0)" class="btn btn-primary" th:onclick="|selectedDatasource(${projectId})|">
|
||||
下一步
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="projectId" id="projectId" th:value="${projectId}">
|
||||
<input type="hidden" name="randomKey" id="randomKey" th:value="${randomKey}">
|
||||
<div class="card" style="min-height: 20em;">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">选择数据源/评价方法</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="mb-3">
|
||||
<div class="form-label">数据源</div>
|
||||
<div>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="datasource_type" checked="" value="database">
|
||||
<span class="form-check-label">数据库</span>
|
||||
</label>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="datasource_type" value="dataCsv">
|
||||
<span class="form-check-label">CSV</span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-label">评价方法</div>
|
||||
<div>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod" checked="" value="WEIGHTED_AVERAGE">
|
||||
<span class="form-check-label">加权平均(∑ wᵢ·sᵢ)</span>
|
||||
</label>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod" value="FUZZY_AVERAGE">
|
||||
<span class="form-check-label">模糊平均/模糊综合</span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="page-body" data-page="project">
|
||||
<div class="container-xl">
|
||||
<!-- 面包屑导航 -->
|
||||
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||
|
|
@ -83,8 +83,8 @@
|
|||
<div th:replace="fragments/dialog::addSimpleFormDialog"></div>
|
||||
</form>
|
||||
<form id="stepForm">
|
||||
<input type="hidden" id="projectId" name="projectId">
|
||||
<div th:replace="fragments/dialog::addFullScreenFormDialog"></div>
|
||||
|
||||
<div th:replace="fragments/dialog::addFullScreenFormDialogNoBtn"></div>
|
||||
</form>
|
||||
<script>
|
||||
|
||||
|
|
@ -103,7 +103,6 @@
|
|||
document.getElementById("simpleFormBody").innerHTML = res;
|
||||
openDialog("simple-form-model");
|
||||
|
||||
|
||||
document.getElementById("SimpleFormDialog_save").onclick = function () {
|
||||
saveProject();
|
||||
}
|
||||
|
|
@ -120,8 +119,6 @@
|
|||
}, "projectForm", "simple-form-model")
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _projectDelete(id) {
|
||||
openDialog("modal-danger");
|
||||
document.getElementById('delete-confirm-9999').onclick = function () {
|
||||
|
|
@ -134,14 +131,133 @@
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _projectHistory(id) {
|
||||
|
||||
}
|
||||
|
||||
function _startEvaluation(id){
|
||||
function _startEvaluation(id) {
|
||||
let randomKey = generateDraftKey().replace("tpl:new:", "")
|
||||
let url = document.getElementById("_rootPath").value
|
||||
+ "evaluation/project/selectDatasourceType?projectId=" + id + "&randomKey=" + randomKey;
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (error, response, xhr) {
|
||||
|
||||
openDialog("modal-full-width-no-btn");
|
||||
document.getElementById("add-full-screen-form-modal-body-no-btn").innerHTML = response;
|
||||
|
||||
}, null,)
|
||||
}
|
||||
|
||||
//选择了数据源后触发
|
||||
function selectedDatasource(projectId) {
|
||||
//获取选中的数据源
|
||||
|
||||
let value = $('input[name="datasource_type"]:checked').val();
|
||||
let method = $('input[name="aggregationMethod"]:checked').val();
|
||||
var url = "";
|
||||
if (value === 'database') {
|
||||
url = document.getElementById("_rootPath").value + "evaluation/project/database?id="
|
||||
+ projectId + "&randomKey=" + document.getElementById("stepForm")['randomKey'].value+"&method=" + method;
|
||||
}
|
||||
if (value === 'dataCsv') {
|
||||
url = document.getElementById("_rootPath").value + "evaluation/project/csv?id=" + projectId
|
||||
+ "&randomKey=" + document.getElementById("stepForm")['randomKey'].value+"&method="+method;
|
||||
}
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (error, response, xhr) {
|
||||
openDialog("modal-full-width-no-btn");
|
||||
document.getElementById("add-full-screen-form-modal-body-no-btn").innerHTML = response;
|
||||
}, null);
|
||||
}
|
||||
|
||||
function processEvaluation() {
|
||||
const url = document.getElementById("_rootPath").value + "evaluation/project/processEvaluation";
|
||||
const http = new HttpClient();
|
||||
|
||||
const form = document.getElementById("stepForm");
|
||||
const obj = {
|
||||
datasourceType: form['datasource'].value,
|
||||
modelId: form['modelId'].value,
|
||||
templateId: form['templateId'].value,
|
||||
projectId: form['projectId'].value,
|
||||
search: form['search'].value,
|
||||
randomKey: form['randomKey'].value,
|
||||
method: form['method'].value,
|
||||
};
|
||||
|
||||
http.post(url, obj, function (error, response, xhr) {
|
||||
openDialog("modal-full-width-no-btn");
|
||||
|
||||
const modal = document.getElementById("modal-full-width-no-btn");
|
||||
const modalBody = document.getElementById("add-full-screen-form-modal-body-no-btn");
|
||||
modalBody.innerHTML = response;
|
||||
|
||||
// 只绑定一次:modal 关闭就关 WS
|
||||
if (!modal.dataset.wsCleanupBound) {
|
||||
modal.addEventListener("hidden.bs.modal", () => {
|
||||
if (window.evaluationWs && window.evaluationWs.readyState === WebSocket.OPEN) {
|
||||
window.evaluationWs.close(1000, "modal hidden");
|
||||
}
|
||||
window.evaluationWs = null;
|
||||
});
|
||||
modal.dataset.wsCleanupBound = "true";
|
||||
}
|
||||
|
||||
// 如果之前有连接,先关掉,避免泄漏
|
||||
if (window.evaluationWs && window.evaluationWs.readyState === WebSocket.OPEN) {
|
||||
window.evaluationWs.close(1000, "open new evaluation");
|
||||
}
|
||||
window.evaluationWs = null;
|
||||
|
||||
// 建立 ws 连接
|
||||
window.evaluationWs = connectWs("/ws/evaluation/" + obj.randomKey, {
|
||||
onOpen: () => {
|
||||
let userId = document.getElementById("_userId_").value;
|
||||
const cmdInfo = {type: "EVALUATION", cmd: obj, userId: userId};
|
||||
window.evaluationWs.send(JSON.stringify(cmdInfo));
|
||||
},
|
||||
onClose: () => {
|
||||
appendLog("WS closed");
|
||||
},
|
||||
onMessage: (ev) => {
|
||||
// ev 可能是字符串或事件对象(取决于 connectWs 封装)
|
||||
|
||||
appendLog(ev);
|
||||
},
|
||||
onError: (err) => {
|
||||
appendLog("WS error");
|
||||
if (window.evaluationWs && window.evaluationWs.readyState === WebSocket.OPEN) {
|
||||
window.evaluationWs.close(1002, "client error");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 页面卸载时也关(防止刷新/跳转遗留)
|
||||
if (!window._evaluationUnloadBound) {
|
||||
window.addEventListener("beforeunload", () => {
|
||||
if (window.evaluationWs && window.evaluationWs.readyState === WebSocket.OPEN) {
|
||||
window.evaluationWs.close(1001, "page unload");
|
||||
}
|
||||
window.evaluationWs = null;
|
||||
});
|
||||
window._evaluationUnloadBound = true;
|
||||
}
|
||||
|
||||
}, null, null);
|
||||
}
|
||||
|
||||
// 简单的日志追加(每条独占一行 + 自动滚动)
|
||||
function appendLog(text) {
|
||||
const wrap = document.getElementById("during_log");
|
||||
if (!wrap) {
|
||||
return;
|
||||
}
|
||||
const code = document.createElement("code");
|
||||
code.textContent = text;
|
||||
code.style.display = "block"; // 一条一行
|
||||
wrap.appendChild(code);
|
||||
wrap.scrollTop = wrap.scrollHeight;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">评估输入</div>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<table class="table table-vcenter card-table">
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>数据来源:</th>
|
||||
<td th:text="${datasourceName}">
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<th>工程名称:</th>
|
||||
<td th:text="${projectName}">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>指标名称:</th>
|
||||
<td th:text="${indicatorName}">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">评估过程</div>
|
||||
</div>
|
||||
<div class="card-body" style="overflow-y: auto; max-height: 40em;"><pre id="during_log"></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">评估结果</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -165,9 +165,12 @@
|
|||
|
||||
// 根据指标ID获取指标树
|
||||
function metricTree(id) {
|
||||
|
||||
let templateId = document.getElementById("templateForm")["id"].value;
|
||||
if(!templateId||templateId===""){
|
||||
templateId="0"
|
||||
}
|
||||
const url = document.getElementById("_rootPath").value
|
||||
+ "evaluation/evaluationTemplate/metricTree/" + id;
|
||||
+ "evaluation/evaluationTemplate/metricTree/" + id+"/" + templateId;
|
||||
const http = new HttpClient();
|
||||
|
||||
http.get(url, function (error, res, xhr) {
|
||||
|
|
|
|||
53
manager-admin/src/test/java/com/hshh/ApplicationTest.java
Normal file
53
manager-admin/src/test/java/com/hshh/ApplicationTest.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package com.hshh;
|
||||
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.model.entity.ModelDefine;
|
||||
import com.hshh.model.service.ModelDefineService;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@SpringBootTest(classes = Application.class)
|
||||
@AutoConfigureMockMvc
|
||||
@Slf4j
|
||||
public class ApplicationTest {
|
||||
|
||||
@Resource
|
||||
private IndicatorService indicatorService;
|
||||
@Resource
|
||||
private ModelDefineService modelDefineService;
|
||||
|
||||
@Test
|
||||
public void addIndicator() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Indicator indicator = new Indicator();
|
||||
indicator.setName("测试指标_" + i);
|
||||
indicator.setCode("test_" + i);
|
||||
indicatorService.save(indicator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addModel() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ModelDefine modelDefine = new ModelDefine();
|
||||
modelDefine.setModelName("测试设施" + i);
|
||||
modelDefine.setModelCode("test" + i);
|
||||
modelDefine.setSortOrder(i);
|
||||
modelDefineService.save(modelDefine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -75,5 +75,9 @@
|
|||
<artifactId>caffeine</artifactId>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
18
manager-system/src/main/java/com/hshh/system/Global.java
Normal file
18
manager-system/src/main/java/com/hshh/system/Global.java
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package com.hshh.system;
|
||||
|
||||
import com.hshh.system.common.cmd.CmdInfo;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* 全局变量类 .
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class Global {
|
||||
|
||||
/**
|
||||
* 全局待处理的命令容器.
|
||||
*/
|
||||
public static LinkedBlockingQueue<CmdInfo> cmdQueue = new LinkedBlockingQueue<>();
|
||||
}
|
||||
|
|
@ -58,4 +58,5 @@ public class BaseController {
|
|||
List<Menus> menuList = menuService.getMenus(href);
|
||||
model.addAttribute("chainMenuList", menuList);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.system.common.bean;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
|
@ -10,7 +11,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class CheckedBean {
|
||||
public class CheckedBean implements Serializable {
|
||||
|
||||
@TableField(exist = false)
|
||||
private boolean checked;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.hshh.system.common.bean;
|
|||
|
||||
import com.hshh.system.reflect.GetterUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
|
@ -41,7 +42,8 @@ public class JsTree {
|
|||
*/
|
||||
private List<JsTree> children;
|
||||
|
||||
private Map<String, Object> data;
|
||||
private Map<String, Object> data = new HashMap<>();
|
||||
private double weight = 1;
|
||||
|
||||
/**
|
||||
* 树的状态.
|
||||
|
|
|
|||
|
|
@ -47,4 +47,12 @@ public class PaginationBean implements Serializable {
|
|||
@Setter
|
||||
|
||||
private Integer id;
|
||||
|
||||
//以下为临时属性,待重构 //todo
|
||||
@Getter
|
||||
@Setter
|
||||
private String randomKey;
|
||||
@Getter
|
||||
@Setter
|
||||
private String method;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.hshh.system.common.cmd;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
|
||||
public enum CmdEnum {
|
||||
EVALUATION("evaluation", "评估");
|
||||
@Getter
|
||||
private final String desc;
|
||||
@Getter
|
||||
private final String code;
|
||||
|
||||
CmdEnum(String code, String desc) {
|
||||
this.desc = desc;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.hshh.system.common.cmd;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 命令定义
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class CmdInfo {
|
||||
|
||||
private CmdEnum type;
|
||||
private String cmd;
|
||||
private Integer userId;
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.hshh.data.controller;
|
||||
package com.hshh.system.common.enums;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
|
|
@ -9,6 +9,7 @@ package com.hshh.data.controller;
|
|||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class TestController {
|
||||
|
||||
public enum AggregationMethod {
|
||||
WEIGHTED_AVERAGE,
|
||||
FUZZY_AVERAGE;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.hshh.system.common.threadpool;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public final class NamedThreadFactory implements ThreadFactory {
|
||||
private final String poolName;
|
||||
private final boolean daemon;
|
||||
private final AtomicInteger seq = new AtomicInteger(1);
|
||||
private final ThreadGroup group;
|
||||
|
||||
public NamedThreadFactory(String poolName, boolean daemon) {
|
||||
this.poolName = poolName;
|
||||
this.daemon = daemon;
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, poolName + "-" + seq.getAndIncrement(), 0);
|
||||
t.setDaemon(daemon);
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.hshh.system.common.threadpool;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class ThreadPoolBuilder {
|
||||
private final String poolName;
|
||||
|
||||
private int coreSize = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||
private int maxSize = coreSize;
|
||||
private int queueCapacity = 1024;
|
||||
private long keepAliveSeconds = 30;
|
||||
private boolean allowCoreTimeout = false;
|
||||
private boolean daemon = false;
|
||||
private RejectedExecutionHandler rejection = new ThreadPoolExecutor.AbortPolicy();
|
||||
|
||||
public ThreadPoolBuilder(String poolName) {
|
||||
this.poolName = Objects.requireNonNull(poolName, "poolName");
|
||||
}
|
||||
|
||||
public ThreadPoolBuilder coreSize(int n) { this.coreSize = n; return this; }
|
||||
public ThreadPoolBuilder maxSize(int n) { this.maxSize = n; return this; }
|
||||
public ThreadPoolBuilder queueCapacity(int cap) { this.queueCapacity = cap; return this; }
|
||||
public ThreadPoolBuilder keepAliveSeconds(long sec) { this.keepAliveSeconds = sec; return this; }
|
||||
public ThreadPoolBuilder allowCoreThreadTimeOut(boolean allow) { this.allowCoreTimeout = allow; return this; }
|
||||
public ThreadPoolBuilder daemon(boolean d) { this.daemon = d; return this; }
|
||||
public ThreadPoolBuilder rejection(RejectedExecutionHandler h) { this.rejection = h; return this; }
|
||||
|
||||
/** 构建 ThreadPoolExecutor */
|
||||
public ThreadPoolExecutor build() {
|
||||
if (maxSize < coreSize) maxSize = coreSize;
|
||||
final BlockingQueue<Runnable> queue = (queueCapacity <= 0)
|
||||
? new SynchronousQueue<>()
|
||||
: new LinkedBlockingQueue<>(queueCapacity);
|
||||
|
||||
final NamedThreadFactory tf = new NamedThreadFactory(poolName, daemon);
|
||||
|
||||
ThreadPoolExecutor exec = new ThreadPoolExecutor(
|
||||
coreSize,
|
||||
maxSize,
|
||||
keepAliveSeconds, TimeUnit.SECONDS,
|
||||
queue,
|
||||
tf,
|
||||
rejection
|
||||
);
|
||||
exec.allowCoreThreadTimeOut(allowCoreTimeout);
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.hshh.system.common.threadpool;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public final class ThreadPools {
|
||||
|
||||
private ThreadPools() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取构建器入口
|
||||
*/
|
||||
public static ThreadPoolBuilder builder(String poolName) {
|
||||
return new ThreadPoolBuilder(poolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* CPU 密集:线程数≈CPU核心数
|
||||
*/
|
||||
public static ExecutorService newCpuBoundPool(String poolName) {
|
||||
int n = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||
return builder(poolName)
|
||||
.coreSize(n)
|
||||
.maxSize(n)
|
||||
.queueCapacity(1024)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* IO 密集:线程数扩大(默认 2~4 倍)且允许回收核心线程
|
||||
*/
|
||||
public static ExecutorService newIoBoundPool(String poolName) {
|
||||
int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||
return builder(poolName)
|
||||
.coreSize(cores * 2)
|
||||
.maxSize(cores * 4)
|
||||
.queueCapacity(8192)
|
||||
.keepAliveSeconds(60)
|
||||
.allowCoreThreadTimeOut(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划任务线程池
|
||||
*/
|
||||
public static ScheduledExecutorService newScheduledPool(String poolName, int coreSize) {
|
||||
return new ScheduledThreadPoolExecutor(
|
||||
coreSize,
|
||||
new NamedThreadFactory(poolName, false),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 优雅关闭:先等待 quietSeconds,超时则 shutdownNow 再等 forceSeconds。
|
||||
*/
|
||||
public static void gracefulShutdown(ExecutorService pool, long quietSeconds, long forceSeconds) {
|
||||
if (pool == null) {
|
||||
return;
|
||||
}
|
||||
pool.shutdown();
|
||||
try {
|
||||
if (!pool.awaitTermination(quietSeconds, TimeUnit.SECONDS)) {
|
||||
pool.shutdownNow();
|
||||
pool.awaitTermination(forceSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
pool.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.hshh.system.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
/**
|
||||
* ws配置.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Configuration
|
||||
public class EndpointConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/login", "/css/**", "/js/**", "/img/**", "/libs/**", "/captcha", "/toAuth",
|
||||
"/ws", "/swagger-ui.html",
|
||||
"/ws/**", "/swagger-ui.html",
|
||||
"/swagger-ui/**",
|
||||
"/webfonts/**",
|
||||
"/v3/api-docs",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
package com.hshh.system.ws;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.hshh.system.Global;
|
||||
import com.hshh.system.common.cmd.CmdInfo;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 评估需求ws server.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@ServerEndpoint("/ws/evaluation/{key}")
|
||||
@Component
|
||||
@Slf4j
|
||||
public class WsEvaluationServer {
|
||||
|
||||
// key -> 当前key下所有会话
|
||||
private static final Map<String, Set<Session>> SESSION_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 打开事件.
|
||||
*
|
||||
* @param session session容器
|
||||
* @param key key标识
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("key") String key) {
|
||||
log.info("session is open key: {}", key);
|
||||
|
||||
session.getUserProperties().put("key", key);
|
||||
|
||||
SESSION_MAP.computeIfAbsent(key, k -> ConcurrentHashMap.newKeySet()).add(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收信息.
|
||||
*
|
||||
* @param message 信息
|
||||
* @param session session容器
|
||||
* @param key key标识
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session, @PathParam("key") String key)
|
||||
throws Exception {
|
||||
log.info("receive message: {},key:{}", message, key);
|
||||
try {
|
||||
CmdInfo cmdInfo = JSON.parseObject(message, CmdInfo.class);
|
||||
Global.cmdQueue.add(cmdInfo);
|
||||
} catch (Exception e) {
|
||||
log.error("error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭事件.
|
||||
*
|
||||
* @param session session容器
|
||||
* @param key key标识
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session, @PathParam("key") String key) {
|
||||
log.info("session is closed key: {},sessionId:{}", key, session.getId());
|
||||
System.out.println("连接关闭: " + session.getId() + " 参数key=" + key);
|
||||
removeSession(key, session);
|
||||
}
|
||||
|
||||
/**
|
||||
* 出错后的处理.
|
||||
*
|
||||
* @param session session容器
|
||||
* @param error 异常
|
||||
*/
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
String key = (String) session.getUserProperties().get("key");
|
||||
removeSession(key, session);
|
||||
log.error("session error ", error);
|
||||
|
||||
}
|
||||
|
||||
private void removeSession(String key, Session session) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
Set<Session> set = SESSION_MAP.get(key);
|
||||
if (set != null) {
|
||||
set.remove(session);
|
||||
if (set.isEmpty()) {
|
||||
SESSION_MAP.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 主动推送 API ==========
|
||||
|
||||
/**
|
||||
* 给某个 key 的所有连接发消息.
|
||||
*/
|
||||
public static int sendToKey(String key, String msg) {
|
||||
Set<Session> set = SESSION_MAP.get(key);
|
||||
if (set == null) {
|
||||
return 0;
|
||||
}
|
||||
int ok = 0;
|
||||
for (Session s : set) {
|
||||
if (s.isOpen()) {
|
||||
try {
|
||||
s.getBasicRemote().sendText(msg);
|
||||
ok++;
|
||||
} catch (Exception e) {
|
||||
log.error("session error ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给所有 key 的连接广播.
|
||||
*/
|
||||
public static int broadcast(String msg) {
|
||||
int sum = 0;
|
||||
for (String k : SESSION_MAP.keySet()) {
|
||||
sum += sendToKey(k, msg);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ public class CodeGenerator {
|
|||
basePath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
|
||||
})
|
||||
.strategyConfig(builder -> {
|
||||
builder.addInclude("m_data_evaluation_template_weight") // 设置需要生成的表名(多个用逗号分隔)
|
||||
builder.addInclude("m_data_evaluation_template_indicator_weight") // 设置需要生成的表名(多个用逗号分隔)
|
||||
.addTablePrefix("m_data_"); // 设置过滤表前缀
|
||||
})
|
||||
.execute();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user