1. 指标子集映射
This commit is contained in:
parent
e0bc36ae0e
commit
92f28962ef
|
|
@ -1,14 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/manager-admin/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-admin/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-common/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-common/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-system/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-system/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-z-generation/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/manager-z-generation/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@
|
|||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,670 +1,140 @@
|
|||
<!doctype html>
|
||||
<!--
|
||||
* 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, 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>
|
||||
@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;
|
||||
}
|
||||
body {
|
||||
font-feature-settings: "cv03", "cv04", "cv11";
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body >
|
||||
<script src="./dist/js/demo-theme.min.js?1684106062"></script>
|
||||
<div class="page">
|
||||
<!-- Navbar -->
|
||||
<header class="navbar navbar-expand-md d-print-none" >
|
||||
<div class="container-xl">
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>替换雷达为横向条形图 · 最小示例</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial; background:#f8fafc; }
|
||||
.chart-card { width: 900px; margin: 40px auto; background: #f3f6fb; border-radius: 12px; padding: 24px; }
|
||||
.chart-title { margin: 0 0 8px; text-align: center; color:#0f172a; }
|
||||
.chart-container {
|
||||
position: relative;
|
||||
height: 300px; /* 你提供的高度 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-title">一级维度得分对比</h3>
|
||||
<div class="chart-container">
|
||||
<svg id="radarChart"></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 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>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
|
||||
<script>
|
||||
/**
|
||||
* 横向条形图(替换 #radarChart)
|
||||
* @param {string|SVGElement} svgSel - 目标 SVG 选择器/元素
|
||||
* @param {{name:string,score:number}[]} data - 数据;score 建议 0~100
|
||||
* @param {{domainMax?:number, sortAsc?:boolean, target?:number, margin?:object}} opts
|
||||
*/
|
||||
function renderBarChart(svgSel, data, opts = {}) {
|
||||
const cfg = Object.assign({
|
||||
sortAsc: true,
|
||||
domainMax: 100, // 轴与条统一最大值,确保与刻度对齐
|
||||
target: 80,
|
||||
margin: { top: 24, right: 120, bottom: 28, left: 200 }
|
||||
}, opts);
|
||||
|
||||
const src = (data||[]).map(d=>({...d}));
|
||||
if (cfg.sortAsc) src.sort((a,b)=>d3.ascending(a.score,b.score));
|
||||
|
||||
const svg = d3.select(svgSel);
|
||||
const parent = svg.node().parentNode;
|
||||
const W = parent.clientWidth || 800;
|
||||
const H = parent.clientHeight || Math.max(240, src.length*40 + cfg.margin.top + cfg.margin.bottom);
|
||||
|
||||
svg.attr("width", W).attr("height", H)
|
||||
.attr("viewBox", `0 0 ${W} ${H}`)
|
||||
.attr("preserveAspectRatio","xMidYMid meet")
|
||||
.selectAll("*").remove();
|
||||
|
||||
const {top,right,bottom,left} = cfg.margin;
|
||||
const width = Math.max(50, W - left - right);
|
||||
const innerH = Math.max(20, H - top - bottom);
|
||||
const gap = 10;
|
||||
const barH = Math.max(16, Math.min(32, (innerH - (src.length-1)*gap) / Math.max(1,src.length)));
|
||||
|
||||
const g = svg.append("g").attr("transform", `translate(${left},${top})`);
|
||||
|
||||
// ★ 唯一的 x 比例尺(条/轴/目标线共用)
|
||||
const x = d3.scaleLinear()
|
||||
.domain([0, cfg.domainMax])
|
||||
.nice()
|
||||
.range([0, width]);
|
||||
|
||||
const y = d3.scaleBand()
|
||||
.domain(src.map(d=>d.name))
|
||||
.range([0, src.length*(barH+gap)-gap])
|
||||
.paddingInner(gap/(barH+gap));
|
||||
|
||||
const color = d3.scaleLinear()
|
||||
.domain([0.5*cfg.domainMax, 0.75*cfg.domainMax, 0.9*cfg.domainMax])
|
||||
.range (["#ef4444", "#f59e0b", "#10b981"])
|
||||
.clamp(true);
|
||||
|
||||
// X 轴
|
||||
g.append("g")
|
||||
.attr("transform", `translate(0,${y.range()[1]})`)
|
||||
.call(d3.axisBottom(x).ticks(6).tickSizeOuter(0))
|
||||
.selectAll("path,line").attr("stroke", "#e5e7eb");
|
||||
|
||||
// 行
|
||||
const row = g.selectAll(".row").data(src).enter().append("g")
|
||||
.attr("class","row")
|
||||
.attr("transform", d=>`translate(0,${y(d.name)})`);
|
||||
|
||||
// 条形
|
||||
row.append("rect")
|
||||
.attr("height", barH)
|
||||
.attr("width", d=>x(d.score)) // 与轴同一比例尺
|
||||
.attr("fill", d=>color(d.score))
|
||||
.attr("rx", 8).attr("ry", 8);
|
||||
|
||||
// 左侧分类名
|
||||
row.append("text")
|
||||
.attr("x", -10).attr("y", barH/2).attr("dy",".35em")
|
||||
.attr("text-anchor","end").attr("fill","#0f172a").attr("font-weight",700)
|
||||
.text(d=>d.name);
|
||||
|
||||
// 右侧分数
|
||||
row.append("text")
|
||||
.attr("x", d=>x(d.score)+8).attr("y", barH/2).attr("dy",".35em")
|
||||
.attr("fill","#0f172a").attr("font-weight",800).attr("font-size",18)
|
||||
.text(d=>d.score.toFixed(1));
|
||||
|
||||
// 最低分标注
|
||||
const minScore = d3.min(src, d=>d.score);
|
||||
row.filter(d=>d.score===minScore).append("text")
|
||||
.attr("x", d=>x(d.score)+8).attr("y", barH/2+16)
|
||||
.attr("fill","#ef4444").attr("font-weight",800).attr("font-size",12)
|
||||
.text("LOWEST");
|
||||
|
||||
// 目标线(可选)
|
||||
if (typeof cfg.target === "number") {
|
||||
g.append("line")
|
||||
.attr("x1", x(cfg.target)).attr("x2", x(cfg.target))
|
||||
.attr("y1", 0).attr("y2", y.range()[1])
|
||||
.attr("stroke", "#94a3b8").attr("stroke-dasharray", "4,4");
|
||||
g.append("text")
|
||||
.attr("x", x(cfg.target)+6).attr("y", -6)
|
||||
.attr("fill","#64748b").attr("font-size",12)
|
||||
.text(`目标 ${cfg.target}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 最小示例数据(可替换为你的实时数据)======
|
||||
const level1 = [
|
||||
{ name:"港口安全管理", score: 90 },
|
||||
{ name:"港口环境与资源利用", score: 90 },
|
||||
{ name:"港口运行效率", score:90 }
|
||||
];
|
||||
|
||||
// 渲染 & 自适应
|
||||
renderBarChart('#radarChart', level1, { domainMax: 100, target: 80 });
|
||||
window.addEventListener('resize', () =>
|
||||
renderBarChart('#radarChart', level1, { domainMax: 100, target: 80 })
|
||||
);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package com.hshh;
|
||||
|
||||
import com.hshh.system.base.service.LogsService;
|
||||
import com.hshh.system.common.threadpool.ThreadPools;
|
||||
import com.hshh.thread.HandleCmdThread;
|
||||
import com.hshh.system.logs.LogRecorderThread;
|
||||
import com.hshh.thread.HandleEvaluationCmdThread;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -15,8 +18,10 @@ import org.springframework.stereotype.Component;
|
|||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class Init {
|
||||
public class AdminInit {
|
||||
|
||||
@Resource
|
||||
private LogsService logsService;
|
||||
private static final ExecutorService cpu = ThreadPools.newCpuBoundPool("cpu-pool");
|
||||
private static final int evaluationThreadNum = 5;
|
||||
|
||||
|
|
@ -25,16 +30,23 @@ public class Init {
|
|||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
//评估线程
|
||||
startEvaluationThread();
|
||||
//日志记录线程
|
||||
startRecordLogs();
|
||||
}
|
||||
|
||||
private void startEvaluationThread() {
|
||||
try {
|
||||
for (int i = 0; i < evaluationThreadNum; i++) {
|
||||
cpu.execute(new Thread(new HandleCmdThread()));
|
||||
cpu.execute(new Thread(new HandleEvaluationCmdThread()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("error::", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void startRecordLogs() {
|
||||
new Thread(new LogRecorderThread(logsService)).start();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.hshh.model.entity.ModelDefine;
|
|||
import com.hshh.model.service.FormFieldConfigService;
|
||||
import com.hshh.model.service.FormValueService;
|
||||
import com.hshh.model.service.ModelDefineService;
|
||||
import com.hshh.system.annotation.LogOperation;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.bean.ErrorField;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
|
|
@ -70,6 +71,7 @@ public class DataController extends BaseController {
|
|||
* @param model session容器
|
||||
* @return /data/list.html
|
||||
*/
|
||||
@LogOperation("进入数据管理")
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "导航到数据管理页面", description = "导航到数据管理页面")
|
||||
public String index(PaginationBean request, Model model) {
|
||||
|
|
@ -81,12 +83,12 @@ public class DataController extends BaseController {
|
|||
|
||||
model.addAttribute("modelDefineList", modelDefineList); //设置到session中
|
||||
|
||||
if (!modelDefineList.isEmpty()) {
|
||||
if (!modelDefineList.isEmpty() && request.getBusinessKey() != null) {
|
||||
|
||||
List<FormFieldConfig> formConfigList = formFieldConfigService.getFormFieldConfigByModelId(
|
||||
(request.getId() == null ? modelDefineList.get(0).getId() : request.getId())); //查询模型表头
|
||||
request.getBusinessKey()); //查询模型表头
|
||||
sortFieldList(formConfigList); //排序
|
||||
Map<String, String> headerMap = new LinkedHashMap<>(); //定义表头兑现
|
||||
Map<String, String> headerMap = new LinkedHashMap<>(); //定义表头
|
||||
formConfigList.forEach(formFieldConfig -> {
|
||||
headerMap.put(formFieldConfig.getFieldName(), formFieldConfig.getFieldLabel());
|
||||
});
|
||||
|
|
@ -114,10 +116,10 @@ public class DataController extends BaseController {
|
|||
*/
|
||||
private void setCurrentActiveModelDefine(Model model, PaginationBean request,
|
||||
List<ModelDefine> modelDefineList) {
|
||||
AtomicReference<ModelDefine> activeModelDefine = new AtomicReference<>(); //当前激活的数据模型;tab页
|
||||
AtomicReference<ModelDefine> activeModelDefine = new AtomicReference<>();
|
||||
|
||||
modelDefineList.forEach(a -> {
|
||||
if (request.getId() != null && request.getId().equals(a.getId())) {
|
||||
if (request.getBusinessKey() != null && request.getBusinessKey().equals(a.getId())) {
|
||||
a.setChecked(true);
|
||||
activeModelDefine.set(a);
|
||||
|
||||
|
|
@ -129,15 +131,6 @@ public class DataController extends BaseController {
|
|||
});
|
||||
if (activeModelDefine.get() != null) {
|
||||
model.addAttribute("currentModelDefine", activeModelDefine.get());
|
||||
} else {
|
||||
//设置默认第一个选中
|
||||
if (!modelDefineList.isEmpty()) {
|
||||
modelDefineList.get(0).setChecked(true);
|
||||
//设置查询参数为第一个
|
||||
request.setId(modelDefineList.get(0).getId());
|
||||
model.addAttribute("currentModelDefine", modelDefineList.get(0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +150,7 @@ public class DataController extends BaseController {
|
|||
* @param id 模型id
|
||||
* @return form表单内容 div...
|
||||
*/
|
||||
@LogOperation("获取form输入窗体")
|
||||
@GetMapping("/getForm/{id}")
|
||||
@Operation(summary = "获取form输入窗体", description = "根据模型ID获取form窗体")
|
||||
@ResponseBody
|
||||
|
|
@ -171,6 +165,7 @@ public class DataController extends BaseController {
|
|||
* @param formValue 表单值
|
||||
* @return 操作结果
|
||||
*/
|
||||
@LogOperation("保存对应模型ID对应的form表单记录")
|
||||
@PostMapping("/form/save")
|
||||
@ResponseBody
|
||||
@Operation(summary = "保存记录", description = "保存对应模型ID对应的form表单记录")
|
||||
|
|
@ -194,6 +189,7 @@ public class DataController extends BaseController {
|
|||
* @param id 记录ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@LogOperation("根据ID删除记录")
|
||||
@ResponseBody
|
||||
@GetMapping("/remove/{id}")
|
||||
@Operation(summary = "删除记录", description = "根据ID删除记录")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class BarData {
|
||||
|
||||
private String name;
|
||||
private double score;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* csv上传文件描述类.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CsvUploadBean extends PageEvaluationRequest {
|
||||
|
||||
private MultipartFile file;
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class DatasourceRequest implements Serializable {
|
||||
public class PageDatasourceRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
//数据源类型 数据库||Csv文件
|
||||
|
|
@ -9,7 +9,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class EvaluationRequest {
|
||||
public class PageEvaluationRequest {
|
||||
|
||||
/**
|
||||
* database | csv.
|
||||
|
|
@ -36,7 +36,16 @@ public class EvaluationRequest {
|
|||
*/
|
||||
private String randomKey;
|
||||
/**
|
||||
* 计算方式
|
||||
* 计算方式.
|
||||
*/
|
||||
private String method;
|
||||
private Integer indicatorTopId;
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
private Integer userId;
|
||||
private String membership;
|
||||
private int[] ids;
|
||||
//csv数据标识字段
|
||||
private String identifier;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 页面指标权重.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class PageIndicatorWeight {
|
||||
|
||||
/**
|
||||
* 指标ID.
|
||||
*/
|
||||
private int indicatorId;
|
||||
/**
|
||||
* 权重.
|
||||
*/
|
||||
private String weight;
|
||||
}
|
||||
|
|
@ -10,9 +10,9 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class MetricComputeRequest {
|
||||
public class PageMetricComputeRequest {
|
||||
|
||||
private List<String> metric;
|
||||
private List<List<MetricMapperWeightBean>> weightList;
|
||||
private List<List<PageMetricMapperWeightBean>> weightList;
|
||||
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class MetricComputerResponse {
|
||||
public class PageMetricComputerResponse {
|
||||
|
||||
private String id;
|
||||
private String weight;
|
||||
|
|
@ -9,7 +9,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class MetricMapperWeightBean {
|
||||
public class PageMetricMapperWeightBean {
|
||||
|
||||
/**
|
||||
* 从那个指标开始.
|
||||
|
|
@ -31,4 +31,5 @@ public class MetricMapperWeightBean {
|
|||
* 行号.
|
||||
*/
|
||||
private int rowNum;
|
||||
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class MetricTableHeaderBean {
|
||||
public class PageMetricTableHeaderBean {
|
||||
|
||||
private int id;
|
||||
private String name;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class PieData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String label;
|
||||
private double value;
|
||||
private String color;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationRootResult;
|
||||
import com.hshh.indicator.entity.IndicatorTopLevel;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 报告模板类.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class ReportBean implements Serializable {
|
||||
|
||||
private EvaluationRootResult result;
|
||||
private List<IndicatorTopLevel> levelList;
|
||||
private String highRate;
|
||||
private Integer bottomNum;
|
||||
|
||||
private List<PieData> pieDataList;
|
||||
|
||||
private List<ReportIndicatorNodeData> dataNodeList;
|
||||
private List<BarData> barDataList;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class ReportIndicatorNodeData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String id;
|
||||
private String name;
|
||||
private Integer level;
|
||||
private double score;
|
||||
private Map<String, Double> membershipDist;
|
||||
private double weight;
|
||||
private String parent;
|
||||
private String evaluation;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.hshh.evaluation.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 评估数据描述.原始数据id,实际数据data,type=csv or database.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class SingleEvaluationData {
|
||||
|
||||
private int id;
|
||||
private String data;
|
||||
private String type;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -11,14 +11,14 @@ import lombok.Data;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class DynamicTable {
|
||||
public class pageDynamicTable {
|
||||
|
||||
|
||||
/**
|
||||
* 表头map linkedMap.
|
||||
*/
|
||||
private Map<Integer, MetricTableHeaderBean> headerMap;
|
||||
private Map<Integer, PageMetricTableHeaderBean> headerMap;
|
||||
|
||||
|
||||
private List<List<MetricMapperWeightBean>> weight;
|
||||
private List<List<PageMetricMapperWeightBean>> weight;
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import com.hshh.evaluation.bean.BarData;
|
||||
import com.hshh.evaluation.bean.PieData;
|
||||
import com.hshh.evaluation.bean.ReportIndicatorNodeData;
|
||||
import com.hshh.evaluation.entity.EvaluationIndicatorResult;
|
||||
import com.hshh.evaluation.entity.EvaluationRootResult;
|
||||
import com.hshh.indicator.entity.IndicatorTopLevel;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.enums.LevelEnum;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public class AssistantEvaluationProjectController extends BaseController {
|
||||
|
||||
protected Map<String, Double> membershipScoreMap(String input) {
|
||||
Map<String, Double> map = new LinkedHashMap<>(); // 保证顺序和输入一致
|
||||
|
||||
for (String pair : input.split(";")) {
|
||||
if (pair.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String[] kv = pair.split(":");
|
||||
if (kv.length == 2) {
|
||||
String key = kv[0].trim();
|
||||
double value = Double.parseDouble(kv[1].trim());
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
protected String getClosestLevel(List<IndicatorTopLevel> levelList, int targetScore) {
|
||||
IndicatorTopLevel closest = null;
|
||||
int minDiff = Integer.MAX_VALUE;
|
||||
for (IndicatorTopLevel item : levelList) {
|
||||
int diff = Math.abs(targetScore - (int) Double.parseDouble(item.getGrade()));
|
||||
if (diff < minDiff) {
|
||||
minDiff = diff;
|
||||
closest = item;
|
||||
}
|
||||
}
|
||||
return closest != null ? closest.getLevelName() : null;
|
||||
}
|
||||
|
||||
//获取优良率
|
||||
protected String highRate(Map<String, Double> membershipMap) {
|
||||
AtomicReference<Double> highRate = new AtomicReference<>((double) 0);
|
||||
membershipMap.forEach((k, v) -> {
|
||||
if (k.equals(LevelEnum.Excellent.getLevel())) {
|
||||
highRate.set(highRate.get() + v);
|
||||
}
|
||||
if (k.equals(LevelEnum.Good.getLevel())) {
|
||||
highRate.set(highRate.get() + v);
|
||||
}
|
||||
});
|
||||
return String.format("%.2f", highRate.get() * 100);
|
||||
}
|
||||
|
||||
protected void setLevelName(List<IndicatorTopLevel> levelList, EvaluationRootResult rootResult) {
|
||||
if (levelList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
rootResult.setLevelName(levelList.get(levelList.size() - 1).getLevelName());
|
||||
for (IndicatorTopLevel indicatorTopLevel : levelList) {
|
||||
if (Double.parseDouble(rootResult.getFinalScore()) >= Double.parseDouble(
|
||||
indicatorTopLevel.getGrade())) {
|
||||
rootResult.setLevelName(indicatorTopLevel.getLevelName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected List<PieData> pieDataList(Map<String, Double> membershipMap) {
|
||||
List<PieData> list = new ArrayList<>();
|
||||
membershipMap.forEach((k, v) -> {
|
||||
PieData pieData = new PieData();
|
||||
pieData.setLabel(k);
|
||||
pieData.setValue(v * 100);
|
||||
pieData.setColor(LevelEnum.getColor(k));
|
||||
list.add(pieData);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
protected List<ReportIndicatorNodeData> covertIndicatorResultToReportIndicatorNodeData(
|
||||
List<EvaluationIndicatorResult> list, List<IndicatorTopLevel> levelList) {
|
||||
List<ReportIndicatorNodeData> resultList = new ArrayList<>();
|
||||
list.forEach(indicatorResult -> {
|
||||
ReportIndicatorNodeData reportIndicatorNodeData = new ReportIndicatorNodeData();
|
||||
resultList.add(reportIndicatorNodeData);
|
||||
|
||||
reportIndicatorNodeData.setId("node_" + indicatorResult.getIndicatorId());
|
||||
reportIndicatorNodeData.setName(indicatorResult.getIndicatorName());
|
||||
reportIndicatorNodeData.setLevel(indicatorResult.getLevel());
|
||||
reportIndicatorNodeData.setScore(
|
||||
new BigDecimal(indicatorResult.getFinalScore()).setScale(2, RoundingMode.HALF_UP)
|
||||
.doubleValue());
|
||||
Map<String, Double> membershipScoreMap = new HashMap<>();
|
||||
Map<String, Double> originalMap = membershipScoreMap(indicatorResult.getMemberShipScore());
|
||||
|
||||
originalMap.forEach((k, v) -> {
|
||||
membershipScoreMap.put(LevelEnum.getCode(k),
|
||||
BigDecimal.valueOf(v * 100).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
||||
});
|
||||
reportIndicatorNodeData.setMembershipDist(membershipScoreMap);
|
||||
reportIndicatorNodeData.setEvaluation(
|
||||
getClosestLevel(levelList, (int) reportIndicatorNodeData.getScore()));
|
||||
reportIndicatorNodeData.setWeight(indicatorResult.getWeight());
|
||||
if (indicatorResult.getIndicatorParentId() != null) {
|
||||
reportIndicatorNodeData.setParent("node_" + indicatorResult.getIndicatorParentId());
|
||||
}
|
||||
});
|
||||
return resultList;
|
||||
}
|
||||
|
||||
protected List<BarData> covertIndicatorResultToBarData(List<EvaluationIndicatorResult> list) {
|
||||
List<BarData> resultList = new ArrayList<>();
|
||||
list.forEach(indicatorResult -> {
|
||||
BarData barData = new BarData();
|
||||
barData.setName(indicatorResult.getIndicatorName());
|
||||
barData.setScore(
|
||||
new BigDecimal(indicatorResult.getFinalScore()).setScale(2, RoundingMode.HALF_UP)
|
||||
.doubleValue());
|
||||
resultList.add(barData);
|
||||
});
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import com.hshh.evaluation.bean.DynamicTable;
|
||||
import com.hshh.evaluation.bean.MetricMapperWeightBean;
|
||||
import com.hshh.evaluation.bean.MetricTableHeaderBean;
|
||||
import com.hshh.evaluation.bean.PageMetricMapperWeightBean;
|
||||
import com.hshh.evaluation.bean.PageMetricTableHeaderBean;
|
||||
import com.hshh.evaluation.bean.pageDynamicTable;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
|
|
@ -13,6 +13,7 @@ import java.util.ArrayList;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 评估模板类辅助方法.
|
||||
|
|
@ -29,7 +30,7 @@ public class AssistantTemplateController extends BaseController {
|
|||
* @return list string数组
|
||||
*/
|
||||
protected List<String[]> convertMetricMapperWeightBeanListToStrArray(
|
||||
List<List<MetricMapperWeightBean>> weightList) {
|
||||
List<List<PageMetricMapperWeightBean>> weightList) {
|
||||
|
||||
List<String[]> data = new ArrayList<>();
|
||||
weightList.forEach(weight -> {
|
||||
|
|
@ -48,19 +49,27 @@ public class AssistantTemplateController extends BaseController {
|
|||
* @param detailList 数据库数据
|
||||
* @return 页面约定的权重列表
|
||||
*/
|
||||
protected List<MetricMapperWeightBean> convertEvaluationTemplateWeightList(
|
||||
protected List<List<PageMetricMapperWeightBean>> convertEvaluationTemplateWeightList(
|
||||
List<EvaluationTemplateWeight> detailList) {
|
||||
List<MetricMapperWeightBean> list = new ArrayList<>();
|
||||
detailList.forEach(detail -> {
|
||||
MetricMapperWeightBean weightBean = new MetricMapperWeightBean();
|
||||
weightBean.setRowNum(detail.getRowNum());
|
||||
weightBean.setValue(detail.getWeight());
|
||||
weightBean.setRowId(detail.getFromIndicatorId());
|
||||
weightBean.setColId(detail.getToIndicatorId());
|
||||
weightBean.setParentId(detail.getIndicatorParentId());
|
||||
list.add(weightBean);
|
||||
List<List<PageMetricMapperWeightBean>> finalList = new ArrayList<>();
|
||||
Map<Integer, List<EvaluationTemplateWeight>> groupByFromIndicatorMap = detailList.stream()
|
||||
.collect(Collectors.groupingBy(EvaluationTemplateWeight::getFromIndicatorId));
|
||||
|
||||
groupByFromIndicatorMap.forEach((key, value) -> {
|
||||
List<PageMetricMapperWeightBean> list = new ArrayList<>();
|
||||
finalList.add(list);
|
||||
value.forEach(detail -> {
|
||||
PageMetricMapperWeightBean weightBean = new PageMetricMapperWeightBean();
|
||||
weightBean.setRowNum(detail.getRowNum());
|
||||
weightBean.setValue(detail.getWeight());
|
||||
weightBean.setRowId(detail.getFromIndicatorId());
|
||||
weightBean.setColId(detail.getToIndicatorId());
|
||||
weightBean.setParentId(detail.getIndicatorParentId());
|
||||
list.add(weightBean);
|
||||
});
|
||||
});
|
||||
return list;
|
||||
|
||||
return finalList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -69,15 +78,15 @@ public class AssistantTemplateController extends BaseController {
|
|||
* @param children 子指标
|
||||
* @return 表格头信息
|
||||
*/
|
||||
protected Map<Integer, MetricTableHeaderBean> createTableHeaderMap(List<Indicator> children) {
|
||||
List<MetricTableHeaderBean> headerBeans = new ArrayList<>();
|
||||
protected Map<Integer, PageMetricTableHeaderBean> createTableHeaderMap(List<Indicator> children) {
|
||||
List<PageMetricTableHeaderBean> headerBeans = new ArrayList<>();
|
||||
children.forEach(a -> {
|
||||
MetricTableHeaderBean bean = new MetricTableHeaderBean();
|
||||
PageMetricTableHeaderBean bean = new PageMetricTableHeaderBean();
|
||||
bean.setId(a.getId());
|
||||
bean.setName(a.getName());
|
||||
headerBeans.add(bean);
|
||||
});
|
||||
Map<Integer, MetricTableHeaderBean> headerMap = new LinkedHashMap<>();
|
||||
Map<Integer, PageMetricTableHeaderBean> headerMap = new LinkedHashMap<>();
|
||||
headerBeans.forEach(header -> {
|
||||
headerMap.put(header.getId(), header);
|
||||
});
|
||||
|
|
@ -92,11 +101,11 @@ public class AssistantTemplateController extends BaseController {
|
|||
* @param i 行号
|
||||
* @return 默认映射列表
|
||||
*/
|
||||
protected List<MetricMapperWeightBean> createEmptyMapperList(Integer parentIndicatorId,
|
||||
protected List<PageMetricMapperWeightBean> createEmptyMapperList(Integer parentIndicatorId,
|
||||
List<Indicator> children, int i) {
|
||||
List<MetricMapperWeightBean> innerList = new ArrayList<>();
|
||||
List<PageMetricMapperWeightBean> innerList = new ArrayList<>();
|
||||
for (Indicator child : children) {
|
||||
MetricMapperWeightBean weightBean = new MetricMapperWeightBean();
|
||||
PageMetricMapperWeightBean weightBean = new PageMetricMapperWeightBean();
|
||||
//行ID
|
||||
weightBean.setRowId(children.get(i).getId());
|
||||
//列Id
|
||||
|
|
@ -119,8 +128,8 @@ public class AssistantTemplateController extends BaseController {
|
|||
* @param indicatePid 父节点指标
|
||||
* @return 动态表
|
||||
*/
|
||||
protected DynamicTable createNewDynamicFromDatabase(Integer indicatePid) {
|
||||
DynamicTable dynamicTable = new DynamicTable();
|
||||
protected pageDynamicTable createNewDynamicFromDatabase(Integer indicatePid) {
|
||||
pageDynamicTable dynamicTable = new pageDynamicTable();
|
||||
//查询当前指标的子指标
|
||||
IndicatorService indicatorService = SpringContextHolder.getBean(IndicatorServiceImpl.class);
|
||||
List<Indicator> children = indicatorService.queryChildren(indicatePid);
|
||||
|
|
@ -129,9 +138,9 @@ public class AssistantTemplateController extends BaseController {
|
|||
dynamicTable.setHeaderMap(createTableHeaderMap(children));
|
||||
|
||||
//设置权重信息
|
||||
List<List<MetricMapperWeightBean>> weight = new ArrayList<>();
|
||||
List<List<PageMetricMapperWeightBean>> weight = new ArrayList<>();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
List<MetricMapperWeightBean> innerList = createEmptyMapperList(indicatePid, children, i
|
||||
List<PageMetricMapperWeightBean> innerList = createEmptyMapperList(indicatePid, children, i
|
||||
);
|
||||
weight.add(innerList);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/evaluation/evaluationCsvData")
|
||||
public class EvaluationCsvDataController {
|
||||
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 评估记录表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/evaluation/evaluationHistory")
|
||||
public class EvaluationHistoryController {
|
||||
|
||||
}
|
||||
|
|
@ -1,25 +1,42 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.hshh.evaluation.bean.CsvUploadBean;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.bean.ReportBean;
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import com.hshh.evaluation.entity.EvaluationIndicatorResult;
|
||||
import com.hshh.evaluation.entity.EvaluationProject;
|
||||
import com.hshh.evaluation.entity.EvaluationRootResult;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.service.EvaluationCsvDataService;
|
||||
import com.hshh.evaluation.service.EvaluationHistoryService;
|
||||
import com.hshh.evaluation.service.EvaluationIndicatorResultService;
|
||||
import com.hshh.evaluation.service.EvaluationProjectService;
|
||||
import com.hshh.evaluation.service.EvaluationRootResultService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.entity.IndicatorTopLevel;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.indicator.service.IndicatorTopLevelService;
|
||||
import com.hshh.model.entity.FormValue;
|
||||
import com.hshh.model.service.FormFieldConfigService;
|
||||
import com.hshh.model.service.FormValueService;
|
||||
import com.hshh.system.annotation.LogOperation;
|
||||
import com.hshh.system.base.entity.TableRelations;
|
||||
import com.hshh.system.base.service.TableRelationsService;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import com.hshh.system.common.enums.ErrorCode;
|
||||
import com.hshh.system.common.enums.ErrorMessage;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
|
|
@ -28,11 +45,14 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
/**
|
||||
* 评估工程.
|
||||
|
|
@ -42,7 +62,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
*/
|
||||
@Controller
|
||||
@RequestMapping("/evaluation/project")
|
||||
public class EvaluationProjectController extends BaseController {
|
||||
public class EvaluationProjectController extends AssistantEvaluationProjectController {
|
||||
|
||||
@Resource
|
||||
private EvaluationProjectService evaluationProjectService;
|
||||
|
|
@ -76,6 +96,28 @@ public class EvaluationProjectController extends BaseController {
|
|||
private IndicatorService indicatorService;
|
||||
|
||||
|
||||
/**
|
||||
* 上传的csv文件数据记录服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationCsvDataService evaluationCsvDataService;
|
||||
|
||||
/**
|
||||
* 评估历史服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationHistoryService evaluationHistoryService;
|
||||
|
||||
/**
|
||||
* 根指标评估历史记录服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationRootResultService rootResultService;
|
||||
@Resource
|
||||
private IndicatorTopLevelService topLevelService;
|
||||
@Resource
|
||||
private EvaluationIndicatorResultService evaluationIndicatorResultService;
|
||||
|
||||
/**
|
||||
* 默认页.
|
||||
*
|
||||
|
|
@ -114,6 +156,7 @@ public class EvaluationProjectController extends BaseController {
|
|||
*/
|
||||
@ResponseBody
|
||||
@PostMapping("/save")
|
||||
@LogOperation("保存评估工程")
|
||||
public OperateResult<Object> save(@Valid @RequestBody EvaluationProject project,
|
||||
BindingResult bindingResult) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
|
|
@ -146,6 +189,7 @@ public class EvaluationProjectController extends BaseController {
|
|||
*/
|
||||
@ResponseBody
|
||||
@GetMapping("/remove/{id}")
|
||||
@LogOperation("删除工程")
|
||||
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
|
||||
List<TableRelations> reList = tableRelationsService.queryRel(id, "m_data_evaluation_project");
|
||||
if (!reList.isEmpty()) {
|
||||
|
|
@ -159,14 +203,14 @@ public class EvaluationProjectController extends BaseController {
|
|||
/**
|
||||
* 选择数据源类型.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @param model session容器
|
||||
* @param params 请求参数
|
||||
* @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);
|
||||
public String selectDatasourceType(@RequestParam Map<String, String> params, Model model) {
|
||||
setAttribute(model, params);
|
||||
|
||||
return "project/datasource_select";
|
||||
}
|
||||
|
||||
|
|
@ -178,19 +222,27 @@ public class EvaluationProjectController extends BaseController {
|
|||
* @return project/datasource_db.html
|
||||
*/
|
||||
@GetMapping("/database")
|
||||
public String databasePage(PaginationBean request, Model model) {
|
||||
//获取工程
|
||||
public String databasePage(PaginationBean request, Model model,
|
||||
@RequestParam Map<String, String> params) {
|
||||
|
||||
//获取基础设施ID
|
||||
Long modelId = evaluationProjectService.selectModelIdByProjectId(request.getId());
|
||||
Long modelId = evaluationProjectService.selectModelIdByProjectId(
|
||||
params.get("projectId") == null ? 0 : Integer.parseInt(params.get("projectId")));
|
||||
if (modelId == null) {
|
||||
throw new RuntimeException("没有设置基础设施");
|
||||
}
|
||||
params.put("modelId", modelId.toString());
|
||||
|
||||
//设置数据源页面中的隐藏属性
|
||||
addDatasourceModelAttribute(modelId, request, model);
|
||||
addDatasourceModelAttribute(request, model, params);
|
||||
|
||||
//获取表头
|
||||
Map<String, String> headerMap = formFieldConfigService.getHeaderMap(modelId.intValue());
|
||||
model.addAttribute("headerMap", headerMap);
|
||||
//查询数据
|
||||
//替换为modelId查询
|
||||
request.setId(modelId.intValue());
|
||||
request.setBusinessKey(modelId.intValue());
|
||||
|
||||
List<FormValue> formDataList = formValueService.list(request);
|
||||
List<Map<String, Object>> listMap = new ArrayList<>();
|
||||
formDataList.forEach(formData -> {
|
||||
|
|
@ -203,17 +255,41 @@ public class EvaluationProjectController extends BaseController {
|
|||
return "project/datasource_db";
|
||||
}
|
||||
|
||||
private void addDatasourceModelAttribute(Long modelId, PaginationBean request, Model model) {
|
||||
EvaluationProject project = evaluationProjectService.getById(request.getId());
|
||||
private void addDatasourceModelAttribute(PaginationBean request, Model model,
|
||||
@RequestParam Map<String, String> params) {
|
||||
EvaluationProject project = evaluationProjectService.getById(
|
||||
params.get("projectId") == null ? 0 : Integer.parseInt(params.get("projectId")));
|
||||
if (project != null) {
|
||||
model.addAttribute("templateId", project.getTemplateId());
|
||||
params.put("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());
|
||||
setAttribute(model, params);
|
||||
|
||||
}
|
||||
|
||||
private void setAttribute(Model model, @RequestParam Map<String, String> params) {
|
||||
if (params.get("projectId") != null) {
|
||||
model.addAttribute("projectId", params.get("projectId"));
|
||||
}
|
||||
if (params.get("templateId") != null) {
|
||||
model.addAttribute("templateId", params.get("templateId"));
|
||||
}
|
||||
if (params.get("method") != null) {
|
||||
model.addAttribute("method", params.get("method"));
|
||||
}
|
||||
if (params.get("search") != null) {
|
||||
model.addAttribute("search", params.get("search"));
|
||||
}
|
||||
if (params.get("randomKey") != null) {
|
||||
model.addAttribute("randomKey", params.get("randomKey"));
|
||||
}
|
||||
if (params.get("modelId") != null) {
|
||||
model.addAttribute("modelId", params.get("modelId"));
|
||||
}
|
||||
if (params.get("membership") != null) {
|
||||
model.addAttribute("membership", params.get("membership"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -223,11 +299,70 @@ public class EvaluationProjectController extends BaseController {
|
|||
* @param model session容器
|
||||
* @return project/datasource_csv.html
|
||||
*/
|
||||
|
||||
@GetMapping("/csv")
|
||||
public String csvPage(PaginationBean request, Model model) {
|
||||
public String csvPage(PaginationBean request, Model model,
|
||||
@RequestParam Map<String, String> params) {
|
||||
|
||||
if (params.get("projectId") != null && params.get("templateId") == null) {
|
||||
EvaluationProject project = evaluationProjectService.getById(
|
||||
Integer.parseInt(params.get("projectId")));
|
||||
if (project != null) {
|
||||
model.addAttribute("templateId", project.getTemplateId());
|
||||
}
|
||||
}
|
||||
|
||||
setAttribute(model, params);
|
||||
|
||||
//分页查询randomKey
|
||||
List<EvaluationCsvData> list = evaluationCsvDataService.list(request);
|
||||
if (!list.isEmpty()) {
|
||||
//取出csvHeader
|
||||
JSONArray first = JSON.parseArray(list.get(0).getCsvHeader());
|
||||
|
||||
Map<String, String> headerMap = new LinkedHashMap<>();
|
||||
first.forEach(item -> {
|
||||
headerMap.put(item.toString(), item.toString());
|
||||
});
|
||||
|
||||
model.addAttribute("headerMap", headerMap);
|
||||
List<Map<String, Object>> listMap = new ArrayList<>();
|
||||
list.forEach(formData -> {
|
||||
|
||||
listMap.add(formData.toMap()); //转为map对象放入listMap中
|
||||
});
|
||||
Long total = evaluationCsvDataService.count(request);
|
||||
setPaginationInfo(request, listMap, total, model);
|
||||
}
|
||||
|
||||
return "project/datasource_csv";
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传csv文件.
|
||||
*
|
||||
* @param uploadInfo 上传的信息
|
||||
* @return project/datasource_csv.html
|
||||
*/
|
||||
|
||||
@PostMapping("/uploadCsv")
|
||||
public String uploadCsv(@ModelAttribute CsvUploadBean uploadInfo,
|
||||
RedirectAttributes ra, @RequestParam Map<String, String> params) throws IOException {
|
||||
|
||||
//上传文件信息放入数据库
|
||||
evaluationProjectService.uploadCsv(uploadInfo);
|
||||
|
||||
//设置工程ID
|
||||
ra.addAttribute("id", uploadInfo.getProjectId());
|
||||
ra.addAttribute("search", uploadInfo.getSearch());
|
||||
ra.addAttribute("randomKey", uploadInfo.getRandomKey());
|
||||
ra.addAttribute("method", uploadInfo.getMethod());
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
ra.addAttribute(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return "redirect:/evaluation/project/csv";
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航的数据评估执行页面.
|
||||
*
|
||||
|
|
@ -235,21 +370,21 @@ public class EvaluationProjectController extends BaseController {
|
|||
* @param model session容器
|
||||
* @return 评估处理页面
|
||||
*/
|
||||
@LogOperation("评估执行页面")
|
||||
@PostMapping("/processEvaluation")
|
||||
public String processEvaluationPage(@RequestBody EvaluationRequest request, Model model) {
|
||||
public String processEvaluationPage(@RequestBody PageEvaluationRequest request, Model model) {
|
||||
|
||||
addProcessEvaluationModelAttribute(request, model);
|
||||
return "project/project_evaluation_process";
|
||||
}
|
||||
|
||||
private void addProcessEvaluationModelAttribute(EvaluationRequest request, Model model) {
|
||||
private void addProcessEvaluationModelAttribute(PageEvaluationRequest request, Model model) {
|
||||
//获取工程名称
|
||||
EvaluationProject project = evaluationProjectService.getById(request.getProjectId());
|
||||
if (project != null) {
|
||||
model.addAttribute("projectName", project.getProjectName());
|
||||
}
|
||||
Indicator indicator = indicatorService.selectByTemplateId(
|
||||
request.getTemplateId());
|
||||
Indicator indicator = indicatorService.selectByTemplateId(request.getTemplateId());
|
||||
//获取指标名称
|
||||
if (indicator != null) {
|
||||
model.addAttribute("indicatorName", indicator.getName());
|
||||
|
|
@ -258,4 +393,114 @@ public class EvaluationProjectController extends BaseController {
|
|||
model.addAttribute("datasourceName",
|
||||
(request.getDatasourceType().equals("database") ? "数据库" : "CSV文件"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看根指标评估历史.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return project/evaluation_root_history.html
|
||||
*/
|
||||
@GetMapping("/root_history")
|
||||
public String rootHistory(Integer projectId) {
|
||||
EvaluationHistory recentHistory = evaluationHistoryService.queryRecentByProjectId(projectId);
|
||||
if (recentHistory == null) {
|
||||
throw new RuntimeException("请先开始评估");
|
||||
}
|
||||
String randomKey = recentHistory.getRandomKey();
|
||||
// 重定向到另一个接口,带上参数
|
||||
return "redirect:root_history_by_randomKey?randomKey=" + randomKey + "&projectId=" + projectId;
|
||||
}
|
||||
|
||||
@GetMapping("/root_history_by_randomKey")
|
||||
public String rootHistoryByRandomKey(String randomKey, Integer projectId, Model model) {
|
||||
List<EvaluationRootResult> rootList = rootResultService.queryListByRandomKey(
|
||||
randomKey);
|
||||
model.addAttribute("projectId", projectId);
|
||||
model.addAttribute("rootList", rootList);
|
||||
return "project/evaluation_root_history";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看报告.
|
||||
*
|
||||
* @param id 根历史记录ID
|
||||
*/
|
||||
@GetMapping("/reportData")
|
||||
@ResponseBody
|
||||
@LogOperation("查看报告")
|
||||
public OperateResult<ReportBean> report(Integer id) {
|
||||
final ReportBean reportBean = new ReportBean();
|
||||
//设置摘要信息
|
||||
EvaluationRootResult rootResult = rootResultService.getById(id);
|
||||
reportBean.setResult(rootResult);
|
||||
//规范化时间
|
||||
rootResult.setCreateTimeStr(
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(rootResult.getCreateTime()));
|
||||
|
||||
//获取底层指标数量
|
||||
int bottomNum = indicatorService.selectNoChildByTopId(rootResult.getIndicatorTopId()).size();
|
||||
reportBean.setBottomNum(bottomNum);
|
||||
|
||||
//设置所在评价集区间名称
|
||||
List<IndicatorTopLevel> levelList = topLevelService.getTopLevel(rootResult.getIndicatorTopId());
|
||||
levelList.sort((a, b) -> Double.compare(Double.parseDouble(b.getGrade()),
|
||||
Double.parseDouble(a.getGrade())));
|
||||
setLevelName(levelList, rootResult);
|
||||
reportBean.setLevelList(levelList);
|
||||
|
||||
//各维度得分对比
|
||||
String membership = rootResult.getMembershipScore();
|
||||
Map<String, Double> membershipMap = membershipScoreMap(membership);
|
||||
StringBuilder replaceMemberShipBuilder = new StringBuilder();
|
||||
levelList.forEach(level -> {
|
||||
if (membershipMap.get(level.getLevelName()) != null) {
|
||||
replaceMemberShipBuilder.append(level.getLevelName()).append(":")
|
||||
.append(membershipMap.get(level.getLevelName())).append(";");
|
||||
level.setActualValue(
|
||||
Double.parseDouble(level.getGrade()) * membershipMap.get(level.getLevelName()));
|
||||
}
|
||||
});
|
||||
//按照优先级重新覆盖隶属函数对应的值
|
||||
rootResult.setMembershipScore(replaceMemberShipBuilder.toString());
|
||||
//设置指标表格
|
||||
List<EvaluationIndicatorResult> indicatorResultList = evaluationIndicatorResultService.selectByRootId(
|
||||
id);
|
||||
reportBean.setDataNodeList(
|
||||
covertIndicatorResultToReportIndicatorNodeData(indicatorResultList, levelList));
|
||||
|
||||
//设置优和良综合
|
||||
reportBean.setHighRate(highRate(membershipMap));
|
||||
//设置隶属度pie数据
|
||||
reportBean.setPieDataList(pieDataList(membershipMap));
|
||||
//查询一级指标的名称和得分
|
||||
List<EvaluationIndicatorResult> firstLevelList = evaluationIndicatorResultService.queryListByParentIdAndRandomKey(
|
||||
rootResult.getIndicatorTopId(),
|
||||
|
||||
rootResult.getRandomKey(), rootResult.getId());
|
||||
|
||||
//设置柱状图数据
|
||||
reportBean.setBarDataList(covertIndicatorResultToBarData(firstLevelList));
|
||||
return OperateResult.success(reportBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航到报告页面.
|
||||
*/
|
||||
@GetMapping("/report")
|
||||
public String reportPage() {
|
||||
return "project/evaluation_report";
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航到历史页面.
|
||||
*/
|
||||
@GetMapping("/history")
|
||||
public String history(Integer projectId, Model model) {
|
||||
List<EvaluationHistory> list = evaluationHistoryService.queryListByProjectId(
|
||||
projectId);
|
||||
model.addAttribute("list", list);
|
||||
return "project/evaluation_history";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 评估结果表 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/evaluation/evaluationResult")
|
||||
public class EvaluationResultController {
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import com.hshh.evaluation.bean.DynamicTable;
|
||||
import com.hshh.evaluation.bean.MetricComputeRequest;
|
||||
import com.hshh.evaluation.bean.MetricComputerResponse;
|
||||
import com.hshh.evaluation.bean.MetricMapperWeightBean;
|
||||
import com.hshh.evaluation.bean.MetricTableHeaderBean;
|
||||
import com.hshh.evaluation.bean.PageMetricComputeRequest;
|
||||
import com.hshh.evaluation.bean.PageMetricComputerResponse;
|
||||
import com.hshh.evaluation.bean.PageMetricMapperWeightBean;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateIndicatorWeightService;
|
||||
|
|
@ -12,11 +10,12 @@ import com.hshh.evaluation.service.EvaluationTemplateService;
|
|||
import com.hshh.evaluation.service.EvaluationTemplateWeightService;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.system.annotation.LogOperation;
|
||||
import com.hshh.system.base.entity.TableRelations;
|
||||
import com.hshh.system.base.service.TableRelationsService;
|
||||
import com.hshh.system.common.Strings.StringOperationUtil;
|
||||
import com.hshh.system.common.algorithm.AhpNode;
|
||||
import com.hshh.system.common.algorithm.AhpTreeCompute;
|
||||
import com.hshh.system.common.Strings.StringUtil;
|
||||
import com.hshh.system.algorithm.ahp.AhpNode;
|
||||
import com.hshh.system.algorithm.ahp.AhpTreeCompute;
|
||||
import com.hshh.system.common.bean.JsTree;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
|
|
@ -25,7 +24,6 @@ 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.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
|
|
@ -122,6 +120,7 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
*/
|
||||
@ResponseBody
|
||||
@PostMapping("/save")
|
||||
@LogOperation("保存模板")
|
||||
public OperateResult<Object> save(@Valid @RequestBody EvaluationTemplate evaluationTemplate,
|
||||
BindingResult bindingResult) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
|
|
@ -141,29 +140,19 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
evaluationTemplate.setCreateTime(LocalDateTime.now());
|
||||
|
||||
}
|
||||
|
||||
// //1.合并权重数据
|
||||
// Map<Integer, DraftWeightData> unitWeightDataMap = unitWeightMap(evaluationTemplate);
|
||||
//
|
||||
// //2.填充数据;如果一个指标下面只有一个孩子,则默认填充为1
|
||||
// List<Indicator> lonelyChild = indicatorService.queryLonelyChild(
|
||||
// evaluationTemplate.getIndicatorTopId());
|
||||
//
|
||||
// paddingDefaultValueWhenParentHasOnlyLonelyChild(lonelyChild, unitWeightDataMap);
|
||||
|
||||
// //4. 提交
|
||||
// evaluationTemplateService.saveWhole(evaluationTemplate, unitWeightDataMap);
|
||||
evaluationTemplateService.saveWhole(evaluationTemplate);
|
||||
return OperateResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id删除指标.
|
||||
* 根据id删除模板.
|
||||
*
|
||||
* @param id 要删除的ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@GetMapping("/remove/{id}")
|
||||
@ResponseBody
|
||||
@LogOperation("删除模板")
|
||||
public OperateResult<Object> remove(@PathVariable("id") Integer id) {
|
||||
List<TableRelations> reledList = tableRelationsService.queryRel(id,
|
||||
"m_data_evaluation_template");
|
||||
|
|
@ -206,8 +195,9 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
return OperateResult.success(new ArrayList<>());
|
||||
}
|
||||
//查询指标权重树
|
||||
Map<Integer, Double> weightMap = evaluationTemplateIndicatorWeightService.getEvaluationTemplateIndicatorWeightMap(
|
||||
Map<Integer, String> weightMap = evaluationTemplateIndicatorWeightService.getEvaluationTemplateIndicatorWeightMap(
|
||||
id, templateId);
|
||||
//获取互比信息
|
||||
Map<Integer, List<EvaluationTemplateWeight>> weightDetailMap = evaluationTemplateDetailWeightService.groupByParentIndicatorId(
|
||||
id, templateId);
|
||||
List<JsTree> jsTreeList = indicatorService.metricTree(id);
|
||||
|
|
@ -216,20 +206,22 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
return OperateResult.success(jsTreeList);
|
||||
}
|
||||
|
||||
private void setWeightToTree(List<JsTree> jsTreeList, Map<Integer, Double> weightMap,
|
||||
private void setWeightToTree(List<JsTree> jsTreeList, Map<Integer, String> weightMap,
|
||||
Map<Integer, List<EvaluationTemplateWeight>> weightDetailMap) {
|
||||
if (jsTreeList == null) {
|
||||
return;
|
||||
}
|
||||
jsTreeList.forEach(tree -> {
|
||||
if (weightMap.containsKey((int) tree.getOriginalId())) {
|
||||
tree.getData().put("weight", weightMap.get((int) tree.getOriginalId()));
|
||||
|
||||
tree.getData().put("weight", weightMap.get((int) tree.getOriginalId()));
|
||||
tree.setText(tree.getText() + "(" + weightMap.get((int) tree.getOriginalId()) + ")");
|
||||
} else {
|
||||
tree.setText(tree.getText() + "(1)");
|
||||
tree.getData().put("weight", 1);
|
||||
}
|
||||
if (weightDetailMap.containsKey((int) tree.getOriginalId())) {
|
||||
tree.getData().put("weightDetail",
|
||||
tree.getData().put("children",
|
||||
convertEvaluationTemplateWeightList(weightDetailMap.get((int) tree.getOriginalId())));
|
||||
}
|
||||
setWeightToTree(tree.getChildren(), weightMap, weightDetailMap);
|
||||
|
|
@ -237,8 +229,6 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取指标编辑/新增时的table表格.
|
||||
*
|
||||
|
|
@ -262,13 +252,13 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
*/
|
||||
@PostMapping("/computer")
|
||||
@ResponseBody
|
||||
public synchronized OperateResult<List<MetricComputerResponse>> computerWeight(
|
||||
@RequestBody MetricComputeRequest requests) {
|
||||
public synchronized OperateResult<List<PageMetricComputerResponse>> computerWeight(
|
||||
@RequestBody PageMetricComputeRequest requests) {
|
||||
//如果没有值,直接静默返回
|
||||
if (requests.getWeightList() == null || requests.getWeightList().isEmpty()) {
|
||||
return OperateResult.success();
|
||||
}
|
||||
final List<MetricComputerResponse> responseList = new ArrayList<>();
|
||||
final List<PageMetricComputerResponse> responseList = new ArrayList<>();
|
||||
|
||||
List<String> metricList = requests.getMetric();
|
||||
final AhpNode H = new AhpNode("H");
|
||||
|
|
@ -276,15 +266,15 @@ public class EvaluationTemplateController extends AssistantTemplateController {
|
|||
AhpNode m = new AhpNode(metric);
|
||||
H.add(m);
|
||||
});
|
||||
List<List<MetricMapperWeightBean>> weightList = requests.getWeightList();
|
||||
List<List<PageMetricMapperWeightBean>> weightList = requests.getWeightList();
|
||||
|
||||
double[][] data = StringOperationUtil.toDoubleArray(
|
||||
double[][] data = StringUtil.toDoubleArray(
|
||||
convertMetricMapperWeightBeanListToStrArray(weightList));
|
||||
H.setLocalMatrix(data);
|
||||
H.globalWeight = 1; // 根节点全局权重=1
|
||||
AhpTreeCompute.computeTree(H);
|
||||
H.children.forEach(child -> {
|
||||
MetricComputerResponse response = new MetricComputerResponse();
|
||||
PageMetricComputerResponse response = new PageMetricComputerResponse();
|
||||
response.setId(child.name);
|
||||
response.setWeight(String.format("%.4f", child.globalWeight));
|
||||
responseList.add(response);
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.hshh.evaluation.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/evaluation/evaluationTemplateIndicatorWeight")
|
||||
public class EvaluationTemplateIndicatorWeightController {
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
package com.hshh.evaluation.entity;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import com.hshh.system.common.bean.BaseBean;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
|
@ -15,7 +19,7 @@ import lombok.Data;
|
|||
*/
|
||||
@TableName("m_data_evaluation_csv_data")
|
||||
@Data
|
||||
public class EvaluationCsvData implements Serializable {
|
||||
public class EvaluationCsvData extends BaseBean {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
@ -36,5 +40,15 @@ public class EvaluationCsvData implements Serializable {
|
|||
|
||||
private Integer userId;
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", id);
|
||||
map.put("seq", getSeq());
|
||||
JSONObject jsonObj = JSON.parseObject(rawData, JSONObject.class);
|
||||
map.putAll(jsonObj);
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
private String csvHeader;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,8 @@ public class EvaluationHistory implements Serializable {
|
|||
private Integer userId;
|
||||
|
||||
private String randomKey;
|
||||
private String datasourceType;
|
||||
private String membershipFunc;
|
||||
private String fuzzyOperator;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
package com.hshh.evaluation.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 评估结果表.
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@TableName("m_data_evaluation_result")
|
||||
@Data
|
||||
public class EvaluationResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
private Integer historyId;
|
||||
|
||||
|
||||
private Integer projectId;
|
||||
|
||||
|
||||
private String rawData;
|
||||
|
||||
|
||||
private String resultData;
|
||||
|
||||
|
||||
private LocalDateTime createTime;
|
||||
private String randomKey;
|
||||
/**
|
||||
* 得分.
|
||||
*/
|
||||
private Double finalScore;
|
||||
|
||||
}
|
||||
|
|
@ -4,7 +4,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.hshh.evaluation.bean.MetricMapperWeightBean;
|
||||
import com.hshh.evaluation.bean.PageIndicatorWeight;
|
||||
import com.hshh.evaluation.bean.PageMetricMapperWeightBean;
|
||||
import com.hshh.system.common.bean.BaseBean;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
|
@ -47,12 +48,16 @@ public class EvaluationTemplate extends BaseBean {
|
|||
private String indicatorTopName;
|
||||
@TableField(exist = false)
|
||||
private String templateStatusName;
|
||||
//提交时,当前页面对应的指标id,其余指标从缓存取
|
||||
@TableField(exist = false)
|
||||
private List<List<MetricMapperWeightBean>> currentPagePartData;
|
||||
//暂存指标权重的key
|
||||
@TableField(exist = false)
|
||||
private String draftKey;
|
||||
|
||||
/**
|
||||
* 前端传递的各个指标的权重.
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<PageIndicatorWeight> indicatorWeightList;
|
||||
/**
|
||||
* 前端传递的各个指标之间对比权重信息.
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<PageMetricMapperWeightBean> templateDetailWeightList;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,40 @@
|
|||
package com.hshh.evaluation.mapper;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
* 上传的评估数据csv原始数据记录.
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
public interface EvaluationCsvDataMapper extends BaseMapper<EvaluationCsvData> {
|
||||
|
||||
/**
|
||||
* 列表信息.
|
||||
*
|
||||
* @param paginationBean 请求参数
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<EvaluationCsvData> list(PaginationBean paginationBean);
|
||||
|
||||
/**
|
||||
* 总条数.
|
||||
*
|
||||
* @param paginationBean 请求参数
|
||||
* @return 总条目
|
||||
*/
|
||||
Long count(PaginationBean paginationBean);
|
||||
|
||||
/**
|
||||
* 根据id集合查找记录.
|
||||
*
|
||||
* @param ids id集合
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<EvaluationCsvData> selectByIds(@Param("ids") List<Integer> ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.hshh.evaluation.mapper;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -13,4 +14,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||
*/
|
||||
public interface EvaluationHistoryMapper extends BaseMapper<EvaluationHistory> {
|
||||
|
||||
/**
|
||||
* 根据项目查询最新的历史记录.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return 最新的历史记录
|
||||
*/
|
||||
List<EvaluationHistory> queryRecentByProjectId(Integer projectId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package com.hshh.evaluation.mapper;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationResult;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 评估结果表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
public interface EvaluationResultMapper extends BaseMapper<EvaluationResult> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
|
||||
|
||||
/**
|
||||
* 核心评估服务.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
public interface CoreEvaluationService {
|
||||
|
||||
/**
|
||||
* 核心评估算法.
|
||||
*
|
||||
* @param request 评估请求
|
||||
* @param userId 用户 ID
|
||||
*/
|
||||
void evaluation(PageEvaluationRequest request, Integer userId);
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.CsvUploadBean;
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 保存每次评估时上传的csv数据.
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
public interface EvaluationCsvDataService extends IService<EvaluationCsvData> {
|
||||
|
||||
/**
|
||||
* 保存用户上传的csv文件记录.
|
||||
*
|
||||
* @param dataList csv解析后的数据
|
||||
* @param uploadInfo 附加表单信息
|
||||
*/
|
||||
void saveWhole(List<Map<String, String>> dataList, CsvUploadBean uploadInfo);
|
||||
|
||||
/**
|
||||
* 列表信息.
|
||||
*
|
||||
* @param paginationBean 请求参数
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<EvaluationCsvData> list(PaginationBean paginationBean);
|
||||
|
||||
/**
|
||||
* 总条数.
|
||||
*
|
||||
* @param paginationBean 请求参数
|
||||
* @return 总条目
|
||||
*/
|
||||
Long count(PaginationBean paginationBean);
|
||||
|
||||
/**
|
||||
* 根据id集合查找记录.
|
||||
*
|
||||
* @param ids id集合
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<EvaluationCsvData> selectByIds(@Param("ids") List<Integer> ids);
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 评估记录表 服务类.
|
||||
|
|
@ -11,4 +13,26 @@ import com.hshh.evaluation.entity.EvaluationHistory;
|
|||
*/
|
||||
public interface EvaluationHistoryService extends IService<EvaluationHistory> {
|
||||
|
||||
/**
|
||||
* 保存评估历史.
|
||||
*
|
||||
* @param request 评估请求
|
||||
*/
|
||||
void saveWhole(PageEvaluationRequest request);
|
||||
|
||||
/**
|
||||
* 根据项目查询最新的历史记录.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return 最新的历史记录
|
||||
*/
|
||||
EvaluationHistory queryRecentByProjectId(Integer projectId);
|
||||
|
||||
/**
|
||||
* 查询工程评估的历史记录.
|
||||
*
|
||||
* @param projectId 工程ID
|
||||
* @return 历史记录
|
||||
*/
|
||||
List<EvaluationHistory> queryListByProjectId(Integer projectId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.bean.CsvUploadBean;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationProject;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -59,5 +61,12 @@ public interface EvaluationProjectService extends IService<EvaluationProject> {
|
|||
* @param request 评估请求
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void evaluate(EvaluationRequest request, Integer userId);
|
||||
void evaluate(PageEvaluationRequest request, Integer userId);
|
||||
|
||||
/**
|
||||
* 上传csv文件.
|
||||
*
|
||||
* @param uploadInfo csv文件信息
|
||||
*/
|
||||
void uploadCsv(CsvUploadBean uploadInfo) throws IOException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationResult;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 评估结果表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
public interface EvaluationResultService extends IService<EvaluationResult> {
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.hshh.evaluation.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateIndicatorWeight;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
|
@ -17,9 +18,27 @@ public interface EvaluationTemplateIndicatorWeightService extends
|
|||
* 获取指标对应的权重.
|
||||
*
|
||||
* @param indicatorTopId 指标ID
|
||||
* @param templateId 模板 ID
|
||||
* @param templateId 模板 ID
|
||||
* @return 权重信息
|
||||
*/
|
||||
public Map<Integer, Double> getEvaluationTemplateIndicatorWeightMap(Integer indicatorTopId,
|
||||
Map<Integer, String> getEvaluationTemplateIndicatorWeightMap(Integer indicatorTopId,
|
||||
Integer templateId);
|
||||
|
||||
/**
|
||||
* 保存指标权重信息.
|
||||
*
|
||||
* @param templateId 模板ID
|
||||
* @param indicatorTopId 顶级指标ID
|
||||
* @param list 指标权重集合
|
||||
*/
|
||||
void saveEvaluationTemplateIndicatorWeight(Integer templateId, Integer indicatorTopId,
|
||||
List<EvaluationTemplateIndicatorWeight> list);
|
||||
|
||||
/**
|
||||
* 删除指标权重信息.
|
||||
*
|
||||
* @param templateId 模板 ID
|
||||
* @param indicatorTopId 顶级指标ID
|
||||
*/
|
||||
void deleteByTemplateIdAndIndicatorTopId(Integer templateId, Integer indicatorTopId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ public interface EvaluationTemplateService extends IService<EvaluationTemplate>
|
|||
* 保存评估模板数据.
|
||||
*
|
||||
* @param evaluationTemplate 评估模板
|
||||
* @param weightData 权重
|
||||
|
||||
*/
|
||||
void saveWhole(EvaluationTemplate evaluationTemplate,
|
||||
Map<Integer, DraftWeightData> weightData);
|
||||
void saveWhole(EvaluationTemplate evaluationTemplate
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据名称查询列表.
|
||||
|
|
|
|||
|
|
@ -14,24 +14,6 @@ import java.util.Map;
|
|||
public interface EvaluationTemplateWeightService extends IService<EvaluationTemplateWeight> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据模板id+指标id删除.
|
||||
*
|
||||
* @param templateId 模板ID
|
||||
* @param indicatorTopId 顶级指标ID
|
||||
* @param parentId 上级指标ID
|
||||
*/
|
||||
void deleteEvaluationTemplateWeightWithTemplateIdAndIndicatorId(Integer templateId,
|
||||
Integer indicatorTopId,
|
||||
Integer parentId);
|
||||
|
||||
/**
|
||||
* 根据模板ID删除权重信息.
|
||||
*
|
||||
* @param templateId 模板ID
|
||||
*/
|
||||
void deleteEvaluationTemplateWeightWithTemplateId(Integer templateId);
|
||||
|
||||
/**
|
||||
* 根据指标父ID和模板id获取权重列表.
|
||||
*
|
||||
|
|
@ -42,6 +24,16 @@ public interface EvaluationTemplateWeightService extends IService<EvaluationTemp
|
|||
List<EvaluationTemplateWeight> queryListByIndicatorParentIdAndTemplateId(
|
||||
Integer indicatorParentId, Integer templateId);
|
||||
|
||||
/**
|
||||
* 根据顶级ID和模板id获取权重列表.
|
||||
*
|
||||
* @param indicatorTopId 指标顶级ID
|
||||
* @param templateId 模板ID
|
||||
* @return 权重列表
|
||||
*/
|
||||
List<EvaluationTemplateWeight> queryListByIndicatorTopIdAndTemplateId(
|
||||
Integer indicatorTopId, Integer templateId);
|
||||
|
||||
/**
|
||||
* 指标对应的权重详情,按照父指标ID分类.
|
||||
*
|
||||
|
|
@ -51,4 +43,23 @@ public interface EvaluationTemplateWeightService extends IService<EvaluationTemp
|
|||
*/
|
||||
Map<Integer, List<EvaluationTemplateWeight>> groupByParentIndicatorId(Integer indicatorParentId,
|
||||
Integer templateId);
|
||||
|
||||
/**
|
||||
* 保存指标和指标之间的矩阵信息.
|
||||
*
|
||||
* @param templateId 模板ID
|
||||
* @param indicatorTopId 指标ID
|
||||
* @param weightList 互比矩阵列表
|
||||
*/
|
||||
void saveIndicatorMatrix(Integer templateId, Integer indicatorTopId,
|
||||
List<EvaluationTemplateWeight> weightList);
|
||||
|
||||
/**
|
||||
* 删除互比信息.
|
||||
*
|
||||
* @param templateId 模板ID
|
||||
* @param indicatorTopId 顶级指标ID
|
||||
*/
|
||||
void deleteByTemplateIdAndIndicatorTopId(Integer templateId, Integer indicatorTopId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package com.hshh.evaluation.service;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
public interface IEvaluationCsvDataService extends IService<EvaluationCsvData> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,514 @@
|
|||
package com.hshh.evaluation.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.bean.SingleEvaluationData;
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.service.CoreEvaluationService;
|
||||
import com.hshh.evaluation.service.EvaluationCsvDataService;
|
||||
import com.hshh.evaluation.service.EvaluationHistoryService;
|
||||
import com.hshh.evaluation.service.EvaluationRootResultService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateIndicatorWeightService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.entity.IndicatorBottomCsvMapper;
|
||||
import com.hshh.indicator.entity.IndicatorBottomFormMapper;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import com.hshh.indicator.entity.IndicatorTopLevel;
|
||||
import com.hshh.indicator.entity.IndicatorTopSet;
|
||||
import com.hshh.indicator.service.IndicatorBottomCsvMapperService;
|
||||
import com.hshh.indicator.service.IndicatorBottomFormMapperService;
|
||||
import com.hshh.indicator.service.IndicatorEvalItemService;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.indicator.service.IndicatorTopLevelService;
|
||||
import com.hshh.indicator.service.IndicatorTopSetService;
|
||||
import com.hshh.model.entity.FormValue;
|
||||
import com.hshh.model.service.FormValueService;
|
||||
import com.hshh.system.algorithm.fuzzy.EvaluationLevel;
|
||||
import com.hshh.system.algorithm.fuzzy.FuzzyEvaluationService;
|
||||
import com.hshh.system.algorithm.fuzzy.FuzzyOperator;
|
||||
import com.hshh.system.algorithm.fuzzy.GlobalEvaluationConfig;
|
||||
import com.hshh.system.algorithm.fuzzy.GlobalMembershipFunction;
|
||||
import com.hshh.system.algorithm.fuzzy.GradeRange;
|
||||
import com.hshh.system.algorithm.fuzzy.IndicatorNode;
|
||||
import com.hshh.system.algorithm.fuzzy.LeafFullTriangularMembershipFunction;
|
||||
import com.hshh.system.algorithm.fuzzy.LeafHybridMembershipFunction;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import com.hshh.system.ws.WsEvaluationServer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 模糊综合评估服务类 (重构后).
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Service
|
||||
public class CoreEvaluationServiceImpl implements CoreEvaluationService {
|
||||
|
||||
|
||||
@Resource
|
||||
private EvaluationTemplateService evaluationTemplateService;
|
||||
@Resource
|
||||
private IndicatorTopSetService indicatorTopSetService;
|
||||
@Resource
|
||||
private IndicatorService indicatorService;
|
||||
@Resource
|
||||
private IndicatorTopLevelService indicatorTopLevelService;
|
||||
@Resource
|
||||
private IndicatorBottomFormMapperService indicatorBottomFormMapperService;
|
||||
@Resource
|
||||
private IndicatorBottomCsvMapperService indicatorBottomCsvMapperService;
|
||||
@Resource
|
||||
private FormValueService formValueService;
|
||||
@Resource
|
||||
private EvaluationCsvDataService evaluationCsvDataService;
|
||||
@Resource
|
||||
private EvaluationTemplateIndicatorWeightService evaluationTemplateIndicatorWeightService;
|
||||
@Resource
|
||||
private IndicatorEvalItemService indicatorEvalItemService; //底部指标评价集区间
|
||||
@Resource
|
||||
private EvaluationHistoryService evaluationHistoryService; //评估历史批次记录
|
||||
@Resource
|
||||
private EvaluationRootResultService evaluationRootResultService; //评估详情及概况记录
|
||||
|
||||
// 定义分页大小常量,便于管理
|
||||
private static final int DEFAULT_PAGE_SIZE = 100;
|
||||
|
||||
/**
|
||||
* 评估主入口方法。 通过策略模式分发到不同的数据源处理器.
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void evaluation(PageEvaluationRequest request, Integer userId) {
|
||||
long now = System.currentTimeMillis();
|
||||
try {
|
||||
|
||||
// 1. 获取评估所需的通用前置数据(模板、隶属度、评价集、指标树)
|
||||
EvaluationTemplate template = getTemplateOrThrow(request.getTemplateId());
|
||||
Integer indicatorTopId = template.getIndicatorTopId();
|
||||
request.setIndicatorTopId(indicatorTopId);
|
||||
IndicatorTopSet membershipFuncSet = getMembershipFuncSetOrThrow(indicatorTopId); //隶属函数设置
|
||||
List<IndicatorTopLevel> topLevelList = getTopLevelListOrThrow(indicatorTopId); //评价集区间
|
||||
Indicator indicator = indicatorService.getIndicator(indicatorTopId); //获取指标
|
||||
|
||||
Map<Integer, String> indicatorWeightMap = evaluationTemplateIndicatorWeightService.getEvaluationTemplateIndicatorWeightMap(
|
||||
indicatorTopId, template.getId()); //指标权重map
|
||||
Map<Integer, List<IndicatorEvalItem>> indicatorEvalItemMap = indicatorEvalItemService.getIndicatorEvalItemMapByIndicatorTopId(
|
||||
indicatorTopId); //底部指标评价范围
|
||||
// 2. 根据数据源类型,选择并执行相应的策略
|
||||
String dataSourceType = request.getDatasourceType();
|
||||
if ("database".equals(dataSourceType)) {
|
||||
// 获取数据库数据源的特定映射关系
|
||||
List<IndicatorBottomFormMapper> mapperList = indicatorBottomFormMapperService.selectIndicatorToFieldNameListByIndicatorTopId(
|
||||
indicatorTopId);
|
||||
if (mapperList == null || mapperList.isEmpty()) {
|
||||
throw new EvaluationException("设施字段和指标没有设置映射关系");
|
||||
}
|
||||
Map<Integer, String> mappingMap = mapperList.stream().collect(
|
||||
Collectors.toMap(IndicatorBottomFormMapper::getIndicatorId,
|
||||
IndicatorBottomFormMapper::getFiledName));
|
||||
|
||||
// 创建数据库策略并执行
|
||||
DataSourceStrategy<FormValue> dbStrategy = new DatabaseSourceStrategy(formValueService,
|
||||
FormValue::getModelData);
|
||||
processEvaluation(request, userId, membershipFuncSet, topLevelList, indicator, mappingMap,
|
||||
dbStrategy, indicatorWeightMap, indicatorEvalItemMap);
|
||||
|
||||
} else if ("csv".equals(dataSourceType)) {
|
||||
// 获取CSV数据源的特定映射关系
|
||||
List<IndicatorBottomCsvMapper> mapperList = indicatorBottomCsvMapperService.selectIndicatorToFieldNameListByIndicatorTopId(
|
||||
indicatorTopId);
|
||||
if (mapperList == null || mapperList.isEmpty()) {
|
||||
throw new EvaluationException("CSV列和指标没有设置映射关系");
|
||||
}
|
||||
Map<Integer, String> mappingMap = mapperList.stream().collect(
|
||||
Collectors.toMap(IndicatorBottomCsvMapper::getIndicatorId,
|
||||
IndicatorBottomCsvMapper::getCsvColumnName));
|
||||
|
||||
// 创建CSV策略并执行
|
||||
DataSourceStrategy<EvaluationCsvData> csvStrategy = new CsvSourceStrategy(
|
||||
evaluationCsvDataService, EvaluationCsvData::getRawData);
|
||||
processEvaluation(request, userId, membershipFuncSet, topLevelList, indicator, mappingMap,
|
||||
csvStrategy, indicatorWeightMap, indicatorEvalItemMap);
|
||||
|
||||
} else {
|
||||
throw new EvaluationException("不支持的数据源类型: " + dataSourceType);
|
||||
}
|
||||
|
||||
} catch (EvaluationException e) {
|
||||
WsEvaluationServer.sendTips(e.getMessage(), request.getRandomKey());
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = (end - now) / 1000;
|
||||
WsEvaluationServer.sendTips("整体评估完成,总耗时" + diff + "秒", request.getRandomKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的评估处理流程,与具体数据源解耦.
|
||||
*
|
||||
* @param strategy 数据源策略,封装了如何获取数据的具体实现
|
||||
*/
|
||||
private <T> void processEvaluation(PageEvaluationRequest request, Integer userId,
|
||||
IndicatorTopSet membershipFuncSet, List<IndicatorTopLevel> topLevelList,
|
||||
Indicator indicator, Map<Integer, String> mappingMap,
|
||||
DataSourceStrategy<T> strategy, Map<Integer, String> indicatorWeightMap,
|
||||
Map<Integer, List<IndicatorEvalItem>> indicatorEvalItemMap) {
|
||||
|
||||
//首先记录本次评估
|
||||
request.setMembership(membershipFuncSet.getMembershipFunc());
|
||||
evaluationHistoryService.saveWhole(request);
|
||||
|
||||
boolean hasSpecificIds = request.getIds() != null && request.getIds().length > 0;
|
||||
|
||||
if (hasSpecificIds) {
|
||||
// --- 按指定ID列表进行评估 ---
|
||||
List<Integer> idList = Arrays.stream(request.getIds()).boxed().collect(Collectors.toList());
|
||||
List<T> dataList = strategy.fetchByIds(idList);
|
||||
|
||||
if (dataList != null && !dataList.isEmpty()) {
|
||||
List<SingleEvaluationData> evaluationData = strategy.extractData(dataList);
|
||||
startEvaluation(request, userId, membershipFuncSet, topLevelList, indicator, evaluationData,
|
||||
mappingMap, indicatorWeightMap, indicatorEvalItemMap);
|
||||
}
|
||||
} else {
|
||||
// --- 分页处理所有数据进行评估 ---
|
||||
PaginationBean paginationBean = new PaginationBean();
|
||||
paginationBean.setSearch(request.getSearch());
|
||||
paginationBean.setPageSize(DEFAULT_PAGE_SIZE);
|
||||
|
||||
paginationBean.setRandomKey(request.getRandomKey());
|
||||
paginationBean.setBusinessKey(request.getModelId());
|
||||
Long totalRecords = strategy.count(paginationBean);
|
||||
if (totalRecords == null || totalRecords == 0) {
|
||||
return; // 没有数据,直接返回
|
||||
}
|
||||
|
||||
int totalPages = (int) ((totalRecords + DEFAULT_PAGE_SIZE - 1) / DEFAULT_PAGE_SIZE);
|
||||
|
||||
for (int currentPage = 1; currentPage <= totalPages; currentPage++) {
|
||||
paginationBean.setCurrentPage(currentPage);
|
||||
List<T> currentPageData = strategy.fetchByPage(paginationBean);
|
||||
|
||||
if (currentPageData != null && !currentPageData.isEmpty()) {
|
||||
List<SingleEvaluationData> evaluationData = strategy.extractData(currentPageData);
|
||||
startEvaluation(request, userId, membershipFuncSet, topLevelList, indicator,
|
||||
evaluationData, mappingMap, indicatorWeightMap, indicatorEvalItemMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 数据源策略接口。 定义了数据访问的统一契约,将数据获取的算法从主流程中分离出来.
|
||||
*
|
||||
* @param <T> 数据源对应的实体类型 (如 FormValue, EvaluationCsvData)
|
||||
*/
|
||||
private interface DataSourceStrategy<T> {
|
||||
|
||||
List<T> fetchByIds(List<Integer> ids);
|
||||
|
||||
List<T> fetchByPage(PaginationBean paginationBean);
|
||||
|
||||
Long count(PaginationBean paginationBean);
|
||||
|
||||
List<SingleEvaluationData> extractData(List<T> dataList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库数据源的具体实现策略.
|
||||
*/
|
||||
private static class DatabaseSourceStrategy implements DataSourceStrategy<FormValue> {
|
||||
|
||||
private final FormValueService service;
|
||||
private final Function<FormValue, String> dataExtractor;
|
||||
|
||||
public DatabaseSourceStrategy(FormValueService service,
|
||||
Function<FormValue, String> dataExtractor) {
|
||||
this.service = service;
|
||||
this.dataExtractor = dataExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FormValue> fetchByIds(List<Integer> ids) {
|
||||
return service.selectByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FormValue> fetchByPage(PaginationBean paginationBean) {
|
||||
return service.list(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long count(PaginationBean paginationBean) {
|
||||
return service.count(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SingleEvaluationData> extractData(List<FormValue> dataList) {
|
||||
List<SingleEvaluationData> list = new ArrayList<>();
|
||||
dataList.forEach(value -> {
|
||||
SingleEvaluationData singleEvaluationData = new SingleEvaluationData();
|
||||
singleEvaluationData.setData(value.getModelData());
|
||||
singleEvaluationData.setId(value.getId());
|
||||
singleEvaluationData.setType("database");
|
||||
list.add(singleEvaluationData);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CSV文件数据源的具体实现策略.
|
||||
*/
|
||||
private static class CsvSourceStrategy implements DataSourceStrategy<EvaluationCsvData> {
|
||||
|
||||
private final EvaluationCsvDataService service;
|
||||
private final Function<EvaluationCsvData, String> dataExtractor;
|
||||
|
||||
public CsvSourceStrategy(EvaluationCsvDataService service,
|
||||
Function<EvaluationCsvData, String> dataExtractor) {
|
||||
this.service = service;
|
||||
this.dataExtractor = dataExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationCsvData> fetchByIds(List<Integer> ids) {
|
||||
|
||||
return service.selectByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationCsvData> fetchByPage(PaginationBean paginationBean) {
|
||||
return service.list(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long count(PaginationBean paginationBean) {
|
||||
return service.count(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SingleEvaluationData> extractData(List<EvaluationCsvData> dataList) {
|
||||
List<SingleEvaluationData> list = new ArrayList<>();
|
||||
dataList.forEach(value -> {
|
||||
SingleEvaluationData singleEvaluationData = new SingleEvaluationData();
|
||||
singleEvaluationData.setId(value.getId());
|
||||
singleEvaluationData.setType("csv");
|
||||
singleEvaluationData.setData(value.getRawData());
|
||||
list.add(singleEvaluationData);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private EvaluationTemplate getTemplateOrThrow(Integer templateId) {
|
||||
EvaluationTemplate template = evaluationTemplateService.getById(templateId);
|
||||
if (template == null) {
|
||||
throw new EvaluationException("没有找到对应的指标信息");
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private IndicatorTopSet getMembershipFuncSetOrThrow(Integer indicatorTopId) {
|
||||
IndicatorTopSet set = indicatorTopSetService.getIndicatorTopSet(indicatorTopId);
|
||||
if (set == null) {
|
||||
throw new EvaluationException("没有找到对应的隶属度函数");
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private List<IndicatorTopLevel> getTopLevelListOrThrow(Integer indicatorTopId) {
|
||||
List<IndicatorTopLevel> list = indicatorTopLevelService.getTopLevel(indicatorTopId);
|
||||
if (list == null || list.isEmpty()) {
|
||||
throw new EvaluationException("没有找到全局指标集区间和分值");
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
private static class EvaluationException extends RuntimeException {
|
||||
|
||||
public EvaluationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalEvaluationConfig globalEvaluationConfig(List<IndicatorTopLevel> topLevelList) {
|
||||
|
||||
topLevelList.sort((a, b) -> Integer.compare(b.getLevelOrder(), a.getLevelOrder()));
|
||||
List<EvaluationLevel> evaluationLevels = new ArrayList<>();
|
||||
|
||||
topLevelList.forEach(topLevel -> {
|
||||
EvaluationLevel evaluationLevel = new EvaluationLevel(topLevel.getLevelName(),
|
||||
Double.parseDouble(topLevel.getGrade()));
|
||||
evaluationLevels.add(evaluationLevel);
|
||||
});
|
||||
return new GlobalEvaluationConfig(evaluationLevels);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心评估触发点(此方法保持不变).
|
||||
*/
|
||||
private void startEvaluation(PageEvaluationRequest request, Integer userId,
|
||||
IndicatorTopSet membershipFuncSet, List<IndicatorTopLevel> topLevelList,
|
||||
Indicator indicator, List<SingleEvaluationData> originalList, Map<Integer, String> mappingMap,
|
||||
Map<Integer, String> indicatorWeightMap,
|
||||
Map<Integer, List<IndicatorEvalItem>> indicatorEvalItemMap) {
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
WsEvaluationServer.sendTips("分批次评估" + originalList.size() + "条记录",
|
||||
request.getRandomKey());
|
||||
|
||||
List<IndicatorNode> resultList = new ArrayList<>();
|
||||
//全局level等级及代表分
|
||||
GlobalEvaluationConfig globalEvaluationConfig = globalEvaluationConfig(topLevelList);
|
||||
//遍历数据
|
||||
for (SingleEvaluationData singleEvaluationData : originalList) {
|
||||
JSONObject jsonObject = JSON.parseObject(singleEvaluationData.getData());
|
||||
Map<String, Object> valueMap = new HashMap<>(jsonObject);
|
||||
IndicatorNode root = new IndicatorNode(indicator.getId() + "", indicator.getName());
|
||||
//工程ID
|
||||
root.setProjectId(request.getProjectId());
|
||||
//记录原始数据ID
|
||||
root.setOriginalId(indicator.getId());
|
||||
//记录数据来源
|
||||
root.setType(request.getDatasourceType());
|
||||
//本批次唯一标识
|
||||
root.setRandomKey(request.getRandomKey());
|
||||
//用户id
|
||||
root.setUserId(userId);
|
||||
//设置标识
|
||||
root.setLogicName(jsonObject.getString(request.getIdentifier()) == null ? ""
|
||||
: jsonObject.getString(request.getIdentifier()));
|
||||
root.setLevel(0);
|
||||
//设置隶属函数
|
||||
root.setMembershipFunction(new GlobalMembershipFunction(membershipFuncSet.getMembershipFunc(),
|
||||
Double.parseDouble(membershipFuncSet.getTriangleOverlapRatio()),
|
||||
|
||||
Double.parseDouble(membershipFuncSet.getTrianglePeakRatio()),
|
||||
Double.parseDouble(membershipFuncSet.getSoftEdgeS()),
|
||||
globalEvaluationConfig));
|
||||
//设置权重
|
||||
root.setWeight(indicatorWeightMap.get(indicator.getId()) == null ? 1
|
||||
: Double.parseDouble(indicatorWeightMap.get(indicator.getId())));
|
||||
recursionBuild(valueMap, indicatorWeightMap, indicator, root, mappingMap,
|
||||
globalEvaluationConfig, membershipFuncSet, indicatorEvalItemMap);
|
||||
|
||||
FuzzyEvaluationService service = new FuzzyEvaluationService(globalEvaluationConfig);
|
||||
service.performFuzzyEvaluation(root, FuzzyOperator.valueOf(request.getMethod()));
|
||||
resultList.add(root);
|
||||
}
|
||||
saveResult(resultList);
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = (end - now) / 1000;
|
||||
WsEvaluationServer.sendTips(
|
||||
"分批次结束评估" + originalList.size() + "条记录,耗时:" + diff + "秒",
|
||||
request.getRandomKey());
|
||||
}
|
||||
|
||||
private void saveResult(List<IndicatorNode> resultList) {
|
||||
resultList.forEach(indicatorNode -> {
|
||||
evaluationRootResultService.saveWhole(indicatorNode);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归一个根指标,设置实际值,隶属度,权重.
|
||||
*
|
||||
* @param valueMap 实际值map key=字段名称
|
||||
* @param indicatorWeightMap 权重map key=指标ID
|
||||
* @param indicator 当前指标
|
||||
* @param node 当前节点
|
||||
* @param mappingMap 指标id对应字段名称
|
||||
* @param globalEvaluationConfig 全局评价集集合
|
||||
* @param membershipFuncSet 全局隶属函数设置,告知采用那个函数
|
||||
* @param indicatorEvalItemMap 底部指标评价集区间
|
||||
*/
|
||||
private void recursionBuild(Map<String, Object> valueMap,
|
||||
Map<Integer, String> indicatorWeightMap,
|
||||
Indicator indicator, IndicatorNode node, Map<Integer, String> mappingMap,
|
||||
GlobalEvaluationConfig globalEvaluationConfig, IndicatorTopSet membershipFuncSet,
|
||||
Map<Integer, List<IndicatorEvalItem>> indicatorEvalItemMap) {
|
||||
if (indicator.getChildren() != null && !indicator.getChildren().isEmpty()) {
|
||||
node.setChildren(new ArrayList<>());
|
||||
indicator.getChildren().forEach(child -> {
|
||||
IndicatorNode childNode = new IndicatorNode(child.getId() + "", child.getName());
|
||||
childNode.setLevel(node.getLevel() + 1);
|
||||
//设置隶属函数
|
||||
childNode.setMembershipFunction(
|
||||
new GlobalMembershipFunction(membershipFuncSet.getMembershipFunc(),
|
||||
Double.parseDouble(membershipFuncSet.getTriangleOverlapRatio()),
|
||||
|
||||
Double.parseDouble(membershipFuncSet.getTrianglePeakRatio()),
|
||||
Double.parseDouble(membershipFuncSet.getSoftEdgeS()),
|
||||
globalEvaluationConfig));
|
||||
//设置权重
|
||||
childNode.setWeight(indicatorWeightMap.get(child.getId()) == null ? 1
|
||||
: Double.parseDouble(indicatorWeightMap.get(child.getId())));
|
||||
childNode.setOriginalId(child.getId());
|
||||
childNode.setRandomKey(node.getRandomKey());
|
||||
node.getChildren().add(childNode);
|
||||
|
||||
recursionBuild(valueMap, indicatorWeightMap, child, childNode, mappingMap,
|
||||
globalEvaluationConfig, membershipFuncSet, indicatorEvalItemMap);
|
||||
});
|
||||
} else { //是叶子节点,设置值,设置
|
||||
//根据mappingMap获取这个指标对应的输入字段
|
||||
String fieldName = mappingMap.get(indicator.getId());
|
||||
if (fieldName != null) {
|
||||
Object currentValue = valueMap.get(fieldName);
|
||||
if (currentValue != null) {
|
||||
node.setActualValue(Double.parseDouble(currentValue.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
if (indicatorEvalItemMap.get(indicator.getId()) != null) {
|
||||
List<IndicatorEvalItem> indicatorEvalItemList = indicatorEvalItemMap.get(indicator.getId());
|
||||
List<GradeRange> gradeRanges = getGradeRange(indicatorEvalItemList);
|
||||
if (membershipFuncSet.getMembershipFunc().equals("TRAP_TRI")) {
|
||||
node.setMembershipFunction(new LeafHybridMembershipFunction(gradeRanges,
|
||||
Double.parseDouble(membershipFuncSet.getTriangleOverlapRatio()),
|
||||
|
||||
Double.parseDouble(membershipFuncSet.getTrianglePeakRatio()),
|
||||
Double.parseDouble(membershipFuncSet.getSoftEdgeS()),
|
||||
globalEvaluationConfig));
|
||||
} else {
|
||||
node.setMembershipFunction(new LeafFullTriangularMembershipFunction(gradeRanges,
|
||||
Double.parseDouble(membershipFuncSet.getTriangleOverlapRatio()),
|
||||
|
||||
Double.parseDouble(membershipFuncSet.getTrianglePeakRatio()),
|
||||
Double.parseDouble(membershipFuncSet.getSoftEdgeS()),
|
||||
globalEvaluationConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<GradeRange> getGradeRange(List<IndicatorEvalItem> indicatorEvalItemList) {
|
||||
List<GradeRange> list = new ArrayList<>();
|
||||
indicatorEvalItemList.sort(
|
||||
Comparator.comparingDouble(a -> Double.parseDouble(a.getBottomValue())));
|
||||
indicatorEvalItemList.forEach(indicatorEvalItem -> {
|
||||
GradeRange gradeRange = new GradeRange(indicatorEvalItem.getEvaluationName(),
|
||||
Double.parseDouble(indicatorEvalItem.getBottomValue()),
|
||||
Double.parseDouble(indicatorEvalItem.getTopValue()));
|
||||
list.add(gradeRange);
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,61 @@
|
|||
package com.hshh.evaluation.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hshh.evaluation.bean.CsvUploadBean;
|
||||
import com.hshh.evaluation.entity.EvaluationCsvData;
|
||||
import com.hshh.evaluation.mapper.EvaluationCsvDataMapper;
|
||||
import com.hshh.evaluation.service.IEvaluationCsvDataService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hshh.evaluation.service.EvaluationCsvDataService;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
* 服务实现类.
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Service
|
||||
public class EvaluationCsvDataServiceImpl extends ServiceImpl<EvaluationCsvDataMapper, EvaluationCsvData> implements IEvaluationCsvDataService {
|
||||
public class EvaluationCsvDataServiceImpl extends
|
||||
ServiceImpl<EvaluationCsvDataMapper, EvaluationCsvData> implements
|
||||
EvaluationCsvDataService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveWhole(List<Map<String, String>> dataList, CsvUploadBean uploadInfo) {
|
||||
dataList.forEach(map -> {
|
||||
StringBuilder header = new StringBuilder();
|
||||
EvaluationCsvData evaluationCsvData = new EvaluationCsvData();
|
||||
//设置原始数据
|
||||
evaluationCsvData.setRawData(JSON.toJSONString(map));
|
||||
//设置随机key
|
||||
evaluationCsvData.setRandomKey(uploadInfo.getRandomKey());
|
||||
//时间
|
||||
evaluationCsvData.setCreateTime(LocalDateTime.now());
|
||||
//工程
|
||||
evaluationCsvData.setProjectId(uploadInfo.getProjectId());
|
||||
//设置表头
|
||||
evaluationCsvData.setCsvHeader(JSON.toJSONString(map.keySet()));
|
||||
save(evaluationCsvData);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationCsvData> list(PaginationBean paginationBean) {
|
||||
return this.baseMapper.list(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long count(PaginationBean paginationBean) {
|
||||
return this.baseMapper.count(paginationBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationCsvData> selectByIds(List<Integer> ids) {
|
||||
return this.baseMapper.selectByIds(ids);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
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.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.entity.EvaluationHistory;
|
||||
import com.hshh.evaluation.mapper.EvaluationHistoryMapper;
|
||||
import com.hshh.evaluation.service.EvaluationHistoryService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -15,7 +20,38 @@ import org.springframework.stereotype.Service;
|
|||
* @since 2025-08-21
|
||||
*/
|
||||
@Service
|
||||
public class EvaluationHistoryServiceImpl extends ServiceImpl<EvaluationHistoryMapper, EvaluationHistory> implements
|
||||
public class EvaluationHistoryServiceImpl extends
|
||||
ServiceImpl<EvaluationHistoryMapper, EvaluationHistory> implements
|
||||
EvaluationHistoryService {
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveWhole(PageEvaluationRequest request) {
|
||||
EvaluationHistory history = new EvaluationHistory();
|
||||
history.setCreateTime(LocalDateTime.now());
|
||||
history.setUserId(request.getUserId());
|
||||
history.setRandomKey(request.getRandomKey());
|
||||
history.setProjectId(request.getProjectId());
|
||||
history.setDatasourceType(request.getDatasourceType());
|
||||
history.setMembershipFunc(request.getMembership());
|
||||
history.setFuzzyOperator(request.getMethod());
|
||||
save(history);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationHistory queryRecentByProjectId(Integer projectId) {
|
||||
List<EvaluationHistory> list = this.baseMapper.queryRecentByProjectId(projectId);
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationHistory> queryListByProjectId(Integer projectId) {
|
||||
QueryWrapper<EvaluationHistory> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("project_id", projectId);
|
||||
queryWrapper.orderByDesc("id");
|
||||
return this.baseMapper.selectList(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,30 @@ 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.bean.CsvUploadBean;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
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.CoreEvaluationService;
|
||||
import com.hshh.evaluation.service.EvaluationCsvDataService;
|
||||
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.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
|
@ -37,29 +40,25 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
public class EvaluationProjectServiceImpl extends
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* 评估历史服务类.
|
||||
* 上传的csv文件数据记录服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationHistoryService evaluationHistoryService;
|
||||
private EvaluationCsvDataService evaluationCsvDataService;
|
||||
/**
|
||||
* 评估模板服务类.
|
||||
* 数据库记录评估服务.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateService evaluationTemplateService;
|
||||
/**
|
||||
* 数据查询服务类.
|
||||
*/
|
||||
@Resource
|
||||
private FormValueService formValueService;
|
||||
private CoreEvaluationService coreEvaluationService;
|
||||
|
||||
|
||||
@Override
|
||||
public List<EvaluationProject> list(PaginationBean paginationBean) {
|
||||
|
|
@ -103,125 +102,47 @@ public class EvaluationProjectServiceImpl extends
|
|||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void evaluate(EvaluationRequest request, Integer userId) {
|
||||
public void evaluate(PageEvaluationRequest request, Integer userId) {
|
||||
//评估接口单列
|
||||
coreEvaluationService.evaluation(request, userId);
|
||||
|
||||
//查询模板然后获取指标ID
|
||||
EvaluationTemplate template = evaluationTemplateService.getById(request.getTemplateId());
|
||||
}
|
||||
|
||||
//发送开始处理消息
|
||||
sendTips("开始处理", request.getRandomKey());
|
||||
@Override
|
||||
public void uploadCsv(CsvUploadBean uploadInfo) throws IOException {
|
||||
CSVFormat format = CSVFormat.DEFAULT
|
||||
.builder()
|
||||
.setHeader() // 表示第一行就是表头
|
||||
.setSkipHeaderRecord(true) // 跳过第一行数据,不把它算到记录里
|
||||
.setIgnoreEmptyLines(true)
|
||||
.setTrim(true)
|
||||
.build();
|
||||
//获取表头信息
|
||||
List<Map<String, String>> rows = new ArrayList<>();
|
||||
try (Reader reader = new InputStreamReader(uploadInfo.getFile().getInputStream(),
|
||||
StandardCharsets.UTF_8);
|
||||
CSVParser parser = new CSVParser(reader, format)) {
|
||||
|
||||
//插入评估历史表
|
||||
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);
|
||||
// 取有序表头:Apache 返回 Map<列名, 索引>,按索引排序得到原始顺序
|
||||
List<String> headers = parser.getHeaderMap()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.sorted(Comparator.comparingInt(Map.Entry::getValue))
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (CSVRecord rec : parser) {
|
||||
Map<String, String> obj = new LinkedHashMap<>();
|
||||
for (String h : headers) {
|
||||
// get(h):按列名取值,可能为 null
|
||||
obj.put(h, rec.isMapped(h) ? rec.get(h) : null);
|
||||
}
|
||||
rows.add(obj);
|
||||
|
||||
|
||||
}
|
||||
evaluationCsvDataService.saveWhole(rows, uploadInfo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//根据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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package com.hshh.evaluation.service.impl;
|
||||
|
||||
import com.hshh.evaluation.entity.EvaluationResult;
|
||||
import com.hshh.evaluation.mapper.EvaluationResultMapper;
|
||||
import com.hshh.evaluation.service.EvaluationResultService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 评估结果表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
* @since 2025-08-21
|
||||
*/
|
||||
@Service
|
||||
public class EvaluationResultServiceImpl extends ServiceImpl<EvaluationResultMapper, EvaluationResult> implements
|
||||
EvaluationResultService {
|
||||
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -24,7 +25,7 @@ public class EvaluationTemplateIndicatorWeightServiceImpl extends
|
|||
EvaluationTemplateIndicatorWeightService {
|
||||
|
||||
@Override
|
||||
public Map<Integer, Double> getEvaluationTemplateIndicatorWeightMap(Integer indicatorTopId,
|
||||
public Map<Integer, String> getEvaluationTemplateIndicatorWeightMap(Integer indicatorTopId,
|
||||
Integer templateId) {
|
||||
QueryWrapper<EvaluationTemplateIndicatorWeight> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("indicator_top_id", indicatorTopId);
|
||||
|
|
@ -37,4 +38,26 @@ public class EvaluationTemplateIndicatorWeightServiceImpl extends
|
|||
}
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveEvaluationTemplateIndicatorWeight(Integer templateId, Integer indicatorTopId,
|
||||
List<EvaluationTemplateIndicatorWeight> list) {
|
||||
//先删除旧信息
|
||||
QueryWrapper<EvaluationTemplateIndicatorWeight> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("template_id", templateId);
|
||||
wrapper.eq("indicator_top_id", indicatorTopId);
|
||||
this.remove(wrapper);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
list.forEach(this::save);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByTemplateIdAndIndicatorTopId(Integer templateId, Integer indicatorTopId) {
|
||||
QueryWrapper<EvaluationTemplateIndicatorWeight> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("template_id", templateId);
|
||||
wrapper.eq("indicator_top_id", indicatorTopId);
|
||||
this.remove(wrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@ 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.entity.EvaluationTemplate;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateIndicatorWeight;
|
||||
import com.hshh.evaluation.entity.EvaluationTemplateWeight;
|
||||
import com.hshh.evaluation.mapper.EvaluationTemplateMapper;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateIndicatorWeightService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateService;
|
||||
import com.hshh.evaluation.service.EvaluationTemplateWeightService;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -24,8 +26,16 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
public class EvaluationTemplateServiceImpl extends
|
||||
ServiceImpl<EvaluationTemplateMapper, EvaluationTemplate> implements EvaluationTemplateService {
|
||||
|
||||
/**
|
||||
* 指标互比详情服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateWeightService evaluationTemplateWeightService;
|
||||
private EvaluationTemplateWeightService evaluationTemplateDetailWeightService;
|
||||
/**
|
||||
* 指标权重服务类.
|
||||
*/
|
||||
@Resource
|
||||
private EvaluationTemplateIndicatorWeightService evaluationTemplateIndicatorWeightService;
|
||||
|
||||
@Override
|
||||
public List<EvaluationTemplate> list(PaginationBean search) {
|
||||
|
|
@ -39,42 +49,52 @@ public class EvaluationTemplateServiceImpl extends
|
|||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveWhole(EvaluationTemplate evaluationTemplate,
|
||||
Map<Integer, DraftWeightData> weightDataMap) {
|
||||
public void saveWhole(EvaluationTemplate evaluationTemplate
|
||||
) {
|
||||
//保存或者更新模板信息
|
||||
saveOrUpdate(evaluationTemplate);
|
||||
if (weightDataMap != null && !weightDataMap.isEmpty()) {
|
||||
|
||||
weightDataMap.forEach((k, v) -> {
|
||||
//先按模板ID+上级指标ID
|
||||
evaluationTemplateWeightService.deleteEvaluationTemplateWeightWithTemplateIdAndIndicatorId(
|
||||
evaluationTemplate.getId(), evaluationTemplate.getIndicatorTopId(), k);
|
||||
v.getWeight().forEach(weightBeanList -> {
|
||||
weightBeanList.forEach(weightBean -> {
|
||||
EvaluationTemplateWeight evaluationTemplateWeight = new EvaluationTemplateWeight();
|
||||
//设置模板ID
|
||||
evaluationTemplateWeight.setTemplateId(evaluationTemplate.getId());
|
||||
//设置权重
|
||||
evaluationTemplateWeight.setWeight(Double.valueOf(weightBean.getValue()));
|
||||
//设置顶级指标ID
|
||||
evaluationTemplateWeight.setIndicatorTopId(evaluationTemplate.getIndicatorTopId());
|
||||
//fromIndicatorId
|
||||
evaluationTemplateWeight.setFromIndicatorId(weightBean.getRowId());
|
||||
//toIndicatorId
|
||||
evaluationTemplateWeight.setToIndicatorId(weightBean.getColId());
|
||||
//设置上级指标ID
|
||||
evaluationTemplateWeight.setIndicatorParentId(weightBean.getParentId());
|
||||
//设置行号
|
||||
evaluationTemplateWeight.setRowNum(weightBean.getRowNum());
|
||||
//保存
|
||||
evaluationTemplateWeightService.save(evaluationTemplateWeight);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
//保存指标权重信息
|
||||
List<EvaluationTemplateIndicatorWeight> indicatorWeightList = new ArrayList<>();
|
||||
if (evaluationTemplate.getIndicatorWeightList() != null
|
||||
&& !evaluationTemplate.getIndicatorWeightList()
|
||||
.isEmpty()) {
|
||||
evaluationTemplate.getIndicatorWeightList().forEach(a -> {
|
||||
EvaluationTemplateIndicatorWeight indicatorWeight = new EvaluationTemplateIndicatorWeight();
|
||||
indicatorWeight.setWeight(a.getWeight());
|
||||
//设置模板ID
|
||||
indicatorWeight.setTemplateId(evaluationTemplate.getId());
|
||||
//设置顶级指标ID
|
||||
indicatorWeight.setIndicatorTopId(evaluationTemplate.getIndicatorTopId());
|
||||
//设置指标ID
|
||||
indicatorWeight.setIndicatorId(a.getIndicatorId());
|
||||
indicatorWeightList.add(indicatorWeight);
|
||||
});
|
||||
|
||||
evaluationTemplateIndicatorWeightService.saveEvaluationTemplateIndicatorWeight(
|
||||
evaluationTemplate.getId(), evaluationTemplate.getIndicatorTopId(), indicatorWeightList);
|
||||
}
|
||||
|
||||
//保存各个指标之间互相比较的权重信息
|
||||
if (evaluationTemplate.getTemplateDetailWeightList() != null
|
||||
&& !evaluationTemplate.getTemplateDetailWeightList()
|
||||
.isEmpty()) {
|
||||
List<EvaluationTemplateWeight> detailList = new ArrayList<>();
|
||||
evaluationTemplate.getTemplateDetailWeightList().forEach(a -> {
|
||||
EvaluationTemplateWeight detailWeight = new EvaluationTemplateWeight();
|
||||
//设置模板ID
|
||||
detailWeight.setTemplateId(evaluationTemplate.getId());
|
||||
//设置顶级指标ID
|
||||
detailWeight.setIndicatorTopId(evaluationTemplate.getIndicatorTopId());
|
||||
detailWeight.setFromIndicatorId(a.getRowId());
|
||||
detailWeight.setToIndicatorId(a.getColId());
|
||||
detailWeight.setWeight(a.getValue());
|
||||
detailWeight.setIndicatorParentId(a.getParentId());
|
||||
detailWeight.setRowNum(a.getRowNum());
|
||||
detailList.add(detailWeight);
|
||||
});
|
||||
evaluationTemplateDetailWeightService.saveIndicatorMatrix(evaluationTemplate.getId(),
|
||||
evaluationTemplate.getIndicatorTopId(), detailList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -87,8 +107,14 @@ public class EvaluationTemplateServiceImpl extends
|
|||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void deleteTemplate(EvaluationTemplate evaluationTemplate) {
|
||||
evaluationTemplateWeightService.deleteEvaluationTemplateWeightWithTemplateId(
|
||||
evaluationTemplate.getId());
|
||||
|
||||
//删除互比信息
|
||||
evaluationTemplateDetailWeightService.deleteByTemplateIdAndIndicatorTopId(
|
||||
evaluationTemplate.getId(), evaluationTemplate.getIndicatorTopId());
|
||||
//删除指标权重信息
|
||||
evaluationTemplateIndicatorWeightService.deleteByTemplateIdAndIndicatorTopId(
|
||||
evaluationTemplate.getId(), evaluationTemplate.getIndicatorTopId());
|
||||
//删除模板
|
||||
this.removeById(evaluationTemplate.getId());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -25,25 +24,6 @@ public class EvaluationTemplateWeightServiceImpl extends
|
|||
EvaluationTemplateWeightService {
|
||||
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void deleteEvaluationTemplateWeightWithTemplateIdAndIndicatorId(Integer templateId,
|
||||
Integer indicatorTopId, Integer parentId) {
|
||||
QueryWrapper<EvaluationTemplateWeight> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("template_id", templateId);
|
||||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
queryWrapper.eq("indicator_parent_id", parentId);
|
||||
this.remove(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteEvaluationTemplateWeightWithTemplateId(Integer templateId) {
|
||||
QueryWrapper<EvaluationTemplateWeight> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("template_id", templateId);
|
||||
|
||||
this.remove(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationTemplateWeight> queryListByIndicatorParentIdAndTemplateId(
|
||||
Integer indicatorParentId, Integer templateId) {
|
||||
|
|
@ -57,7 +37,7 @@ public class EvaluationTemplateWeightServiceImpl extends
|
|||
@Override
|
||||
public Map<Integer, List<EvaluationTemplateWeight>> groupByParentIndicatorId(
|
||||
Integer indicatorParentId, Integer templateId) {
|
||||
List<EvaluationTemplateWeight> list = this.queryListByIndicatorParentIdAndTemplateId(
|
||||
List<EvaluationTemplateWeight> list = this.queryListByIndicatorTopIdAndTemplateId(
|
||||
indicatorParentId, templateId);
|
||||
if (!list.isEmpty()) {
|
||||
return list.stream()
|
||||
|
|
@ -65,4 +45,33 @@ public class EvaluationTemplateWeightServiceImpl extends
|
|||
}
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveIndicatorMatrix(Integer templateId, Integer indicatorTopId,
|
||||
List<EvaluationTemplateWeight> weightList) {
|
||||
QueryWrapper<EvaluationTemplateWeight> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("template_id", templateId);
|
||||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
this.remove(queryWrapper);
|
||||
if (weightList != null && !weightList.isEmpty()) {
|
||||
weightList.forEach(this::save);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByTemplateIdAndIndicatorTopId(Integer templateId, Integer indicatorTopId) {
|
||||
QueryWrapper<EvaluationTemplateWeight> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("template_id", templateId);
|
||||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
this.remove(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EvaluationTemplateWeight> queryListByIndicatorTopIdAndTemplateId(
|
||||
Integer indicatorTopId, Integer templateId) {
|
||||
QueryWrapper<EvaluationTemplateWeight> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("template_id", templateId);
|
||||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
return this.list(queryWrapper);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package com.hshh.indicator.bean;
|
||||
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import com.hshh.system.common.bean.JsTree;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* [类的简要说明]
|
||||
* <p>
|
||||
* [详细描述,可选]
|
||||
* <p>
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class IndicatorEvalBean {
|
||||
|
||||
private List<JsTree> jsTreeList;
|
||||
//评价集范围
|
||||
private List<IndicatorEvalItem> evalItemList;
|
||||
//顶级指标ID
|
||||
private Integer indicatorTopId;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.hshh.indicator.bean;
|
||||
|
||||
import com.hshh.indicator.entity.IndicatorTopLevel;
|
||||
import com.hshh.indicator.entity.IndicatorTopSet;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 接收全局指标level,隶属函数bean.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Data
|
||||
public class IndicatorSetBean {
|
||||
|
||||
private List<IndicatorTopLevel> levels;
|
||||
private IndicatorTopSet topSet;
|
||||
}
|
||||
|
|
@ -1,20 +1,23 @@
|
|||
package com.hshh.indicator.controller;
|
||||
|
||||
import com.hshh.indicator.bean.IndicatorEvalBean;
|
||||
import com.hshh.indicator.entity.Indicator;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import com.hshh.indicator.service.IndicatorEvalItemService;
|
||||
import com.hshh.indicator.service.IndicatorService;
|
||||
import com.hshh.indicator.service.IndicatorTopLevelService;
|
||||
import com.hshh.indicator.service.IndicatorTopSetService;
|
||||
import com.hshh.system.annotation.LogOperation;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.bean.JsTree;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
import com.hshh.system.common.enums.ErrorCode;
|
||||
import com.hshh.system.common.enums.ErrorMessage;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
|
@ -32,13 +35,14 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
@RequestMapping("/evaluation")
|
||||
public class EvaluationController extends BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* 指标服务类. 查询所有指标列表
|
||||
* 指标服务类.
|
||||
*/
|
||||
@Resource
|
||||
private IndicatorService indicatorService;
|
||||
/**
|
||||
* 评价服务类.
|
||||
* 指标评价集范围服务类.
|
||||
*/
|
||||
@Resource
|
||||
private IndicatorEvalItemService indicatorEvalItemService;
|
||||
|
|
@ -49,107 +53,87 @@ public class EvaluationController extends BaseController {
|
|||
* @return indicator/evaluation_list.html
|
||||
*/
|
||||
@GetMapping("/evaluationList")
|
||||
public String evaluationList(Integer topIndicatorId, Integer indicatorId, Model model) {
|
||||
public String evaluationList(Model model) {
|
||||
setNavigateTitle(model, "/evaluation/evaluationList");
|
||||
List<Indicator> rootList = indicatorService.queryRootList();
|
||||
if (rootList != null && !rootList.isEmpty()) {
|
||||
if (topIndicatorId != null) {
|
||||
for (Indicator indicator : rootList) {
|
||||
if (indicator.getId().equals(topIndicatorId)) {
|
||||
//回显上次选择的
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
//查询子指标的评价集
|
||||
List<IndicatorEvalItem> evaluationList = indicatorEvalItemService.queryListByIndicatorId(
|
||||
(indicatorId == null ? indicatorListWithoutChildren.get(0).getId() : indicatorId)
|
||||
);
|
||||
model.addAttribute("evaluationList", evaluationList);
|
||||
model.addAttribute("indicatorListWithoutChildren", indicatorListWithoutChildren);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
model.addAttribute("rootList", rootList);
|
||||
|
||||
List<Indicator> bottomList = indicatorService.queryRootList();
|
||||
model.addAttribute("rootList", bottomList);
|
||||
return "indicator/evaluation_list";
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航到评价集增加页面.
|
||||
* 获取当前指标的评价信息.
|
||||
*
|
||||
* @return indicator/add_evaluation.html
|
||||
* @param id 指标ID
|
||||
* @return 评价详细信息
|
||||
*/
|
||||
@RequestMapping("/evaluationAdd")
|
||||
@Operation(summary = "导航到评价集增加页面", description = "导航到评价集增加页面")
|
||||
public String evaluationAdd() {
|
||||
return "indicator/add_evaluation";
|
||||
@GetMapping("/{id}")
|
||||
@ResponseBody
|
||||
|
||||
public OperateResult<IndicatorEvalBean> metricIdChange(@PathVariable("id") Integer id) {
|
||||
IndicatorEvalBean indicatorEvalBean = new IndicatorEvalBean();
|
||||
|
||||
//查询底部评价集
|
||||
indicatorEvalBean.setJsTreeList(evalItemTree(id));
|
||||
return OperateResult.success(indicatorEvalBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存评价集.
|
||||
* 建立底部指标树.
|
||||
*
|
||||
* @param item 评价集数据
|
||||
* @param bindingResult 字段错误信息
|
||||
* @param id 根指标
|
||||
* @return 包含底部指标的树
|
||||
*/
|
||||
private List<JsTree> evalItemTree(Integer id) {
|
||||
List<JsTree> jsTreeList = new ArrayList<>();
|
||||
JsTree jsTree = new JsTree();
|
||||
jsTree.setText("根指标");
|
||||
jsTree.setId("0");
|
||||
jsTreeList.add(jsTree);
|
||||
jsTree.setChildren(new ArrayList<>());
|
||||
//查询根部指标所有底部指标
|
||||
List<Indicator> bottomList = indicatorService.selectNoChildByTopId(
|
||||
id);
|
||||
//查询底部指标的评价集范围
|
||||
Map<Integer, List<IndicatorEvalItem>> evalMap = indicatorEvalItemService.getIndicatorEvalItemMapByIndicatorTopId(
|
||||
id);
|
||||
bottomList.forEach(a -> {
|
||||
JsTree child = new JsTree();
|
||||
jsTree.getChildren().add(child);
|
||||
child.setId("tree_" + a.getId());
|
||||
child.setOriginalId(a.getId());
|
||||
child.setText(a.getName());
|
||||
if (evalMap.containsKey(a.getId())) {
|
||||
List<IndicatorEvalItem> evalItemList = evalMap.get(a.getId());
|
||||
evalItemList = evalItemList.stream().peek(aa -> {
|
||||
if (aa.getEqualValue() == null) {
|
||||
aa.setEqualValue("");
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
StringBuilder tipBuilder = new StringBuilder();
|
||||
evalItemList.forEach(evalItem -> {
|
||||
tipBuilder.append(evalItem.getEvaluationName()).append(":")
|
||||
.append(evalItem.getBottomValue())
|
||||
.append(",").append(evalItem.getTopValue());
|
||||
child.setText(a.getName() + "(" + tipBuilder + ")");
|
||||
});
|
||||
child.getData().put("range", evalItemList);
|
||||
}
|
||||
|
||||
});
|
||||
return jsTreeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存评价集,隶属函数设置,评级集枚举和分值.
|
||||
*
|
||||
* @param data 前端数据
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
@ResponseBody
|
||||
public OperateResult<Object> save(@Valid @RequestBody IndicatorEvalItem item,
|
||||
BindingResult bindingResult) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
return errorsInputHandle(bindingResult);
|
||||
}
|
||||
indicatorEvalItemService.saveOrUpdate(item);
|
||||
@LogOperation("保存评价集")
|
||||
public OperateResult<Void> save(@RequestBody IndicatorEvalBean data) {
|
||||
indicatorEvalItemService.saveWhole(data);
|
||||
return OperateResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id删除评价.
|
||||
*
|
||||
* @param id 要删除的id
|
||||
* @return 操作结果
|
||||
*/
|
||||
@GetMapping("/remove/{id}")
|
||||
@ResponseBody
|
||||
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
|
||||
IndicatorEvalItem evaluation = indicatorEvalItemService.getById(id);
|
||||
if (evaluation == null) {
|
||||
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
|
||||
ErrorCode.BUSINESS_ERROR.getCode());
|
||||
}
|
||||
indicatorEvalItemService.removeById(id);
|
||||
return OperateResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询评价信息.
|
||||
*
|
||||
* @param id 评价ID
|
||||
* @return id对应的评价
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@ResponseBody
|
||||
public OperateResult<IndicatorEvalItem> view(@PathVariable("id") Integer id) {
|
||||
IndicatorEvalItem evaluation = indicatorEvalItemService.getById(id);
|
||||
if (evaluation == null) {
|
||||
return OperateResult.error(null, ErrorMessage.ID_NOT_EXIT.getMessage(),
|
||||
ErrorCode.BUSINESS_ERROR.getCode());
|
||||
}
|
||||
return OperateResult.success(evaluation, ErrorMessage.SUCCESS.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.hshh.model.entity.FormFieldConfig;
|
|||
import com.hshh.model.entity.ModelDefine;
|
||||
import com.hshh.model.service.FormFieldConfigService;
|
||||
import com.hshh.model.service.ModelDefineService;
|
||||
import com.hshh.system.annotation.LogOperation;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.bean.CheckedBean;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
|
|
@ -138,7 +139,7 @@ public class IndicatorController extends BaseController {
|
|||
List<ModelDefine> modelDefineList = modelDefineService.list();
|
||||
model.addAttribute("modelDefineList", modelDefineList);
|
||||
}
|
||||
return "/indicator/add_indicator";
|
||||
return "indicator/add_indicator";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -165,6 +166,7 @@ public class IndicatorController extends BaseController {
|
|||
* @param bindingResult 字段验证信息
|
||||
* @return 保存结果
|
||||
*/
|
||||
@LogOperation("保存指标")
|
||||
@PostMapping("/save")
|
||||
@ResponseBody
|
||||
@Operation(summary = "保存指标", description = "验证后保存指标")
|
||||
|
|
@ -202,6 +204,7 @@ public class IndicatorController extends BaseController {
|
|||
*/
|
||||
@GetMapping("/remove/{id}")
|
||||
@ResponseBody
|
||||
@LogOperation("删除指标")
|
||||
@Operation(summary = "删除指标", description = "根据ID删除指定指标")
|
||||
public OperateResult<Void> remove(@PathVariable("id") Integer id) {
|
||||
if (id == null) {
|
||||
|
|
@ -337,6 +340,7 @@ public class IndicatorController extends BaseController {
|
|||
*/
|
||||
@PostMapping("/uploadCsv")
|
||||
@ResponseBody
|
||||
@LogOperation("上传csv文件")
|
||||
public OperateResult<List<IndicatorCsvColumn>> uploadCsv(@RequestParam("file") MultipartFile file,
|
||||
Integer indicatorTopId) throws IOException {
|
||||
List<IndicatorCsvColumn> list = indicatorService.saveIndicatorTopCsvMapper(indicatorTopId,
|
||||
|
|
@ -356,6 +360,7 @@ public class IndicatorController extends BaseController {
|
|||
*/
|
||||
@PostMapping("/indicatorFormMapper")
|
||||
@ResponseBody
|
||||
@LogOperation("保存指标和form表单ID的映射关系")
|
||||
public OperateResult<List<FormFieldConfig>> saveIndicatorFormMapper(
|
||||
@RequestBody IndicatorFormMapper formMapper) {
|
||||
indicatorTopMapperService.saveFormMapper(formMapper);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package com.hshh.indicator.controller;
|
||||
|
||||
import com.hshh.indicator.bean.IndicatorSetBean;
|
||||
import com.hshh.system.common.bean.BaseController;
|
||||
import com.hshh.system.common.bean.OperateResult;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* 指标全局函数设置.
|
||||
*
|
||||
* @author LiDongYU
|
||||
* @since 2025/7/22
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/indicatorSet")
|
||||
@Tag(name = "指标全局函数设置", description = "指标全局函数设置")
|
||||
public class IndicatorSetController extends BaseController {
|
||||
|
||||
/**
|
||||
* 指标全局函数默认设置页面.
|
||||
*
|
||||
* @param model 数据容器
|
||||
* @param request 页面请求
|
||||
* @return indicator_set.html
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public String list(Model model, HttpServletRequest request) {
|
||||
setNavigateTitle(model, "/indicatorSet/list");
|
||||
return "system/indicator/indicator_set";
|
||||
}
|
||||
@PostMapping("/save")
|
||||
public OperateResult<Void> save(@RequestBody IndicatorSetBean indicatorSetBean) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
|||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.hshh.system.common.bean.CheckedBean;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
|
@ -47,5 +48,15 @@ public class Indicator extends CheckedBean {
|
|||
|
||||
@TableField(exist = false)
|
||||
private double weight;
|
||||
//当前值
|
||||
@TableField(exist = false)
|
||||
private String value;
|
||||
|
||||
//隶属度描述
|
||||
@TableField(exist = false)
|
||||
private Map<String, String> membership;
|
||||
|
||||
//得分
|
||||
@TableField(exist = false)
|
||||
private String score;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.indicator.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
|
@ -17,58 +18,69 @@ import java.io.Serializable;
|
|||
|
||||
public class IndicatorBottomCsvMapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
private static final long serialVersionUID = 1L;
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
|
||||
private Integer indicatorTopId;
|
||||
private Integer indicatorTopId;
|
||||
|
||||
|
||||
private Integer indicatorId;
|
||||
private Integer indicatorId;
|
||||
|
||||
|
||||
private Integer csvColumnId;
|
||||
private Integer csvColumnId;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getIndicatorTopId() {
|
||||
return indicatorTopId;
|
||||
}
|
||||
public Integer getIndicatorTopId() {
|
||||
return indicatorTopId;
|
||||
}
|
||||
|
||||
public void setIndicatorTopId(Integer indicatorTopId) {
|
||||
this.indicatorTopId = indicatorTopId;
|
||||
}
|
||||
public void setIndicatorTopId(Integer indicatorTopId) {
|
||||
this.indicatorTopId = indicatorTopId;
|
||||
}
|
||||
|
||||
public Integer getIndicatorId() {
|
||||
return indicatorId;
|
||||
}
|
||||
public Integer getIndicatorId() {
|
||||
return indicatorId;
|
||||
}
|
||||
|
||||
public void setIndicatorId(Integer indicatorId) {
|
||||
this.indicatorId = indicatorId;
|
||||
}
|
||||
public void setIndicatorId(Integer indicatorId) {
|
||||
this.indicatorId = indicatorId;
|
||||
}
|
||||
|
||||
public Integer getCsvColumnId() {
|
||||
return csvColumnId;
|
||||
}
|
||||
public Integer getCsvColumnId() {
|
||||
return csvColumnId;
|
||||
}
|
||||
|
||||
public void setCsvColumnId(Integer csvColumnId) {
|
||||
this.csvColumnId = csvColumnId;
|
||||
}
|
||||
public void setCsvColumnId(Integer csvColumnId) {
|
||||
this.csvColumnId = csvColumnId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndicatorBottomCsvMapper{" +
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndicatorBottomCsvMapper{" +
|
||||
"id = " + id +
|
||||
", indicatorTopId = " + indicatorTopId +
|
||||
", indicatorId = " + indicatorId +
|
||||
", csvColumnId = " + csvColumnId +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
@TableField(exist = false)
|
||||
private String csvColumnName;
|
||||
|
||||
public String getCsvColumnName() {
|
||||
return csvColumnName;
|
||||
}
|
||||
|
||||
public void setCsvColumnName(String csvColumnName) {
|
||||
this.csvColumnName = csvColumnName;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.indicator.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
|
@ -28,10 +29,7 @@ public class IndicatorBottomFormMapper implements Serializable {
|
|||
private Integer formFieldId;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private Integer indicatorTopId;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String filedName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.indicator.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
|
@ -32,27 +33,13 @@ public class IndicatorEvalItem implements Serializable {
|
|||
private Integer indicatorId;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
@NotNull(message = "名称不能为空")
|
||||
@Size(max = 50, message = "名称不能超过50字符")
|
||||
private String evaluationName;
|
||||
private String topValue;
|
||||
|
||||
@NotNull(message = "符号不能为空")
|
||||
@Size(max = 5, message = "名称不能超过5字符")
|
||||
private String minSymbol;
|
||||
|
||||
@NotNull(message = "值不能为空")
|
||||
@Size(max = 10, message = "值不能超过10字符")
|
||||
private String minValue;
|
||||
|
||||
@NotNull(message = "符号不能为空")
|
||||
@Size(max = 5, message = "名称不能超过5字符")
|
||||
private String maxSymbol;
|
||||
|
||||
@NotNull(message = "值不能为空")
|
||||
@Size(max = 10, message = "值不能超过10字符")
|
||||
private String maxValue;
|
||||
@NotNull(message = "值不能为空")
|
||||
private Double grade;
|
||||
private String bottomValue;
|
||||
//除去范围外,等于某个字符串值
|
||||
private String equalValue;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.hshh.indicator.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
|
@ -27,4 +28,5 @@ public class IndicatorFormMapper implements Serializable {
|
|||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.hshh.indicator.mapper;
|
||||
|
||||
import com.hshh.indicator.entity.IndicatorBottomCsvMapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hshh.indicator.entity.IndicatorBottomCsvMapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
|
@ -13,4 +14,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||
*/
|
||||
public interface IndicatorBottomCsvMapperMapper extends BaseMapper<IndicatorBottomCsvMapper> {
|
||||
|
||||
/**
|
||||
* 根据根指标查找对应关系.
|
||||
*
|
||||
* @param indicatorTopId 根指标
|
||||
* @return 对应关系列表
|
||||
*/
|
||||
List<IndicatorBottomCsvMapper> selectByIndicatorTopId(Integer indicatorTopId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package com.hshh.indicator.mapper;
|
||||
|
||||
import com.hshh.indicator.entity.IndicatorBottomFormMapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hshh.indicator.entity.IndicatorBottomFormMapper;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author liDongYu
|
||||
|
|
@ -13,5 +14,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||
*/
|
||||
public interface IndicatorBottomMapperMapper extends BaseMapper<IndicatorBottomFormMapper> {
|
||||
|
||||
/**
|
||||
* 查找指标ID和字段名称的对应关系.
|
||||
*
|
||||
* @param topId 根指标ID
|
||||
* @return 对应关系列表
|
||||
*/
|
||||
List<IndicatorBottomFormMapper> selectByIndicatorTopId(Integer topId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,4 +27,12 @@ public interface IndicatorBottomCsvMapperService extends IService<IndicatorBotto
|
|||
* @param indicatorTopId 顶部指标ID
|
||||
*/
|
||||
void deleteByIndicatorTopId(Integer indicatorTopId);
|
||||
|
||||
/**
|
||||
* 根据指标ID获取对应关系.
|
||||
*
|
||||
* @param topId 根指标ID
|
||||
* @return 对应关系列表
|
||||
*/
|
||||
List<IndicatorBottomCsvMapper> selectIndicatorToFieldNameListByIndicatorTopId(Integer topId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,4 +34,11 @@ public interface IndicatorBottomFormMapperService extends IService<IndicatorBott
|
|||
*/
|
||||
void saveMapper(List<IndicatorBottomFormMapper> indicatorBottomFormMapperList);
|
||||
|
||||
/**
|
||||
* 查找指标ID和字段名称的对应关系.
|
||||
*
|
||||
* @param topId 根指标ID
|
||||
* @return 对应关系列表
|
||||
*/
|
||||
List<IndicatorBottomFormMapper> selectIndicatorToFieldNameListByIndicatorTopId(Integer topId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.hshh.indicator.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hshh.evaluation.bean.EvalItemToFieldInfo;
|
||||
import com.hshh.indicator.bean.IndicatorEvalBean;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -15,35 +15,18 @@ import java.util.Map;
|
|||
public interface IndicatorEvalItemService extends IService<IndicatorEvalItem> {
|
||||
|
||||
/**
|
||||
* 根据指标ID和名称查询记录.
|
||||
* 根据顶级指标查询返回以子指标为key,value为子指标评价范围集合.
|
||||
*
|
||||
* @param indicatorId 指标ID
|
||||
* @param name 名称
|
||||
* @return 记录
|
||||
* @param indicatorTopId 顶级指标
|
||||
* @return 以子指标分类的评价集范围
|
||||
*/
|
||||
List<IndicatorEvalItem> queryListByNameAndIndicatorId(Integer indicatorId, String name);
|
||||
Map<Integer, List<IndicatorEvalItem>> getIndicatorEvalItemMapByIndicatorTopId(
|
||||
Integer indicatorTopId);
|
||||
|
||||
/**
|
||||
* 根据子指标查询他的评价集.
|
||||
* 保存评价集
|
||||
*
|
||||
* @param indicatorId 子指标
|
||||
* @return 评价集
|
||||
* @param data 前端数据
|
||||
*/
|
||||
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);
|
||||
void saveWhole(IndicatorEvalBean data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,4 +39,10 @@ public class IndicatorBottomCsvMapperServiceImpl extends
|
|||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
remove(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndicatorBottomCsvMapper> selectIndicatorToFieldNameListByIndicatorTopId(
|
||||
Integer topId) {
|
||||
return this.baseMapper.selectByIndicatorTopId(topId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,4 +41,9 @@ public class IndicatorBottomMapperServiceImpl extends
|
|||
public void saveMapper(List<IndicatorBottomFormMapper> indicatorBottomFormMapperList) {
|
||||
indicatorBottomFormMapperList.forEach(this::save);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndicatorBottomFormMapper> selectIndicatorToFieldNameListByIndicatorTopId(Integer topId) {
|
||||
return this.baseMapper.selectByIndicatorTopId(topId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,18 @@ 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.bean.IndicatorEvalBean;
|
||||
import com.hshh.indicator.entity.IndicatorEvalItem;
|
||||
import com.hshh.indicator.mapper.IndicatorEvalItemMapper;
|
||||
import com.hshh.indicator.service.IndicatorEvalItemService;
|
||||
import com.hshh.indicator.service.IndicatorTopLevelService;
|
||||
import com.hshh.indicator.service.IndicatorTopSetService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 指标规则表 服务实现类.
|
||||
|
|
@ -20,36 +25,31 @@ import org.springframework.stereotype.Service;
|
|||
public class IndicatorEvalItemServiceImpl extends
|
||||
ServiceImpl<IndicatorEvalItemMapper, IndicatorEvalItem> implements IndicatorEvalItemService {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<IndicatorEvalItem> queryListByNameAndIndicatorId(Integer indicatorId, String name) {
|
||||
public Map<Integer, List<IndicatorEvalItem>> getIndicatorEvalItemMapByIndicatorTopId(
|
||||
Integer indicatorTopId) {
|
||||
QueryWrapper<IndicatorEvalItem> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("indicator_id", indicatorId);
|
||||
queryWrapper.eq("evaluation_name", name);
|
||||
queryWrapper.eq("indicator_top_id", indicatorTopId);
|
||||
queryWrapper.orderByAsc("id");
|
||||
List<IndicatorEvalItem> indicatorEvalItemList = this.list(queryWrapper);
|
||||
|
||||
return this.list(queryWrapper);
|
||||
return indicatorEvalItemList.stream()
|
||||
.collect(Collectors.groupingBy(IndicatorEvalItem::getIndicatorId));
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public List<IndicatorEvalItem> queryListByIndicatorId(Integer indicatorId) {
|
||||
public void saveWhole(IndicatorEvalBean data) {
|
||||
//保存评价集
|
||||
QueryWrapper<IndicatorEvalItem> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("indicator_id", indicatorId);
|
||||
queryWrapper.orderByAsc("sort_order", "id");
|
||||
queryWrapper.eq("indicator_top_id", data.getIndicatorTopId());
|
||||
remove(queryWrapper);
|
||||
data.getEvalItemList().forEach(item -> {
|
||||
item.setIndicatorTopId(data.getIndicatorTopId());
|
||||
save(item);
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||
import com.hshh.model.entity.FormValue;
|
||||
import com.hshh.system.common.bean.PaginationBean;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 动态表单实际对象记录表 Mapper 接口.
|
||||
|
|
@ -28,4 +29,12 @@ public interface FormValueMapper extends BaseMapper<FormValue> {
|
|||
* @return 查询结果
|
||||
*/
|
||||
Long count(PaginationBean request);
|
||||
|
||||
/**
|
||||
* 查询指定id的记录.
|
||||
*
|
||||
* @param ids id集合
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<FormValue> selectByIds(@Param("ids") List<Integer> ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||
* @since 2025-08-01
|
||||
*/
|
||||
public interface FormValueService extends IService<FormValue> {
|
||||
|
||||
/**
|
||||
* 查询列表.
|
||||
*
|
||||
|
|
@ -27,4 +28,12 @@ public interface FormValueService extends IService<FormValue> {
|
|||
* @return 查询结果
|
||||
*/
|
||||
Long count(PaginationBean request);
|
||||
|
||||
/**
|
||||
* 查询指定id的记录.
|
||||
*
|
||||
* @param ids id集合
|
||||
* @return 结果列表
|
||||
*/
|
||||
List<FormValue> selectByIds(List<Integer> ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,4 +27,9 @@ public class FormValueServiceImpl extends ServiceImpl<FormValueMapper, FormValue
|
|||
public Long count(PaginationBean request) {
|
||||
return this.baseMapper.count(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FormValue> selectByIds(List<Integer> ids) {
|
||||
return this.baseMapper.selectByIds(ids);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.hshh.thread;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.hshh.evaluation.bean.EvaluationRequest;
|
||||
import com.hshh.evaluation.bean.PageEvaluationRequest;
|
||||
import com.hshh.evaluation.service.impl.EvaluationProjectServiceImpl;
|
||||
import com.hshh.system.Global;
|
||||
import com.hshh.system.common.bean.SpringContextHolder;
|
||||
|
|
@ -17,7 +17,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
* @since 2025/7/22
|
||||
*/
|
||||
@Slf4j
|
||||
public class HandleCmdThread implements Runnable {
|
||||
public class HandleEvaluationCmdThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
@ -39,6 +39,6 @@ public class HandleCmdThread implements Runnable {
|
|||
|
||||
SpringContextHolder.getBean(EvaluationProjectServiceImpl.class)
|
||||
.evaluate(JSON.parseObject(cmd.getCmd(),
|
||||
EvaluationRequest.class), cmd.getUserId());
|
||||
PageEvaluationRequest.class), cmd.getUserId());
|
||||
}
|
||||
}
|
||||
|
|
@ -22,15 +22,17 @@ spring:
|
|||
max-request-size: 20MB
|
||||
|
||||
|
||||
|
||||
mybatis-plus:
|
||||
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
configuration:
|
||||
database-id: mysql
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hshh.evaluation.mapper.EvaluationCsvDataMapper">
|
||||
<select id="list" resultType="com.hshh.evaluation.entity.EvaluationCsvData"
|
||||
parameterType="com.hshh.system.common.bean.PaginationBean" databaseId="mysql">
|
||||
SELECT
|
||||
@rownum := @rownum + 1 AS seq,
|
||||
t.*
|
||||
FROM (
|
||||
SELECT * FROM m_data_evaluation_csv_data
|
||||
<where>
|
||||
<if test="randomKey!=null">
|
||||
and random_key = #{randomKey}
|
||||
</if>
|
||||
<if test="search != null and search !='' ">
|
||||
and raw_data LIKE CONCAT('%',#{search},'%')
|
||||
</if>
|
||||
</where>
|
||||
order by id asc ) t, ( SELECT @rownum := #{start} ) r limit
|
||||
#{start},#{pageSize}
|
||||
</select>
|
||||
<select id="list" resultType="com.hshh.evaluation.entity.EvaluationCsvData"
|
||||
parameterType="com.hshh.system.common.bean.PaginationBean" databaseId="dm">SELECT
|
||||
t.seq,
|
||||
t.*
|
||||
FROM (
|
||||
SELECT
|
||||
ROW_NUMBER() OVER (ORDER BY id ASC) AS seq,
|
||||
a.*
|
||||
FROM m_data_evaluation_csv_data a
|
||||
<where>
|
||||
<if test="randomKey!=null">
|
||||
and random_key = #{randomKey}
|
||||
</if>
|
||||
<if test="search != null and search !='' ">
|
||||
and raw_data LIKE '%'||#{search}||'%'
|
||||
</if>
|
||||
</where>
|
||||
) t
|
||||
WHERE t.seq > #{start} AND t.seq <= (#{start} + #{pageSize})
|
||||
</select>
|
||||
<select id="count" resultType="java.lang.Long" databaseId="dm">
|
||||
select count(id) from m_data_evaluation_csv_data
|
||||
<where>
|
||||
<if test="randomKey!=null">
|
||||
and random_key = #{randomKey}
|
||||
</if>
|
||||
<if test="search != null and search !=''">
|
||||
and (raw_data LIKE '%'||#{search}||'%')
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<select id="count" resultType="java.lang.Long" databaseId="mysql">
|
||||
select count(id) from m_data_evaluation_csv_data
|
||||
<where>
|
||||
<if test="randomKey!=null">
|
||||
and random_key = #{randomKey}
|
||||
</if>
|
||||
<if test="search != null and search !=''">
|
||||
and (raw_data LIKE CONCAT('%',#{search},'%'))
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<select id="selectByIds" resultType="com.hshh.evaluation.entity.EvaluationCsvData">
|
||||
SELECT * FROM m_data_evaluation_csv_data
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hshh.evaluation.mapper.EvaluationHistoryMapper">
|
||||
|
||||
<select id="queryRecentByProjectId" resultType="com.hshh.evaluation.entity.EvaluationHistory">
|
||||
SELECT *
|
||||
FROM m_data_evaluation_history
|
||||
where project_id = #{projectId}
|
||||
ORDER BY id DESC
|
||||
LIMIT 1;
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hshh.evaluation.mapper.EvaluationResultMapper">
|
||||
|
||||
</mapper>
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
FROM (
|
||||
SELECT * FROM m_data_model_field_value
|
||||
<where>
|
||||
<if test="id!=null">
|
||||
and model_define_id = #{id}
|
||||
<if test="businessKey!=null">
|
||||
and model_define_id = #{businessKey}
|
||||
</if>
|
||||
<if test="search != null and search !='' ">
|
||||
and model_data LIKE CONCAT('%',#{search},'%')
|
||||
|
|
@ -29,8 +29,8 @@
|
|||
a.*
|
||||
FROM m_data_model_field_value a
|
||||
<where>
|
||||
<if test="id!=null">
|
||||
and model_define_id = #{id}
|
||||
<if test="businessKey!=null">
|
||||
and model_define_id = #{businessKey}
|
||||
</if>
|
||||
<if test="search != null and search !='' ">
|
||||
and model_data LIKE '%'||#{search}||'%'
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
<select id="count" resultType="java.lang.Long" databaseId="dm">
|
||||
select count(id) from m_data_model_field_value
|
||||
<where>
|
||||
<if test="id!=null">
|
||||
and model_define_id = #{id}
|
||||
<if test="businessKey!=null">
|
||||
and model_define_id = #{businessKey}
|
||||
</if>
|
||||
<if test="search != null and search !=''">
|
||||
and (model_data LIKE '%'||#{search}||'%')
|
||||
|
|
@ -53,12 +53,19 @@
|
|||
<select id="count" resultType="java.lang.Long" databaseId="mysql">
|
||||
select count(id) from m_data_model_field_value
|
||||
<where>
|
||||
<if test="id!=null">
|
||||
and model_define_id = #{id}
|
||||
<if test="businessKey!=null">
|
||||
and model_define_id = #{businessKey}
|
||||
</if>
|
||||
<if test="search != null and search !=''">
|
||||
and (model_data LIKE CONCAT('%',#{search},'%'))
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<select id="selectByIds" resultType="com.hshh.model.entity.FormValue">
|
||||
SELECT * FROM m_data_model_field_value
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hshh.indicator.mapper.IndicatorBottomCsvMapperMapper">
|
||||
<select id="selectByIndicatorTopId" resultType="com.hshh.indicator.entity.IndicatorBottomCsvMapper">
|
||||
|
||||
SELECT
|
||||
t1.indicator_id,
|
||||
t2.csv_column_name
|
||||
FROM
|
||||
m_data_indicator_bottom_csv_mapper t1
|
||||
LEFT JOIN m_data_indicator_csv_column t2 on t1.csv_column_id=t2.id
|
||||
where t1.indicator_top_id=#{id}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -2,5 +2,13 @@
|
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hshh.indicator.mapper.IndicatorBottomMapperMapper">
|
||||
|
||||
<select id="selectByIndicatorTopId" resultType="com.hshh.indicator.entity.IndicatorBottomFormMapper">
|
||||
SELECT
|
||||
t1.indicator_id,
|
||||
t2.field_id as filedName
|
||||
FROM
|
||||
m_data_indicator_bottom_form_mapper t1
|
||||
LEFT JOIN m_data_model_field_config t2 on t1.form_field_id=t2.id
|
||||
where t1.indicator_top_id=#{indicatorTopId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@
|
|||
select t.indicator_model_id
|
||||
from m_data_indicator_form t where t.indicator_top_id=#{topId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -246,12 +246,18 @@ function _resetPageNoSearch() {
|
|||
|
||||
//动态数据,动态表头,动态表格 header=map record=list(map)
|
||||
function _dynamic_next(form) {
|
||||
|
||||
let pageNum = document.forms[form]["currentPage"].value;
|
||||
document.forms[form]["currentPage"].value = parseInt(pageNum)+1;
|
||||
dynamic_search();
|
||||
}
|
||||
function _dynamic_pre(form) {
|
||||
|
||||
let pageNum = document.forms[form]["currentPage"].value;
|
||||
document.forms[form]["currentPage"].value = parseInt(pageNum)-1;
|
||||
dynamic_search();
|
||||
}
|
||||
function _dynamic_resetPageNoSearch(form){
|
||||
document.forms[form]["currentPage"].value = 1;
|
||||
dynamic_search();
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -408,4 +414,25 @@ function wsUrl(path) {
|
|||
const loc = window.location; // 当前页面的地址
|
||||
const scheme = loc.protocol === "https:" ? "wss:" : "ws:";
|
||||
return scheme + "//" + loc.host + path;
|
||||
}
|
||||
function formToQueryString(formId) {
|
||||
const form = document.getElementById(formId);
|
||||
const formData = new FormData(form);
|
||||
const params = new URLSearchParams();
|
||||
|
||||
for (let [key, value] of formData.entries()) {
|
||||
// 排除文件输入
|
||||
const field = form.elements[key];
|
||||
if (field && field.type === "file") continue;
|
||||
|
||||
params.append(key, value);
|
||||
}
|
||||
|
||||
return params.toString(); // "key1=val1&key2=val2"
|
||||
}
|
||||
function encryptPassword(password, aesKeyFromBackend,aesIVFromBackend) {
|
||||
var key = CryptoJS.enc.Hex.parse(aesKeyFromBackend); // 32字节
|
||||
var iv = CryptoJS.enc.Hex.parse(aesIVFromBackend); // 16字节
|
||||
|
||||
return CryptoJS.AES.encrypt(password, key, { iv: iv, mode: CryptoJS.mode.CBC }).toString();
|
||||
}
|
||||
1
manager-admin/src/main/resources/static/js/crypto-js.min.js
vendored
Normal file
1
manager-admin/src/main/resources/static/js/crypto-js.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
20
manager-admin/src/main/resources/static/js/html2canvas.min.js
vendored
Normal file
20
manager-admin/src/main/resources/static/js/html2canvas.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
398
manager-admin/src/main/resources/static/js/jspdf.umd.min.js
vendored
Normal file
398
manager-admin/src/main/resources/static/js/jspdf.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -11,7 +11,7 @@
|
|||
<label class="col-2 col-form-label">基础设施</label>
|
||||
<div class="col-6">
|
||||
<label>
|
||||
<select class="form-select" id="modelId" onchange="_tabChange(this.value)">
|
||||
<select class="form-select" id="modelId" onchange="_tabChange(this)">
|
||||
<option>--请选择基础设施--</option>
|
||||
<option th:each="item ,stat: ${modelDefineList}" th:text="${item.getModelName()}"
|
||||
th:value="${item.id}" th:selected="${item.checked}"></option>
|
||||
|
|
@ -129,14 +129,15 @@
|
|||
http.post(url, postObj, function (error, res, xhr) {
|
||||
closeDialog("modal-full-width");
|
||||
document.getElementById("_data_list").setAttribute("hx-vals",
|
||||
JSON.stringify({id: postObj.modelDefineId}))
|
||||
JSON.stringify({businessKey: postObj.modelDefineId}))
|
||||
document.getElementById("_data_list").click();
|
||||
}, "dataRecordForm", "modal-full-width")
|
||||
}
|
||||
|
||||
function _tabChange(id) {
|
||||
function _tabChange(obj) {
|
||||
|
||||
document.getElementById("_data_list").setAttribute("hx-vals",
|
||||
JSON.stringify({id: id}));
|
||||
JSON.stringify({businessKey: obj.value}));
|
||||
document.getElementById("_data_list").click();
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +174,7 @@
|
|||
|
||||
if (!error) {
|
||||
document.getElementById("dataExtendForm")['id'].value = res.result.id;
|
||||
addModeDataRecord(res.result.modelDefineId, res.result);
|
||||
addModeDataRecord( res.result);
|
||||
}
|
||||
}, "dataRecordForm")
|
||||
}
|
||||
|
|
|
|||
12
manager-admin/src/main/resources/templates/error/404.html
Normal file
12
manager-admin/src/main/resources/templates/error/404.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
<div class="page page-center">
|
||||
<div class="container-tight py-4">
|
||||
<div class="empty">
|
||||
<div class="empty-header">404</div>
|
||||
<p class="empty-title">页面不存在</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
13
manager-admin/src/main/resources/templates/error/500.html
Normal file
13
manager-admin/src/main/resources/templates/error/500.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
|
||||
<div class="page page-center">
|
||||
<div class="container-tight py-4">
|
||||
<div class="empty">
|
||||
<div class="empty-header">500</div>
|
||||
<p class="empty-title" th:text="${errorMessage}"></p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -118,14 +118,14 @@
|
|||
</div>
|
||||
<!-- form add对话框 简单form操作,居中对话框-->
|
||||
<div th:fragment="addSimpleFormDialog" id="addSimpleFormDialog">
|
||||
<div class="modal modal-blur fade" id="simple-form-model" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal modal-blur fade" id="simple-form-model" tabindex="-1" role="dialog" aria-hidden="true" >
|
||||
<div class="modal-dialog modal-dialog-centered" role="document" style="min-width: 50em;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="SimpleFormDialog_title"></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" onclick="closeDialog('simple-form-model')"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="simpleFormBody">
|
||||
<div class="modal-body" id="simpleFormBody" >
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
@ -219,7 +219,10 @@
|
|||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div th:fragment="datasetForListMap(formId,headerMap,result,condition)" id="dataset_list_map_table_page">
|
||||
<div th:fragment="datasetForListMap(formId,headerMap,result,condition)" id="dataset_list_map_table_page" style="min-height: 50em;max-height: 50em;overflow-y: scroll;">
|
||||
|
||||
<input type="hidden" name="currentPage"
|
||||
th:value="${condition?.currentPage}"/>
|
||||
<div class="card-body border-bottom py-3">
|
||||
<div class="d-flex">
|
||||
<div class="text-muted">
|
||||
|
|
@ -245,15 +248,17 @@
|
|||
<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>
|
||||
|
||||
<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><label>
|
||||
<input type="checkbox" th:value="${item['id']}" name="list_map_table_checkbox">
|
||||
</label></td>
|
||||
|
||||
<td th:each="entry : ${headerMap}" th:text="${item[entry.key]}"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -262,17 +267,33 @@
|
|||
<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" >
|
||||
<li th:class="${result?.isHasPrevious()}?'page-item':'page-item disabled'">
|
||||
|
||||
<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 class="page-link" href="#" tabindex="-1" aria-disabled="true" th:attr="data-form-id=${#strings.escapeJavaScript(formId)}"
|
||||
onclick="_dynamic_pre(this.dataset.formId)">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/chevron-left -->
|
||||
<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)" >
|
||||
<li th:class="${result?.isHasNext()}?'page-item':'page-item disabled'" >
|
||||
<a class="page-link" href="#" onclick="_dynamic_next(this.dataset.formId)" th:attr="data-form-id=${#strings.escapeJavaScript(formId)}">
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<link th:href="@{/css/tabler-vendors.min.css}" rel="stylesheet"/>
|
||||
<link th:href="@{/js/jstree/themes/default/style.min.css}" rel="stylesheet"/>
|
||||
<link th:href="@{/css/fontawesome-all.min.css}" rel="stylesheet"/>
|
||||
<link th:href="@{/css/jsmind.css}" rel="stylesheet"/>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
|
|
@ -267,9 +267,21 @@
|
|||
<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 th:src="@{/js/html2canvas.min.js}"></script>
|
||||
<script th:src="@{/js/jspdf.umd.min.js}"></script>
|
||||
|
||||
<script>
|
||||
|
||||
const categoryColors = [
|
||||
"#00bcd4", // 卓越
|
||||
"#2196f3", // 优秀
|
||||
"#42a5f5", // 优
|
||||
"#66bb6a", // 良
|
||||
"#ffd600", // 中
|
||||
"#ffa726", // 及格
|
||||
"#ff7043", // 及格下
|
||||
"#ef5350", // 差
|
||||
"#8d6e63" // 极差
|
||||
];
|
||||
let d3TreeData = null;
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 1. 支持多种菜单项,逗号分隔多个选择器
|
||||
|
|
@ -306,12 +318,14 @@
|
|||
}
|
||||
|
||||
// htmx等局部刷新后,确保DOM插入再init
|
||||
document.body.addEventListener('htmx:afterSwap', function (evt) {
|
||||
document.body.addEventListener('htmx:afterSettle', function (evt) {
|
||||
|
||||
if (evt.detail.target.id === 'main-content') {
|
||||
//菜单
|
||||
if (evt.detail.target.querySelector('[data-page="menu-list"]')) {
|
||||
setTimeout(initMenu, 0); // 保证DOM已插入
|
||||
setTimeout(initMenu, 1); // 保证DOM已插入
|
||||
}
|
||||
//指标
|
||||
if(evt.detail.target.querySelector('[data-page="metric"]')){
|
||||
if (typeof topIndictorTree === 'function') {
|
||||
topIndictorTree();
|
||||
|
|
@ -336,6 +350,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
//评估
|
||||
if(evt.detail.target.querySelector('[data-page="evaluation_list"]')){
|
||||
if(typeof initEvaluationList === 'function'){
|
||||
|
||||
|
|
@ -344,20 +359,20 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
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 });
|
||||
document.body.addEventListener('htmx:responseError', function (e) {
|
||||
const status = e.detail.xhr.status;
|
||||
if (status === 404 || status === 500) {
|
||||
const html = e.detail.xhr.responseText; // 服务器返回的错误页 HTML
|
||||
// 把错误页塞进主容器(按你的布局替换 id)
|
||||
document.getElementById('main-content').innerHTML = html;
|
||||
}
|
||||
});
|
||||
|
||||
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",
|
||||
"0.5":"2","0.3333":"3","0.25":"4","0.2":"5","0.16667":"6","0.14286":"7","0.125":"8","0.11111":"9"
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<input type="hidden" name="id" id="id">
|
||||
<input type="hidden" name="indicatorTopId" id="indicatorTopId">
|
||||
<input type="hidden" name="indicatorId" id="indicatorId">
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<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">
|
||||
<option value="">默认空</option>
|
||||
<option value="==">等于</option>
|
||||
<option value=">=">大于等于</option>
|
||||
<option value=">">大于</option>
|
||||
<option value="<">小于</option>
|
||||
<option value="<=">小于等于</option>
|
||||
</select>
|
||||
|
||||
<div class="invalid-feedback" id="minSymbol_error_tip"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<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>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label required" for="maxSymbol">符号:</label>
|
||||
<select name="maxSymbol" id="maxSymbol" class="form-select">
|
||||
<option value="">默认空</option>
|
||||
<option value="==">等于</option>
|
||||
<option value=">=">大于等于</option>
|
||||
<option value=">">大于</option>
|
||||
<option value="<">小于</option>
|
||||
<option value="<=">小于等于</option>
|
||||
</select>
|
||||
|
||||
<div class="invalid-feedback" id="maxSymbol_error_tip"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -1,182 +1,283 @@
|
|||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<div class="page-body" data-page="evaluation_list">
|
||||
<div class="container-xl">
|
||||
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||
<div class="page">
|
||||
<div class="page-body" data-page="indicator_list">
|
||||
<div class="container-xl">
|
||||
|
||||
<div class="row row-cards">
|
||||
<!-- 面包屑(静态示例/Thymeleaf) -->
|
||||
<div th:replace="fragments/dialog::navigateDialog(${chainMenuList})"></div>
|
||||
|
||||
<!-- 顶部重点卡片 -->
|
||||
<div class="card card-priority">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title title-accent">选择评价指标
|
||||
<span class="badge bg-primary ms-2">必填</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<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" 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 class="row row-cards">
|
||||
<!-- 顶层主卡片:加上 card-hero -->
|
||||
<div class="card card-hero">
|
||||
<div class="card-header">
|
||||
<div class="card-title">指标数据评价集</div>
|
||||
<div class="card-actions">
|
||||
<a href="javascript:void(0)" class="btn btn-primary" onclick="evaluationSave()">
|
||||
<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 class="col-auto text-muted small">选定后,下方“评价集设置”将随之变化</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 次级卡片 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title fw-bold">评价集设置</div>
|
||||
<div class="ms-auto">
|
||||
<a href="#" class="btn btn-primary" onclick="evaluation_add()">增加评价</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
|
||||
<!-- 左:子集列表 -->
|
||||
<div class="col-md-3">
|
||||
<div class="subset-panel">
|
||||
<div class="subset-scroll list-group list-group-flush">
|
||||
<div class="list-group-item bg-transparent border-0 py-2"
|
||||
th:each="item:${indicatorListWithoutChildren}">
|
||||
<label class="form-check form-check-inline m-0">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="radios-inline-indicator-no-child" th:value="${item.getId()}"
|
||||
th:checked="${item.checked}" onclick="changeIndicator()">
|
||||
<span class="form-check-label ms-2" th:text="${item.getName()}"></span>
|
||||
</label>
|
||||
<!-- 1. 根指标 -->
|
||||
<div class="card section mb-3">
|
||||
<div class="card-header">
|
||||
<div class="card-title">1. 选择指标(根指标)</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-auto">
|
||||
<label for="indicationId" class="form-label m-0">根指标</label>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3">
|
||||
<select id="indicationId" class="form-select" name="indicationId"
|
||||
onchange="indicatorChange(this.value)">
|
||||
<option value="0">-选择根指标-</option>
|
||||
<option th:each="item:${rootList}" th:value="${item.id}"
|
||||
th:text="${item.getName()}" th:selected="${item.checked}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto text-muted small">选择根指标后,再选择设施与 CSV 以建立映射。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右:表格 -->
|
||||
<div class="col-md-9">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">序号</th>
|
||||
<th>名称</th>
|
||||
<th class="w-1">符号</th>
|
||||
<th class="w-1">下限值</th>
|
||||
<th class="w-1">符号</th>
|
||||
<th class="w-1">上限值</th>
|
||||
<th class="text-end w-10"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="item, stats :${evaluationList}">
|
||||
<td th:text="${stats.count}"></td>
|
||||
<td th:text="${item.getEvaluationName()}"></td>
|
||||
<td th:text="${item.getMinSymbol()}"></td>
|
||||
<td th:text="${item.getMinValue()}"></td>
|
||||
<td th:text="${item.getMaxSymbol()}"></td>
|
||||
<td th:text="${item.getMaxValue()}"></td>
|
||||
<td class="text-end">
|
||||
<a href="javascript:void(0)" class="me-2"
|
||||
th:onclick="|editEvaluation('${item.id}')|">编辑</a>
|
||||
<a href="javascript:void(0)"
|
||||
th:onclick="|removeEvaluation('${item.id}')|">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<!-- 4. 子指标映射 -->
|
||||
<div class="card section">
|
||||
<div class="card-header">
|
||||
<div class="card-title">2. 底部指标区间设置</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-5" id="evaluation_tree"></div>
|
||||
<div class="col-7">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title" id="level_range_title"></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>等级名</th>
|
||||
<th>上限</th>
|
||||
<th>下限</th>
|
||||
<th>等于</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="level_range_body">
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- row -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="evaluationForm">
|
||||
<div th:replace="fragments/dialog::addSimpleFormDialog"></div>
|
||||
</form>
|
||||
<div th:replace="fragments/dialog::confirmationDialog"></div>
|
||||
|
||||
<script>
|
||||
// 交互时给重点卡片一个轻微高亮
|
||||
function initEvaluationList() {
|
||||
function indicatorChange(id) {
|
||||
if (id === '0') {
|
||||
return;
|
||||
}
|
||||
|
||||
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";
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (err, res, xhr) {
|
||||
document.getElementById("simpleFormBody").innerHTML = res;
|
||||
openDialog("simple-form-model");
|
||||
if (data) {
|
||||
fillData(data);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
document.getElementById("SimpleFormDialog_save").onclick = function () {
|
||||
evaluation_save();
|
||||
}
|
||||
}, "evaluationForm")
|
||||
}
|
||||
|
||||
function fillData(data) { fillForm('evaluationForm', data); }
|
||||
|
||||
function evaluation_save() {
|
||||
let url = document.getElementById("_rootPath").value + "evaluation/save";
|
||||
let http = new HttpClient();
|
||||
let form = document.getElementById("evaluationForm");
|
||||
http.post(url, formObjToObject(form), function (err, res, xhr) {
|
||||
closeDialog("simple-form-model");
|
||||
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();
|
||||
}, "evaluationForm", "simple-form-model");
|
||||
}
|
||||
|
||||
function editEvaluation(id) {
|
||||
let url = document.getElementById("_rootPath").value + "evaluation/" + id;
|
||||
let http = new HttpClient();
|
||||
http.get(url, function (error, res, xhr) { evaluation_add(res.result); },
|
||||
"evaluationForm", "simple-form-model");
|
||||
http.get(url, function (error, res, xhr) {
|
||||
|
||||
|
||||
//处理树
|
||||
if (res.result.jsTreeList) {
|
||||
let $tree = $('#evaluation_tree');
|
||||
|
||||
// 如果已经有树,先销毁
|
||||
if ($.jstree.reference($tree)) {
|
||||
|
||||
$tree.jstree("destroy").empty();
|
||||
}
|
||||
$('#evaluation_tree').jstree({
|
||||
'core': {
|
||||
'data': res.result.jsTreeList,
|
||||
check_callback: true // ← 关键
|
||||
}
|
||||
}).on("select_node.jstree", function (e, data) {
|
||||
// 这里 data.node 就是被选中的节点对象
|
||||
|
||||
buildLevelRangeBody(data.node);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}, "")
|
||||
|
||||
}
|
||||
|
||||
function removeEvaluation(id) {
|
||||
openDialog("modal-danger");
|
||||
document.getElementById('delete-confirm-9999').onclick = function () {
|
||||
let url = document.getElementById("_rootPath").value + "evaluation/remove/" + id;
|
||||
let http = new HttpClient();
|
||||
http.get(url, (err, res, xhr) => {
|
||||
if (!err) document.getElementById("_evaluation_evaluationList").click();
|
||||
|
||||
|
||||
|
||||
|
||||
function inputChange() {
|
||||
//获取选中的树节点
|
||||
const $tree = $('#evaluation_tree');
|
||||
try {
|
||||
const inst = $tree.jstree(true);
|
||||
let selectedNodes = inst.get_selected(true);
|
||||
if (selectedNodes && selectedNodes.length) {
|
||||
let currentNode = selectedNodes[0];
|
||||
//获取右边的表格值,放入data.range中
|
||||
let id = currentNode.id.replace("tree_", "");
|
||||
let data = getTableData(id);
|
||||
//修改节点名称,提示用户
|
||||
let nodeName = currentNode.text;
|
||||
nodeName = nodeName.replace(/\([^)]*\)/g, "");
|
||||
let str = "";
|
||||
data.forEach(function (element) {
|
||||
str = str + element.evaluationName + ":" + element.bottomValue + "," + element.topValue
|
||||
+","+ element.equalValue+";"
|
||||
})
|
||||
nodeName = nodeName + "(" + str + ")";
|
||||
|
||||
currentNode.data.range = data;
|
||||
inst.rename_node(currentNode, nodeName);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.warn('destroy skipped:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function buildLevelRangeBody(node) {
|
||||
document.getElementById("level_range_title").textContent = node.text;
|
||||
document.getElementById("level_range_body").innerHTML = "";
|
||||
let levelNames = document.getElementsByName("_level");
|
||||
let historyMap = new Map();
|
||||
if (node.data.range) {
|
||||
node.data.range.forEach((element) => {
|
||||
historyMap.set(element.evaluationName, element);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < levelNames.length; i++) {
|
||||
let tr = document.createElement("tr");
|
||||
let td = document.createElement("td");
|
||||
td.textContent = levelNames[i].value;
|
||||
tr.appendChild(td);
|
||||
//底部指标上限输入
|
||||
let topTd = document.createElement("td");
|
||||
let topInput = document.createElement("input");
|
||||
topInput.type = "number";
|
||||
topInput.style.width = "8ch";
|
||||
topInput.addEventListener("change", function () {
|
||||
inputChange();
|
||||
});
|
||||
if (historyMap.get(td.textContent)) {
|
||||
topInput.value = historyMap.get(td.textContent).topValue;
|
||||
}
|
||||
topTd.appendChild(topInput);
|
||||
//底部指标下限输入
|
||||
let bottomTd = document.createElement("td");
|
||||
let bottomInput = document.createElement("input");
|
||||
bottomInput.type = "number";
|
||||
bottomInput.style.width = "8ch";
|
||||
bottomInput.addEventListener("change", function () {
|
||||
inputChange()
|
||||
})
|
||||
if (historyMap.get(td.textContent)) {
|
||||
bottomInput.value = historyMap.get(td.textContent).bottomValue;
|
||||
}
|
||||
bottomTd.appendChild(bottomInput);
|
||||
|
||||
//相等值输入
|
||||
let equalValueTd = document.createElement("td");
|
||||
let equalValueInput = document.createElement("input");
|
||||
equalValueInput.type = "text";
|
||||
equalValueInput.style.width = "8ch";
|
||||
equalValueInput.addEventListener("change", function () {
|
||||
inputChange();
|
||||
});
|
||||
if (historyMap.get(equalValueTd.textContent)) {
|
||||
equalValueInput.value = historyMap.get(td.textContent).equalValue;
|
||||
}
|
||||
equalValueTd.appendChild(equalValueInput);
|
||||
|
||||
tr.appendChild(topTd);
|
||||
tr.appendChild(bottomTd);
|
||||
tr.appendChild(equalValueTd);
|
||||
document.getElementById("level_range_body").appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
function changeIndicator(){
|
||||
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();
|
||||
function getTableData(indicatorId) {
|
||||
let trs = document.getElementById("level_range_body").getElementsByTagName("tr");
|
||||
|
||||
let data = [];
|
||||
for (let i = 0; i < trs.length; i++) {
|
||||
let obj = {};
|
||||
let tr = trs[i];
|
||||
let tds = tr.getElementsByTagName("td")
|
||||
obj.indicatorId = parseInt(indicatorId);
|
||||
obj.evaluationName = tds[0].textContent;
|
||||
obj.topValue = parseFloat(tds[1].getElementsByTagName("input")[0].value);
|
||||
obj.bottomValue = parseFloat(tds[2].getElementsByTagName("input")[0].value);
|
||||
obj.equalValue=tds[3].getElementsByTagName("input")[0].value
|
||||
data.push(obj);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
//保存评估评价集
|
||||
function evaluationSave() {
|
||||
let obj = {};
|
||||
//顶级指标ID
|
||||
obj.indicatorTopId = parseInt(document.getElementById("indicationId").value);
|
||||
// 设置各个指标的评价集
|
||||
const inst = $('#evaluation_tree').jstree(true);
|
||||
const flat = inst.get_json('#', {flat: true, no_data: false});
|
||||
let evalItemList = [];
|
||||
flat.forEach(n => {
|
||||
if (n.data) {
|
||||
if (n.data.range) {
|
||||
evalItemList = evalItemList.concat(n.data.range);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
obj.evalItemList = evalItemList;
|
||||
let url = document.getElementById("_rootPath").value + "evaluation/save";
|
||||
let http = new HttpClient();
|
||||
http.post(url, obj, function (error, response, xhr) {
|
||||
showAlert("success", "保存成功");
|
||||
}, "", "")
|
||||
}
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
|
@ -81,8 +81,10 @@
|
|||
<div class="card-title">3. 上传 CSV 文件</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<input type="file" id="csvFile" class="form-control mb-3" accept=".csv">
|
||||
|
||||
<label for="csvFile" class="btn btn-primary">选择文件</label>
|
||||
<span id="file-name">未选择文件</span>
|
||||
<input type="file" id="csvFile" accept=".csv" style="display:none" />
|
||||
<!-- 上次上传文件 -->
|
||||
<div class="mb-2" th:if="${csvMapper!=null}">
|
||||
<span class="fw-bold">上次上传文件:</span>
|
||||
|
|
@ -158,7 +160,7 @@
|
|||
</div>
|
||||
|
||||
<!-- ====== JS:保持你的原有逻辑 ====== -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||
|
||||
<script>
|
||||
function formModelChange(object) {
|
||||
let postUrl = document.getElementById('_rootPath').value + "indicator/indicatorFormMapper";
|
||||
|
|
@ -179,6 +181,16 @@
|
|||
}
|
||||
|
||||
function csvListen() {
|
||||
const input = document.getElementById("csvFile");
|
||||
|
||||
const fileName = document.getElementById("file-name");
|
||||
input.addEventListener("change", function() {
|
||||
if (this.files.length > 0) {
|
||||
fileName.textContent = this.files[0].name;
|
||||
} else {
|
||||
fileName.textContent = "未选择文件";
|
||||
}
|
||||
});
|
||||
$('#csvFile').on('change', function () {
|
||||
const f = this.files[0];
|
||||
if (!f) return;
|
||||
|
|
@ -251,8 +263,7 @@
|
|||
// 根指标变化时也高亮主卡
|
||||
$('#indicationId').on('change', flashHero);
|
||||
|
||||
// 初始化 CSV 监听
|
||||
csvListen();
|
||||
|
||||
|
||||
// 轻微高亮动画(与 CSS 中 .flash 对应)
|
||||
function flashHero(){
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@
|
|||
<div class="form-footer">
|
||||
<button type="submit" class="btn btn-primary w-100">登录</button>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="aesKey" id="aesKey" th:value="${aesKey}"/>
|
||||
<input type="hidden" name="aesIv" id="aesIv" th:value="${aesIv}"/>
|
||||
</form>
|
||||
|
||||
|
||||
|
|
@ -92,6 +93,7 @@
|
|||
<!-- Tabler Core -->
|
||||
<script th:src="@{/js/tabler.min.js}" defer></script>
|
||||
<script th:src="@{/js/common/common.js}" ></script>
|
||||
<script th:src="@{/js/crypto-js.min.js}"></script>
|
||||
</body>
|
||||
|
||||
|
||||
|
|
@ -108,8 +110,9 @@
|
|||
formData.forEach((value, key) => {
|
||||
object[key] = value;
|
||||
});
|
||||
object.password = encryptPassword( object.password,object.aesKey,object.aesIv);
|
||||
var jsonData = JSON.stringify(object);
|
||||
console.log("转换得到的 JSON 数据:", jsonData);
|
||||
|
||||
|
||||
// 从 form 的 action 属性获取 URL(Thymeleaf 渲染后会转换为实际地址)
|
||||
var formAction = this.getAttribute('action');
|
||||
|
|
@ -145,7 +148,7 @@
|
|||
document.getElementById(item.elementId + "_error_tip").innerHTML = item.message;
|
||||
}
|
||||
}
|
||||
if(data.code===500){//提交错误
|
||||
if(data.code===10001){//提交错误
|
||||
document.getElementById("error_message").innerHTML = data.message;
|
||||
document.getElementById("error_message").style.display = "block";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
<input type="hidden" name="modelId" th:value="${modelId}" />
|
||||
<input type="hidden" name="modelId" value="" />
|
||||
<input type="hidden" name="projectId" th:value="${projectId}" />
|
||||
<input type="hidden" name="templateId" th:value="${templateId}" />
|
||||
<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}" />
|
||||
<input type="hidden" name="membership" th:value="${membership}" />
|
||||
<div class="row align-items-center mt-3 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="progress">
|
||||
|
|
@ -14,10 +16,10 @@
|
|||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="javascript:void(0)" class="btn btn-info" onclick="">
|
||||
<a href="javascript:void(0)" class="btn btn-info" th:attr="data-project-id=${projectId}" onclick="_startEvaluation(this.dataset.projectId)">
|
||||
上一步
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-success" onclick="selectedDatasource()">
|
||||
<a href="javascript:void(0)" class="btn btn-success" onclick="processEvaluation()">
|
||||
下一步
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -32,59 +34,27 @@
|
|||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<div class="form-label">选择上传文件</div>
|
||||
<input type="file" class="form-control">
|
||||
<input type="file" class="form-control" name="file" accept=".csv" id="csv_file" onchange="readCsv()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" FOR="csv_identifier">标识字段</label>
|
||||
<select class="form-select" id="csv_identifier">
|
||||
<option th:each="entry : ${headerMap}" th:value="${entry.key}" th:text="${entry.value}"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<div class="row" >
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<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 th:replace="fragments/dialog::datasetForListMap('stepForm',${headerMap},${result},${condition})"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
<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}" />
|
||||
<input type="hidden" name="membership" th:value="${membership}" />
|
||||
<div class="row align-items-center mt-3 mb-3">
|
||||
<div class="col-4">
|
||||
<div class="progress">
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
</div>
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="javascript:void(0)" class="btn btn-info" onclick="">
|
||||
<a href="javascript:void(0)" class="btn btn-info" th:attr="data-project-id=${projectId}" onclick="_startEvaluation(this.dataset.projectId)">
|
||||
上一步
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="btn btn-success" onclick="processEvaluation()">
|
||||
|
|
@ -24,7 +24,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="min-height: 20em;">
|
||||
|
||||
|
||||
<div class="card" style="min-height: 50em;max-height: 50em;overflow-y: scroll;">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">数据库记录</h4>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<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">
|
||||
<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>
|
||||
|
|
@ -9,7 +10,9 @@
|
|||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
|
||||
<a href="javascript:void(0)" class="btn btn-primary" th:onclick="|selectedDatasource(${projectId})|">
|
||||
<a href="javascript:void(0)" class="btn btn-primary"
|
||||
th:attr="data-project-id=${projectId}"
|
||||
onclick="selectedDatasource(this.dataset.projectId)">
|
||||
下一步
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -18,43 +21,62 @@
|
|||
<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-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 class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="mb-3">
|
||||
|
||||
</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 class="form-label">1.选择数据源</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">2.模糊运算方式</div>
|
||||
<div>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod" checked="checked"
|
||||
value="PRODUCT_BOUNDED_SUM">
|
||||
<span class="form-check-label">乘积有界和算子M(·,⊕)</span>
|
||||
</label>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod"
|
||||
value="MIN_MAX">
|
||||
<span class="form-check-label">取小取大算子 M(∧,∨)</span>
|
||||
</label>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod"
|
||||
value="PRODUCT_MAX">
|
||||
<span class="form-check-label">乘积取大算子 M(·,∨)</span>
|
||||
</label>
|
||||
<label class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="aggregationMethod"
|
||||
value="MIN_BOUNDED_SUM">
|
||||
<span class="form-check-label">取小有界和算子M(∧,⊕)</span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">工程评估历史</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height:40em;">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter table-mobile-md card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>创建时间</th>
|
||||
<th>数据来源</th>
|
||||
<th>隶属函数</th>
|
||||
<th>模糊运算算子</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody >
|
||||
<tr th:each="evaluationHistory,stat :${list}">
|
||||
<td th:text="${stat.count}"></td>
|
||||
<td th:text="${#temporals.format(evaluationHistory.createTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
|
||||
<td th:text="${evaluationHistory.datasourceType}"></td>
|
||||
<td th:text="${evaluationHistory.membershipFunc}">隶属函数</td>
|
||||
<td th:text="${evaluationHistory.fuzzyOperator}">模糊运算算子</td>
|
||||
<td>
|
||||
<div class="btn-list flex-nowrap"><a href="#" class="btn"
|
||||
th:data-result-id="${evaluationHistory.randomKey}"
|
||||
th:data-project-id="${evaluationHistory.getProjectId()}"
|
||||
onclick="viewRootList(this)">
|
||||
查看详情
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', 'Segoe UI', Arial, sans-serif;
|
||||
background-color: #f8fafc;
|
||||
color: #1e293b;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.report-container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* PDF导出按钮 - 嵌入在报告头部 */
|
||||
.export-btn {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
backdrop-filter: blur(10px);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.export-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.export-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid transparent;
|
||||
border-top: 2px solid white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.report-title {
|
||||
font-size: 2.8rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.report-subtitle {
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.report-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.95rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.executive-summary {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
margin-bottom: 30px;
|
||||
border-left: 6px solid #3b82f6;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
background: #f8fafc;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
color: #64748b;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.summary-text {
|
||||
font-size: 1rem;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
background: #f1f5f9;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #3b82f6;
|
||||
}
|
||||
|
||||
.methodology {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.method-steps {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.method-step {
|
||||
background: #f8fafc;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #10b981;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: #10b981;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.step-desc {
|
||||
font-size: 0.9rem;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.results-section {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
background: #f8fafc;
|
||||
padding: 25px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
position: relative;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 饼图容器调整 */
|
||||
.pie-chart-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pie-chart-svg {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pie-legend {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* D3.js 图表样式 */
|
||||
.pie-chart .arc text {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
fill: white;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.radar-chart .grid-line {
|
||||
stroke: #e2e8f0;
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.radar-chart .axis-line {
|
||||
stroke: #94a3b8;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.radar-chart .axis-label {
|
||||
font-size: 12px;
|
||||
fill: #475569;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.radar-chart .data-area {
|
||||
fill: rgba(59, 130, 246, 0.3);
|
||||
stroke: #3b82f6;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.radar-chart .data-point {
|
||||
fill: #3b82f6;
|
||||
stroke: white;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
padding: 8px 12px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.data-table-section {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
|
||||
padding: 25px;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f8fafc;
|
||||
padding: 18px 20px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f8fafc;
|
||||
}
|
||||
|
||||
.indicator-name {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.level-marker {
|
||||
width: 4px;
|
||||
height: 40px;
|
||||
border-radius: 2px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.level-0 { background-color: #3b82f6; }
|
||||
.level-1 { background-color: #10b981; }
|
||||
.level-2 { background-color: #f59e0b; }
|
||||
.level-3 { background-color: #8b5cf6; }
|
||||
|
||||
.level-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.indicator-text {
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.indicator-path {
|
||||
font-size: 0.8rem;
|
||||
color: #64748b;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.path-separator {
|
||||
color: #94a3b8;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
/* 隶属度分布显示样式 */
|
||||
.membership-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.membership-bar {
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
border-radius: 14px;
|
||||
position: relative;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #e2e8f0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.membership-segment {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.segment-excellent { background-color: #10b981; } /* 优 - 绿色 */
|
||||
.segment-good { background-color: #3b82f6; } /* 良 - 蓝色 */
|
||||
.segment-fair { background-color: #f59e0b; } /* 可 - 黄色 */
|
||||
.segment-poor { background-color: #ef4444; } /* 差 - 红色 */
|
||||
|
||||
.membership-values {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.7rem;
|
||||
color: #374151;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.analysis-section {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.analysis-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 30px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.analysis-card {
|
||||
background: #f8fafc;
|
||||
padding: 25px;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #f59e0b;
|
||||
}
|
||||
|
||||
.analysis-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.analysis-list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.analysis-list li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
font-size: 0.95rem;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.analysis-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.analysis-list li:before {
|
||||
content: "▶";
|
||||
color: #f59e0b;
|
||||
font-weight: 700;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.level-1 .indicator-name { margin-left: 20px; }
|
||||
.level-2 .indicator-name { margin-left: 40px; }
|
||||
.level-3 .indicator-name { margin-left: 60px; }
|
||||
|
||||
.weight-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.weight-value {
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.weight-bar {
|
||||
width: 80px;
|
||||
height: 16px;
|
||||
background-color: #e2e8f0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.weight-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #3b82f6, #1e40af);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.score-badge {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.floating-export {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.export-btn-float {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.export-btn-float:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
@media print {
|
||||
.floating-export {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
/* 四级评价等级颜色 */
|
||||
.score-excellent { background-color: #dcfce7; color: #166534; } /* 优 - 绿色 */
|
||||
.score-good { background-color: #dbeafe; color: #1e40af; } /* 良 - 蓝色 */
|
||||
.score-fair { background-color: #fef3c7; color: #92400e; } /* 可 - 黄色 */
|
||||
.score-poor { background-color: #fee2e2; color: #dc2626; } /* 差 - 红色 */
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.charts-grid, .analysis-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.export-btn {
|
||||
position: relative;
|
||||
top: auto;
|
||||
right: auto;
|
||||
margin-bottom: 20px;
|
||||
align-self: center;
|
||||
}
|
||||
.report-header {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.report-title { font-size: 2rem; }
|
||||
.summary-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.method-steps { grid-template-columns: 1fr; }
|
||||
|
||||
.pie-legend {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.export-btn {
|
||||
display: none !important;
|
||||
}
|
||||
body {
|
||||
background-color: white !important;
|
||||
}
|
||||
.report-container {
|
||||
max-width: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="floating-export">
|
||||
<button class="export-btn-float" onclick="downloadPDF()" id="pdfBtn">
|
||||
<span id="btnText">📄</span>
|
||||
<div id="btnSpinner" class="loading-spinner" style="display: none;"></div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="report-container" id="reportContent">
|
||||
<!-- 报告头部 -->
|
||||
<div class="report-header">
|
||||
<!-- PDF导出按钮 - 嵌入在头部右上角 -->
|
||||
|
||||
|
||||
<h1 class="report-title" id="report-title"></h1>
|
||||
<p class="report-subtitle">基于层次分析法的多维度综合评估</p>
|
||||
<div class="report-meta">
|
||||
<span id="report-meta-object"></span>
|
||||
<span id="report-meta-date"></span>
|
||||
|
||||
</span>
|
||||
<span>评价方法:模糊综合评价法</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 执行摘要 -->
|
||||
<div class="executive-summary">
|
||||
<h2 class="section-title">📊 摘要信息</h2>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color: #3b82f6;" id="object_score"></div>
|
||||
<div class="summary-label">综合得分</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color: #10b981;" id="object_level"></div>
|
||||
<div class="summary-label" >评价等级</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color: #f59e0b;" id="highRate"> 70.0%</div>
|
||||
<div class="summary-label" >优良率</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color: #8b5cf6;" id="bottomNum">10</div>
|
||||
<div class="summary-label">底层指标数</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 方法论说明 -->
|
||||
<div class="methodology">
|
||||
<h2 class="section-title">🔬 评价方法论</h2>
|
||||
<div class="method-steps">
|
||||
<div class="method-step">
|
||||
<div class="step-number">1</div>
|
||||
<div class="step-title">构建指标体系</div>
|
||||
<div class="step-desc">建立3级指标体系,包含学术能力、社会影响、个人发展等维度</div>
|
||||
</div>
|
||||
<div class="method-step">
|
||||
<div class="step-number">2</div>
|
||||
<div class="step-title">确定权重分配</div>
|
||||
<div class="step-desc">运用层次分析法确定各级指标权重,确保评价体系的科学性</div>
|
||||
</div>
|
||||
<div class="method-step">
|
||||
<div class="step-number">3</div>
|
||||
<div class="step-title">隶属度计算</div>
|
||||
<div class="step-desc">建立模糊评价矩阵,计算各指标对不同等级的隶属度</div>
|
||||
</div>
|
||||
<div class="method-step">
|
||||
<div class="step-number">4</div>
|
||||
<div class="step-title">综合评价</div>
|
||||
<div class="step-desc">运用模糊综合评价算法,得出最终评价结果和等级分布</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 结果展示 -->
|
||||
<div class="results-section">
|
||||
<h2 class="section-title">📈 评价结果分析</h2>
|
||||
<div class="charts-grid">
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-title">隶属度等级分布</h3>
|
||||
<div class="chart-container">
|
||||
<div class="pie-chart-wrapper" id="pieChartWrapper"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<h3 class="chart-title">一级维度得分对比</h3>
|
||||
<div class="chart-container">
|
||||
<svg id="radarChart"></svg>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 详细数据表格 -->
|
||||
<div class="data-table-section">
|
||||
<div class="table-header">
|
||||
<h2 class="section-title">📋 详细评价数据</h2>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 35%;">指标名称</th>
|
||||
<th style="width: 15%;">权重</th>
|
||||
<th style="width: 30%;">隶属度分布</th>
|
||||
<th style="width: 15%;">综合得分</th>
|
||||
<th style="width: 5%;">等级</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="indicatorTable">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">指标评估记录</div>
|
||||
<div class="card-actions">
|
||||
<a href="#" class="btn btn-info w-100" th:data-result-id="${projectId}" onclick="goToHistory(this)">
|
||||
评估历史
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive" style="min-height:30em;overflow-x: auto;">
|
||||
<table class="table table-vcenter table-mobile-md card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>NO.</th>
|
||||
<th>名称</th>
|
||||
<th>最终分数</th>
|
||||
<th>隶属度</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="history,stat : ${rootList}">
|
||||
<td th:text="${stat.count}">
|
||||
|
||||
</td>
|
||||
<td th:text="${history.identifier}">
|
||||
|
||||
</td>
|
||||
<td th:text="${history.finalScore}">
|
||||
|
||||
</td>
|
||||
<td th:text="${history.membershipScore}">
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-list flex-nowrap"><a href="#" class="btn"
|
||||
th:data-result-id="${history.id}"
|
||||
onclick="viewResult(this)">
|
||||
查看报告
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user