2094 lines
141 KiB
HTML
2094 lines
141 KiB
HTML
<!DOCTYPE html>
|
||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="generator" content="pandoc" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||
<meta name="author" content="系统设计团队" />
|
||
<title>福建水务营收系统-系统架构设计</title>
|
||
<style>
|
||
code{white-space: pre-wrap;}
|
||
span.smallcaps{font-variant: small-caps;}
|
||
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||
div.column{flex: auto; overflow-x: auto;}
|
||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||
/* The extra [class] is a hack that increases specificity enough to
|
||
override a similar rule in reveal.js */
|
||
ul.task-list[class]{list-style: none;}
|
||
ul.task-list li input[type="checkbox"] {
|
||
font-size: inherit;
|
||
width: 0.8em;
|
||
margin: 0 0.8em 0.2em -1.6em;
|
||
vertical-align: middle;
|
||
}
|
||
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
||
/* CSS for syntax highlighting */
|
||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||
pre > code.sourceCode > span { line-height: 1.25; }
|
||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||
.sourceCode { overflow: visible; }
|
||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
pre > code.sourceCode { white-space: pre-wrap; }
|
||
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
|
||
}
|
||
pre.numberSource code
|
||
{ counter-reset: source-line 0; }
|
||
pre.numberSource code > span
|
||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||
pre.numberSource code > span > a:first-child::before
|
||
{ content: counter(source-line);
|
||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||
border: none; display: inline-block;
|
||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||
-khtml-user-select: none; -moz-user-select: none;
|
||
-ms-user-select: none; user-select: none;
|
||
padding: 0 4px; width: 4em;
|
||
color: #aaaaaa;
|
||
}
|
||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||
div.sourceCode
|
||
{ background-color: #f8f8f8; }
|
||
@media screen {
|
||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||
}
|
||
code span.al { color: #ef2929; } /* Alert */
|
||
code span.an { color: #8f5902; font-weight: bold; font-style: italic; } /* Annotation */
|
||
code span.at { color: #204a87; } /* Attribute */
|
||
code span.bn { color: #0000cf; } /* BaseN */
|
||
code span.cf { color: #204a87; font-weight: bold; } /* ControlFlow */
|
||
code span.ch { color: #4e9a06; } /* Char */
|
||
code span.cn { color: #8f5902; } /* Constant */
|
||
code span.co { color: #8f5902; font-style: italic; } /* Comment */
|
||
code span.cv { color: #8f5902; font-weight: bold; font-style: italic; } /* CommentVar */
|
||
code span.do { color: #8f5902; font-weight: bold; font-style: italic; } /* Documentation */
|
||
code span.dt { color: #204a87; } /* DataType */
|
||
code span.dv { color: #0000cf; } /* DecVal */
|
||
code span.er { color: #a40000; font-weight: bold; } /* Error */
|
||
code span.ex { } /* Extension */
|
||
code span.fl { color: #0000cf; } /* Float */
|
||
code span.fu { color: #204a87; font-weight: bold; } /* Function */
|
||
code span.im { } /* Import */
|
||
code span.in { color: #8f5902; font-weight: bold; font-style: italic; } /* Information */
|
||
code span.kw { color: #204a87; font-weight: bold; } /* Keyword */
|
||
code span.op { color: #ce5c00; font-weight: bold; } /* Operator */
|
||
code span.ot { color: #8f5902; } /* Other */
|
||
code span.pp { color: #8f5902; font-style: italic; } /* Preprocessor */
|
||
code span.sc { color: #ce5c00; font-weight: bold; } /* SpecialChar */
|
||
code span.ss { color: #4e9a06; } /* SpecialString */
|
||
code span.st { color: #4e9a06; } /* String */
|
||
code span.va { color: #000000; } /* Variable */
|
||
code span.vs { color: #4e9a06; } /* VerbatimString */
|
||
code span.wa { color: #8f5902; font-weight: bold; font-style: italic; } /* Warning */
|
||
</style>
|
||
<link rel="stylesheet" href="output/document_style.css" />
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
</head>
|
||
<body>
|
||
<header id="title-block-header">
|
||
<h1 class="title">福建水务营收系统-系统架构设计</h1>
|
||
<p class="author">系统设计团队</p>
|
||
<p class="date">2024年12月19日</p>
|
||
</header>
|
||
<nav id="TOC" role="doc-toc">
|
||
<ul>
|
||
<li><a href="#福建水务营收系统架构设计文档"
|
||
id="toc-福建水务营收系统架构设计文档"><span
|
||
class="toc-section-number">1</span> 福建水务营收系统架构设计文档</a>
|
||
<ul>
|
||
<li><a href="#文档信息" id="toc-文档信息"><span
|
||
class="toc-section-number">1.1</span> 文档信息</a></li>
|
||
<li><a href="#目录" id="toc-目录"><span
|
||
class="toc-section-number">1.2</span> 目录</a></li>
|
||
<li><a href="#一系统架构概述" id="toc-一系统架构概述"><span
|
||
class="toc-section-number">1.3</span> 一、系统架构概述</a>
|
||
<ul>
|
||
<li><a href="#系统总体架构图" id="toc-系统总体架构图"><span
|
||
class="toc-section-number">1.3.1</span> 1.1 系统总体架构图</a></li>
|
||
<li><a href="#物理部署架构图" id="toc-物理部署架构图"><span
|
||
class="toc-section-number">1.3.2</span> 1.2 物理部署架构图</a></li>
|
||
</ul></li>
|
||
<li><a href="#二技术架构" id="toc-二技术架构"><span
|
||
class="toc-section-number">1.4</span> 二、技术架构</a>
|
||
<ul>
|
||
<li><a href="#技术栈总览图" id="toc-技术栈总览图"><span
|
||
class="toc-section-number">1.4.1</span> 2.1 技术栈总览图</a></li>
|
||
<li><a href="#系统数据流向图" id="toc-系统数据流向图"><span
|
||
class="toc-section-number">1.4.2</span> 2.2 系统数据流向图</a></li>
|
||
<li><a href="#服务端技术架构" id="toc-服务端技术架构"><span
|
||
class="toc-section-number">1.4.3</span> 2.3 服务端技术架构</a>
|
||
<ul>
|
||
<li><a href="#ruoyi-vue-pro框架配置示例"
|
||
id="toc-ruoyi-vue-pro框架配置示例"><span
|
||
class="toc-section-number">1.4.3.1</span> 2.3.1
|
||
RuoYi-Vue-Pro框架配置示例</a></li>
|
||
</ul></li>
|
||
<li><a href="#客户端技术架构" id="toc-客户端技术架构"><span
|
||
class="toc-section-number">1.4.4</span> 2.4 客户端技术架构</a>
|
||
<ul>
|
||
<li><a href="#前端项目结构配置" id="toc-前端项目结构配置"><span
|
||
class="toc-section-number">1.4.4.1</span> 2.4.1
|
||
前端项目结构配置</a></li>
|
||
</ul></li>
|
||
<li><a href="#前端技术架构详细设计" id="toc-前端技术架构详细设计"><span
|
||
class="toc-section-number">1.4.5</span> 2.5 前端技术架构详细设计</a>
|
||
<ul>
|
||
<li><a href="#web管理端架构-yudao-ui-admin-vue3"
|
||
id="toc-web管理端架构-yudao-ui-admin-vue3"><span
|
||
class="toc-section-number">1.4.5.1</span> 2.5.1 Web管理端架构
|
||
(yudao-ui-admin-vue3)</a></li>
|
||
<li><a href="#移动端架构-uni-app" id="toc-移动端架构-uni-app"><span
|
||
class="toc-section-number">1.4.5.2</span> 2.5.2 移动端架构
|
||
(uni-app)</a></li>
|
||
<li><a href="#客户端小程序架构" id="toc-客户端小程序架构"><span
|
||
class="toc-section-number">1.4.5.3</span> 2.5.3
|
||
客户端小程序架构</a></li>
|
||
<li><a href="#前端工程化配置" id="toc-前端工程化配置"><span
|
||
class="toc-section-number">1.4.5.4</span> 2.5.4 前端工程化配置</a></li>
|
||
</ul></li>
|
||
<li><a href="#技术特性" id="toc-技术特性"><span
|
||
class="toc-section-number">1.4.6</span> 2.6 技术特性</a></li>
|
||
</ul></li>
|
||
<li><a href="#三应用架构" id="toc-三应用架构"><span
|
||
class="toc-section-number">1.5</span> 三、应用架构</a>
|
||
<ul>
|
||
<li><a href="#微服务应用架构图" id="toc-微服务应用架构图"><span
|
||
class="toc-section-number">1.5.1</span> 3.1 微服务应用架构图</a></li>
|
||
<li><a href="#服务治理架构" id="toc-服务治理架构"><span
|
||
class="toc-section-number">1.5.2</span> 3.2 服务治理架构</a></li>
|
||
<li><a href="#统一平台" id="toc-统一平台"><span
|
||
class="toc-section-number">1.5.3</span> 3.3 统一平台</a></li>
|
||
<li><a href="#营收系统" id="toc-营收系统"><span
|
||
class="toc-section-number">1.5.4</span> 3.4 营收系统</a></li>
|
||
<li><a href="#客户服务" id="toc-客户服务"><span
|
||
class="toc-section-number">1.5.5</span> 3.5 客户服务</a></li>
|
||
<li><a href="#表务系统" id="toc-表务系统"><span
|
||
class="toc-section-number">1.5.6</span> 3.6 表务系统</a></li>
|
||
<li><a href="#报装管理" id="toc-报装管理"><span
|
||
class="toc-section-number">1.5.7</span> 3.7 报装管理</a></li>
|
||
<li><a href="#统计分析" id="toc-统计分析"><span
|
||
class="toc-section-number">1.5.8</span> 3.8 统计分析</a></li>
|
||
<li><a href="#工程管理" id="toc-工程管理"><span
|
||
class="toc-section-number">1.5.9</span> 3.9 工程管理</a></li>
|
||
<li><a href="#抄表app" id="toc-抄表app"><span
|
||
class="toc-section-number">1.5.10</span> 3.10 抄表APP</a></li>
|
||
<li><a href="#接口服务" id="toc-接口服务"><span
|
||
class="toc-section-number">1.5.11</span> 3.11 接口服务</a></li>
|
||
<li><a href="#系统配置" id="toc-系统配置"><span
|
||
class="toc-section-number">1.5.12</span> 3.12 系统配置</a></li>
|
||
</ul></li>
|
||
<li><a href="#四数据架构" id="toc-四数据架构"><span
|
||
class="toc-section-number">1.6</span> 四、数据架构</a>
|
||
<ul>
|
||
<li><a href="#数据分层" id="toc-数据分层"><span
|
||
class="toc-section-number">1.6.1</span> 4.1 数据分层</a></li>
|
||
<li><a href="#opengauss数据库架构" id="toc-opengauss数据库架构"><span
|
||
class="toc-section-number">1.6.2</span> 4.2 OpenGauss数据库架构</a>
|
||
<ul>
|
||
<li><a href="#主从高可用架构" id="toc-主从高可用架构"><span
|
||
class="toc-section-number">1.6.2.1</span> 4.2.1 主从高可用架构</a></li>
|
||
<li><a href="#分片存储架构" id="toc-分片存储架构"><span
|
||
class="toc-section-number">1.6.2.2</span> 4.2.2 分片存储架构</a></li>
|
||
<li><a href="#数据安全架构" id="toc-数据安全架构"><span
|
||
class="toc-section-number">1.6.2.3</span> 4.2.3 数据安全架构</a></li>
|
||
</ul></li>
|
||
<li><a href="#数据模型设计" id="toc-数据模型设计"><span
|
||
class="toc-section-number">1.6.3</span> 4.3 数据模型设计</a></li>
|
||
<li><a href="#数据集成与共享" id="toc-数据集成与共享"><span
|
||
class="toc-section-number">1.6.4</span> 4.4 数据集成与共享</a></li>
|
||
<li><a href="#opengauss特性应用" id="toc-opengauss特性应用"><span
|
||
class="toc-section-number">1.6.5</span> 4.5 OpenGauss特性应用</a>
|
||
<ul>
|
||
<li><a href="#性能优化特性" id="toc-性能优化特性"><span
|
||
class="toc-section-number">1.6.5.1</span> 4.5.1 性能优化特性</a></li>
|
||
<li><a href="#企业级特性" id="toc-企业级特性"><span
|
||
class="toc-section-number">1.6.5.2</span> 4.5.2 企业级特性</a></li>
|
||
</ul></li>
|
||
</ul></li>
|
||
<li><a href="#五安全架构" id="toc-五安全架构"><span
|
||
class="toc-section-number">1.7</span> 五、安全架构</a>
|
||
<ul>
|
||
<li><a href="#网络安全" id="toc-网络安全"><span
|
||
class="toc-section-number">1.7.1</span> 5.1 网络安全</a></li>
|
||
<li><a href="#opengauss数据安全架构"
|
||
id="toc-opengauss数据安全架构"><span
|
||
class="toc-section-number">1.7.2</span> 5.2 OpenGauss数据安全架构</a>
|
||
<ul>
|
||
<li><a href="#数据加密安全" id="toc-数据加密安全"><span
|
||
class="toc-section-number">1.7.2.1</span> 5.2.1 数据加密安全</a></li>
|
||
<li><a href="#访问控制安全" id="toc-访问控制安全"><span
|
||
class="toc-section-number">1.7.2.2</span> 5.2.2 访问控制安全</a></li>
|
||
</ul></li>
|
||
<li><a href="#数据安全特性" id="toc-数据安全特性"><span
|
||
class="toc-section-number">1.7.3</span> 5.3 数据安全特性</a></li>
|
||
<li><a href="#多租户安全隔离" id="toc-多租户安全隔离"><span
|
||
class="toc-section-number">1.7.4</span> 5.4 多租户安全隔离</a></li>
|
||
<li><a href="#应用安全" id="toc-应用安全"><span
|
||
class="toc-section-number">1.7.5</span> 5.5 应用安全</a></li>
|
||
<li><a href="#接口安全" id="toc-接口安全"><span
|
||
class="toc-section-number">1.7.6</span> 5.6 接口安全</a></li>
|
||
</ul></li>
|
||
<li><a href="#六部署架构" id="toc-六部署架构"><span
|
||
class="toc-section-number">1.8</span> 六、部署架构</a>
|
||
<ul>
|
||
<li><a href="#物理部署" id="toc-物理部署"><span
|
||
class="toc-section-number">1.8.1</span> 6.1 物理部署</a></li>
|
||
<li><a href="#逻辑部署" id="toc-逻辑部署"><span
|
||
class="toc-section-number">1.8.2</span> 6.2 逻辑部署</a></li>
|
||
<li><a href="#容器部署" id="toc-容器部署"><span
|
||
class="toc-section-number">1.8.3</span> 6.3 容器部署</a></li>
|
||
</ul></li>
|
||
<li><a href="#七接口架构" id="toc-七接口架构"><span
|
||
class="toc-section-number">1.9</span> 七、接口架构</a>
|
||
<ul>
|
||
<li><a href="#外部接口" id="toc-外部接口"><span
|
||
class="toc-section-number">1.9.1</span> 7.1 外部接口</a></li>
|
||
<li><a href="#内部接口" id="toc-内部接口"><span
|
||
class="toc-section-number">1.9.2</span> 7.2 内部接口</a></li>
|
||
<li><a href="#接口标准" id="toc-接口标准"><span
|
||
class="toc-section-number">1.9.3</span> 7.3 接口标准</a></li>
|
||
<li><a href="#接口服务管理" id="toc-接口服务管理"><span
|
||
class="toc-section-number">1.9.4</span> 7.4 接口服务管理</a></li>
|
||
</ul></li>
|
||
</ul></li>
|
||
</ul>
|
||
</nav>
|
||
<h1 data-number="1" id="福建水务营收系统架构设计文档"><span
|
||
class="header-section-number">1</span> 福建水务营收系统架构设计文档</h1>
|
||
<h2 data-number="1.1" id="文档信息"><span
|
||
class="header-section-number">1.1</span> 文档信息</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>项目信息</th>
|
||
<th>详情</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>项目名称</strong></td>
|
||
<td>福建水务营收系统</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>文档类型</strong></td>
|
||
<td>概要设计文档</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>技术框架</strong></td>
|
||
<td>RuoYi-Vue-Pro + yudao-ui-admin-vue3</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>文档版本</strong></td>
|
||
<td>v1.0</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>编写日期</strong></td>
|
||
<td>2024-12-19</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>文档状态</strong></td>
|
||
<td>✅ 基本完成</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2 data-number="1.2" id="目录"><span
|
||
class="header-section-number">1.2</span> 目录</h2>
|
||
<ul>
|
||
<li><a href="#一系统架构概述">一、系统架构概述</a></li>
|
||
<li><a href="#二技术架构">二、技术架构</a></li>
|
||
<li><a href="#三应用架构">三、应用架构</a></li>
|
||
<li><a href="#四数据架构">四、数据架构</a></li>
|
||
<li><a href="#五安全架构">五、安全架构</a></li>
|
||
<li><a href="#六部署架构">六、部署架构</a></li>
|
||
<li><a href="#七接口架构">七、接口架构</a></li>
|
||
</ul>
|
||
<h2 data-number="1.3" id="一系统架构概述"><span
|
||
class="header-section-number">1.3</span> 一、系统架构概述</h2>
|
||
<p>福建水务营收系统采用多层架构设计,旨在支持集团化的集中管理、统一资源管理的业务需求。系统架构的设计目标是实现”一个业务平台、一网通平台”的建设目标,为集团及下属各分公司提供统一的营业收费系统。</p>
|
||
<p>系统架构主要包括以下核心特点: -
|
||
多租户架构:支持集团、分公司、营业站点的多层级租户管理模式 -
|
||
统一资源服务:统一的数字水务系统运行资源环境 -
|
||
统一平台应用:统一业务流程,集中汇集数据 -
|
||
统一对外接口:提供标准的接口和能力</p>
|
||
<h3 data-number="1.3.1" id="系统总体架构图"><span
|
||
class="header-section-number">1.3.1</span> 1.1 系统总体架构图</h3>
|
||
<p><strong>图表 1</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_1.png"
|
||
alt="图表 1" />
|
||
<figcaption aria-hidden="true">图表 1</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "用户层"
|
||
A1[Web管理端<br/>yudao-ui-admin-vue3]
|
||
A2[移动抄表端<br/>uni-app]
|
||
A3[客户微信端<br/>微信小程序]
|
||
A4[客户支付宝端<br/>支付宝小程序]
|
||
end
|
||
|
||
subgraph "网关层"
|
||
B1[Nginx负载均衡]
|
||
B2[API网关<br/>统一认证/权限控制]
|
||
end
|
||
|
||
subgraph "应用层"
|
||
C1[营收管理<br/>RuoYi-Vue-Pro]
|
||
C2[客户服务<br/>RuoYi-Vue-Pro]
|
||
C3[表务管理<br/>RuoYi-Vue-Pro]
|
||
C4[统计分析<br/>RuoYi-Vue-Pro]
|
||
end
|
||
|
||
subgraph "服务层"
|
||
D1[权限服务<br/>Spring Security]
|
||
D2[工作流服务<br/>Flowable]
|
||
D3[消息服务<br/>Redis MQ]
|
||
D4[文件服务<br/>MinIO/OSS]
|
||
end
|
||
|
||
subgraph "数据层"
|
||
E1[(OpenGauss 5.0+<br/>主从架构)]
|
||
E2[(Redis 6.0<br/>集群缓存)]
|
||
E3[文件存储<br/>分布式存储]
|
||
end
|
||
|
||
subgraph "外部接口"
|
||
F1[银行接口<br/>代扣/托收]
|
||
F2[支付接口<br/>微信/支付宝]
|
||
F3[短信接口<br/>阿里云/腾讯云]
|
||
F4[物联网接口<br/>智能水表]
|
||
end
|
||
|
||
A1 --> B1
|
||
A2 --> B1
|
||
A3 --> B1
|
||
A4 --> B1
|
||
|
||
B1 --> B2
|
||
B2 --> C1
|
||
B2 --> C2
|
||
B2 --> C3
|
||
B2 --> C4
|
||
|
||
C1 --> D1
|
||
C1 --> D2
|
||
C1 --> D3
|
||
C1 --> D4
|
||
C2 --> D1
|
||
C2 --> D3
|
||
C3 --> D1
|
||
C3 --> D2
|
||
C4 --> D1
|
||
|
||
D1 --> E1
|
||
D2 --> E1
|
||
D3 --> E2
|
||
D4 --> E3
|
||
|
||
C1 --> F1
|
||
C1 --> F2
|
||
C2 --> F3
|
||
C3 --> F4
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.3.2" id="物理部署架构图"><span
|
||
class="header-section-number">1.3.2</span> 1.2 物理部署架构图</h3>
|
||
<p><strong>图表 2</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_2.png"
|
||
alt="图表 2" />
|
||
<figcaption aria-hidden="true">图表 2</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "DMZ区域"
|
||
LB1[负载均衡器<br/>Nginx Cluster]
|
||
WAF[Web应用防火墙]
|
||
end
|
||
|
||
subgraph "应用服务区"
|
||
subgraph "Web服务集群"
|
||
WEB1[Web服务器1<br/>8核32G]
|
||
WEB2[Web服务器2<br/>8核32G]
|
||
end
|
||
|
||
subgraph "应用服务集群"
|
||
APP1[应用服务器1<br/>16核64G]
|
||
APP2[应用服务器2<br/>16核64G]
|
||
end
|
||
end
|
||
|
||
subgraph "数据服务区"
|
||
subgraph "数据库集群"
|
||
DB1[OpenGauss主库<br/>32核128G]
|
||
DB2[OpenGauss从库<br/>32核128G]
|
||
end
|
||
|
||
subgraph "缓存集群"
|
||
REDIS1[Redis主节点<br/>16核32G]
|
||
REDIS2[Redis从节点<br/>16核32G]
|
||
REDIS3[Redis哨兵<br/>8核16G]
|
||
end
|
||
|
||
subgraph "文件存储"
|
||
FILE1[文件服务器1<br/>8核32G 10TB]
|
||
FILE2[文件服务器2<br/>8核32G 10TB]
|
||
end
|
||
end
|
||
|
||
subgraph "管理服务区"
|
||
MONITOR[监控服务器<br/>8核16G]
|
||
BACKUP[备份服务器<br/>8核32G 20TB]
|
||
JUMP[跳板服务器<br/>4核8G]
|
||
end
|
||
|
||
Internet --> WAF
|
||
WAF --> LB1
|
||
LB1 --> WEB1
|
||
LB1 --> WEB2
|
||
|
||
WEB1 --> APP1
|
||
WEB1 --> APP2
|
||
WEB2 --> APP1
|
||
WEB2 --> APP2
|
||
|
||
APP1 --> DB1
|
||
APP2 --> DB1
|
||
DB1 --> DB2
|
||
|
||
APP1 --> REDIS1
|
||
APP2 --> REDIS1
|
||
REDIS1 --> REDIS2
|
||
REDIS3 --> REDIS1
|
||
REDIS3 --> REDIS2
|
||
|
||
APP1 --> FILE1
|
||
APP2 --> FILE2
|
||
FILE1 --> FILE2
|
||
|
||
MONITOR --> APP1
|
||
MONITOR --> APP2
|
||
MONITOR --> DB1
|
||
MONITOR --> REDIS1
|
||
|
||
BACKUP --> DB1
|
||
BACKUP --> FILE1
|
||
</code></pre>
|
||
</details>
|
||
<h2 data-number="1.4" id="二技术架构"><span
|
||
class="header-section-number">1.4</span> 二、技术架构</h2>
|
||
<p>系统采用B/S和M/S相结合的架构模式,具体技术栈如下:</p>
|
||
<h3 data-number="1.4.1" id="技术栈总览图"><span
|
||
class="header-section-number">1.4.1</span> 2.1 技术栈总览图</h3>
|
||
<p><strong>图表 3</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_3.png"
|
||
alt="图表 3" />
|
||
<figcaption aria-hidden="true">图表 3</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "前端技术栈"
|
||
FE1[Vue 3.2+ TypeScript]
|
||
FE2[Element Plus UI]
|
||
FE3[Vite 构建工具]
|
||
FE4[Pinia 状态管理]
|
||
FE5[Vue Router 路由]
|
||
FE6[Axios HTTP请求]
|
||
FE7[ECharts 图表]
|
||
FE8[富文本编辑器]
|
||
end
|
||
|
||
subgraph "后端技术栈"
|
||
BE1[Spring Boot 3.x]
|
||
BE2[Spring Security 6.x]
|
||
BE3[MyBatis Plus 3.x]
|
||
BE4[Redis 6.0+]
|
||
BE5[OpenGauss 5.0+]
|
||
BE6[Knife4j API文档]
|
||
BE7[Jackson JSON处理]
|
||
BE8[Maven 依赖管理]
|
||
end
|
||
|
||
subgraph "中间件技术栈"
|
||
MW1[Nginx 负载均衡]
|
||
MW2[Redis 缓存集群]
|
||
MW3[Flowable 工作流]
|
||
MW4[Quartz 定时任务]
|
||
MW5[MinIO 文件存储]
|
||
MW6[RocketMQ 消息队列]
|
||
MW7[ElasticSearch 搜索]
|
||
MW8[Sentinel 熔断限流]
|
||
end
|
||
|
||
subgraph "移动端技术栈"
|
||
MB1[uni-app 跨平台]
|
||
MB2[uView UI组件]
|
||
MB3[微信小程序]
|
||
MB4[支付宝小程序]
|
||
MB5[H5响应式]
|
||
MB6[高德地图SDK]
|
||
MB7[NFC设备接口]
|
||
end
|
||
|
||
subgraph "监控运维技术栈"
|
||
OP1[SkyWalking APM]
|
||
OP2[Spring Boot Admin]
|
||
OP3[Docker 容器化]
|
||
OP4[Kubernetes 编排]
|
||
OP5[Jenkins CI/CD]
|
||
OP6[Prometheus 监控]
|
||
OP7[Grafana 仪表盘]
|
||
OP8[ELK 日志分析]
|
||
end
|
||
|
||
FE1 --> BE1
|
||
FE6 --> BE1
|
||
BE1 --> BE2
|
||
BE1 --> BE3
|
||
BE3 --> BE5
|
||
BE1 --> BE4
|
||
BE1 --> MW3
|
||
BE1 --> MW4
|
||
MW1 --> BE1
|
||
BE1 --> MW5
|
||
BE1 --> MW6
|
||
BE1 --> MW7
|
||
MW8 --> BE1
|
||
|
||
MB1 --> BE1
|
||
MB3 --> BE1
|
||
MB4 --> BE1
|
||
|
||
OP1 --> BE1
|
||
OP2 --> BE1
|
||
OP3 --> BE1
|
||
OP4 --> OP3
|
||
OP5 --> OP4
|
||
OP6 --> BE1
|
||
OP7 --> OP6
|
||
OP8 --> BE1
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.4.2" id="系统数据流向图"><span
|
||
class="header-section-number">1.4.2</span> 2.2 系统数据流向图</h3>
|
||
<p><strong>图表 4</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_4.png"
|
||
alt="图表 4" />
|
||
<figcaption aria-hidden="true">图表 4</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>flowchart TD
|
||
subgraph "数据采集层"
|
||
A1[移动抄表APP<br/>数据采集]
|
||
A2[智能水表<br/>远程数据]
|
||
A3[Web管理端<br/>业务录入]
|
||
A4[客户端小程序<br/>用户数据]
|
||
A5[外部系统<br/>接口数据]
|
||
end
|
||
|
||
subgraph "数据接入层"
|
||
B1[API网关<br/>数据验证]
|
||
B2[数据清洗<br/>格式转换]
|
||
B3[消息队列<br/>异步处理]
|
||
B4[数据缓存<br/>临时存储]
|
||
end
|
||
|
||
subgraph "业务处理层"
|
||
C1[抄表服务<br/>水量计算]
|
||
C2[收费服务<br/>账单生成]
|
||
C3[账务服务<br/>财务处理]
|
||
C4[工单服务<br/>流程处理]
|
||
C5[统计服务<br/>数据分析]
|
||
end
|
||
|
||
subgraph "数据存储层"
|
||
D1[(MySQL主库<br/>核心业务数据)]
|
||
D2[(MySQL从库<br/>查询数据)]
|
||
D3[(Redis缓存<br/>热点数据)]
|
||
D4[文件存储<br/>附件图片]
|
||
D5[(备份库<br/>历史数据)]
|
||
end
|
||
|
||
subgraph "数据服务层"
|
||
E1[查询服务<br/>数据检索]
|
||
E2[报表服务<br/>统计分析]
|
||
E3[接口服务<br/>对外开放]
|
||
E4[推送服务<br/>消息通知]
|
||
end
|
||
|
||
subgraph "数据展现层"
|
||
F1[管理后台<br/>业务操作]
|
||
F2[统计大屏<br/>可视化展示]
|
||
F3[移动端<br/>现场作业]
|
||
F4[客户端<br/>自助服务]
|
||
F5[第三方系统<br/>数据集成]
|
||
end
|
||
|
||
%% 数据流向关系
|
||
A1 --> B1
|
||
A2 --> B2
|
||
A3 --> B1
|
||
A4 --> B1
|
||
A5 --> B3
|
||
|
||
B1 --> B4
|
||
B2 --> B3
|
||
B3 --> C1
|
||
B4 --> C2
|
||
|
||
C1 --> D1
|
||
C2 --> D1
|
||
C3 --> D1
|
||
C4 --> D1
|
||
C5 --> D2
|
||
|
||
D1 --> D2
|
||
D1 --> D3
|
||
D1 --> D5
|
||
|
||
D2 --> E1
|
||
D3 --> E1
|
||
D1 --> E2
|
||
D2 --> E3
|
||
|
||
E1 --> F1
|
||
E2 --> F2
|
||
E3 --> F3
|
||
E4 --> F4
|
||
E3 --> F5
|
||
|
||
%% 反向数据流
|
||
F1 -.-> C2
|
||
F3 -.-> C1
|
||
F4 -.-> C3
|
||
F5 -.-> C4
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.4.3" id="服务端技术架构"><span
|
||
class="header-section-number">1.4.3</span> 2.3 服务端技术架构</h3>
|
||
<ul>
|
||
<li>操作系统:国产 Linux 操作系统</li>
|
||
<li>数据库:华为OpenGauss 5.0+数据库,企业级国产数据库</li>
|
||
<li>应用框架:基于RuoYi-Vue-Pro框架定制开发
|
||
<ul>
|
||
<li>核心框架:Spring Boot 3.x,支持JDK 17/21</li>
|
||
<li>ORM框架:MyBatis Plus,增强的MyBatis</li>
|
||
<li>权限框架:Spring Security,基于RBAC的权限管理</li>
|
||
<li>数据缓存:Redis + Redisson,高性能缓存和分布式锁</li>
|
||
<li>工作流引擎:Flowable,灵活的工作流处理</li>
|
||
<li>任务调度:基于Quartz的CRON任务调度</li>
|
||
<li>服务监控:Spring Boot Admin、SkyWalking APM</li>
|
||
<li>消息队列:基于Redis的轻量级消息队列</li>
|
||
<li>文档生成:Knife4j,基于Swagger的API文档生成</li>
|
||
<li>代码生成:自动化CRUD和表单代码生成器</li>
|
||
<li>多租户:基于字段隔离的SaaS多租户设计</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h4 data-number="1.4.3.1" id="ruoyi-vue-pro框架配置示例"><span
|
||
class="header-section-number">1.4.3.1</span> 2.3.1
|
||
RuoYi-Vue-Pro框架配置示例</h4>
|
||
<p><strong>application.yml主配置文件:</strong></p>
|
||
<div class="sourceCode" id="cb5"><pre
|
||
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># 服务端口配置</span></span>
|
||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="fu">server</span><span class="kw">:</span></span>
|
||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">port</span><span class="kw">:</span><span class="at"> </span><span class="dv">48080</span></span>
|
||
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">servlet</span><span class="kw">:</span></span>
|
||
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">context-path</span><span class="kw">:</span><span class="at"> /admin-api</span></span>
|
||
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Spring Boot 配置</span></span>
|
||
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="fu">spring</span><span class="kw">:</span></span>
|
||
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">application</span><span class="kw">:</span></span>
|
||
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">name</span><span class="kw">:</span><span class="at"> water-biz-server</span></span>
|
||
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">profiles</span><span class="kw">:</span></span>
|
||
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">active</span><span class="kw">:</span><span class="at"> local</span></span>
|
||
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="at"> </span></span>
|
||
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="co"> # 数据源配置</span></span>
|
||
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">datasource</span><span class="kw">:</span></span>
|
||
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">druid</span><span class="kw">:</span></span>
|
||
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">url</span><span class="kw">:</span><span class="at"> jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true</span></span>
|
||
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">username</span><span class="kw">:</span><span class="at"> root</span></span>
|
||
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">password</span><span class="kw">:</span><span class="at"> ${MYSQL_PASSWORD:123456}</span></span>
|
||
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">driver-class-name</span><span class="kw">:</span><span class="at"> com.mysql.cj.jdbc.Driver</span></span>
|
||
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="co"> # 连接池配置</span></span>
|
||
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">initial-size</span><span class="kw">:</span><span class="at"> </span><span class="dv">10</span></span>
|
||
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">min-idle</span><span class="kw">:</span><span class="at"> </span><span class="dv">10</span></span>
|
||
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-active</span><span class="kw">:</span><span class="at"> </span><span class="dv">20</span></span>
|
||
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-wait</span><span class="kw">:</span><span class="at"> </span><span class="dv">60000</span></span>
|
||
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">time-between-eviction-runs-millis</span><span class="kw">:</span><span class="at"> </span><span class="dv">60000</span></span>
|
||
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">min-evictable-idle-time-millis</span><span class="kw">:</span><span class="at"> </span><span class="dv">300000</span></span>
|
||
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">validation-query</span><span class="kw">:</span><span class="at"> SELECT 1 FROM DUAL</span></span>
|
||
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">test-while-idle</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
|
||
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">test-on-borrow</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
|
||
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">test-on-return</span><span class="kw">:</span><span class="at"> </span><span class="ch">false</span></span>
|
||
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">pool-prepared-statements</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
|
||
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-pool-prepared-statement-per-connection-size</span><span class="kw">:</span><span class="at"> </span><span class="dv">20</span></span>
|
||
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a><span class="at"> </span></span>
|
||
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a><span class="co"> # Redis 配置</span></span>
|
||
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">redis</span><span class="kw">:</span></span>
|
||
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">host</span><span class="kw">:</span><span class="at"> </span><span class="fl">127.0.0.1</span></span>
|
||
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">port</span><span class="kw">:</span><span class="at"> </span><span class="dv">6379</span></span>
|
||
<span id="cb5-39"><a href="#cb5-39" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">password</span><span class="kw">:</span><span class="at"> ${REDIS_PASSWORD:}</span></span>
|
||
<span id="cb5-40"><a href="#cb5-40" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">database</span><span class="kw">:</span><span class="at"> </span><span class="dv">1</span></span>
|
||
<span id="cb5-41"><a href="#cb5-41" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">timeout</span><span class="kw">:</span><span class="at"> 6000ms</span></span>
|
||
<span id="cb5-42"><a href="#cb5-42" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">lettuce</span><span class="kw">:</span></span>
|
||
<span id="cb5-43"><a href="#cb5-43" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">pool</span><span class="kw">:</span></span>
|
||
<span id="cb5-44"><a href="#cb5-44" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-active</span><span class="kw">:</span><span class="at"> </span><span class="dv">32</span></span>
|
||
<span id="cb5-45"><a href="#cb5-45" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-wait</span><span class="kw">:</span><span class="at"> 6000ms</span></span>
|
||
<span id="cb5-46"><a href="#cb5-46" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">max-idle</span><span class="kw">:</span><span class="at"> </span><span class="dv">32</span></span>
|
||
<span id="cb5-47"><a href="#cb5-47" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">min-idle</span><span class="kw">:</span><span class="at"> </span><span class="dv">8</span></span>
|
||
<span id="cb5-48"><a href="#cb5-48" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb5-49"><a href="#cb5-49" aria-hidden="true" tabindex="-1"></a><span class="co"># MyBatis Plus 配置</span></span>
|
||
<span id="cb5-50"><a href="#cb5-50" aria-hidden="true" tabindex="-1"></a><span class="fu">mybatis-plus</span><span class="kw">:</span></span>
|
||
<span id="cb5-51"><a href="#cb5-51" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">configuration</span><span class="kw">:</span></span>
|
||
<span id="cb5-52"><a href="#cb5-52" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">map-underscore-to-camel-case</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
|
||
<span id="cb5-53"><a href="#cb5-53" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">log-impl</span><span class="kw">:</span><span class="at"> org.apache.ibatis.logging.stdout.StdOutImpl</span></span>
|
||
<span id="cb5-54"><a href="#cb5-54" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">global-config</span><span class="kw">:</span></span>
|
||
<span id="cb5-55"><a href="#cb5-55" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">db-config</span><span class="kw">:</span></span>
|
||
<span id="cb5-56"><a href="#cb5-56" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">id-type</span><span class="kw">:</span><span class="at"> NONE</span></span>
|
||
<span id="cb5-57"><a href="#cb5-57" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">logic-delete-field</span><span class="kw">:</span><span class="at"> deleted</span></span>
|
||
<span id="cb5-58"><a href="#cb5-58" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">logic-delete-value</span><span class="kw">:</span><span class="at"> </span><span class="dv">1</span></span>
|
||
<span id="cb5-59"><a href="#cb5-59" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">logic-not-delete-value</span><span class="kw">:</span><span class="at"> </span><span class="dv">0</span></span>
|
||
<span id="cb5-60"><a href="#cb5-60" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">type-aliases-package</span><span class="kw">:</span><span class="at"> cn.iocoder.yudao.module.*.dal.dataobject</span></span>
|
||
<span id="cb5-61"><a href="#cb5-61" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb5-62"><a href="#cb5-62" aria-hidden="true" tabindex="-1"></a><span class="co"># 水务系统多租户配置</span></span>
|
||
<span id="cb5-63"><a href="#cb5-63" aria-hidden="true" tabindex="-1"></a><span class="fu">yudao</span><span class="kw">:</span></span>
|
||
<span id="cb5-64"><a href="#cb5-64" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">tenant</span><span class="kw">:</span></span>
|
||
<span id="cb5-65"><a href="#cb5-65" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">enable</span><span class="kw">:</span><span class="at"> </span><span class="ch">true</span></span>
|
||
<span id="cb5-66"><a href="#cb5-66" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">ignore-urls</span><span class="kw">:</span></span>
|
||
<span id="cb5-67"><a href="#cb5-67" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/tenant/get-id-by-name</span></span>
|
||
<span id="cb5-68"><a href="#cb5-68" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/infra/file/*/get/**</span></span>
|
||
<span id="cb5-69"><a href="#cb5-69" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">ignore-tables</span><span class="kw">:</span></span>
|
||
<span id="cb5-70"><a href="#cb5-70" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> water_tenant</span></span>
|
||
<span id="cb5-71"><a href="#cb5-71" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> water_system_config</span></span>
|
||
<span id="cb5-72"><a href="#cb5-72" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> water_dict_data</span></span>
|
||
<span id="cb5-73"><a href="#cb5-73" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> water_dict_type</span></span>
|
||
<span id="cb5-74"><a href="#cb5-74" aria-hidden="true" tabindex="-1"></a><span class="at"> </span></span>
|
||
<span id="cb5-75"><a href="#cb5-75" aria-hidden="true" tabindex="-1"></a><span class="co"> # 水务系统安全配置</span></span>
|
||
<span id="cb5-76"><a href="#cb5-76" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">security</span><span class="kw">:</span></span>
|
||
<span id="cb5-77"><a href="#cb5-77" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">permit-all-urls</span><span class="kw">:</span></span>
|
||
<span id="cb5-78"><a href="#cb5-78" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/auth/login</span></span>
|
||
<span id="cb5-79"><a href="#cb5-79" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/auth/logout</span></span>
|
||
<span id="cb5-80"><a href="#cb5-80" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/auth/refresh-token</span></span>
|
||
<span id="cb5-81"><a href="#cb5-81" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/captcha/get</span></span>
|
||
<span id="cb5-82"><a href="#cb5-82" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="kw">-</span><span class="at"> /admin-api/water/sms/send</span></span>
|
||
<span id="cb5-83"><a href="#cb5-83" aria-hidden="true" tabindex="-1"></a><span class="at"> </span></span>
|
||
<span id="cb5-84"><a href="#cb5-84" aria-hidden="true" tabindex="-1"></a><span class="co"> # 文件存储配置</span></span>
|
||
<span id="cb5-85"><a href="#cb5-85" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">file</span><span class="kw">:</span></span>
|
||
<span id="cb5-86"><a href="#cb5-86" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">config</span><span class="kw">:</span></span>
|
||
<span id="cb5-87"><a href="#cb5-87" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">type</span><span class="kw">:</span><span class="at"> local</span></span>
|
||
<span id="cb5-88"><a href="#cb5-88" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">local</span><span class="kw">:</span></span>
|
||
<span id="cb5-89"><a href="#cb5-89" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">domain</span><span class="kw">:</span><span class="at"> http://127.0.0.1:48080</span></span>
|
||
<span id="cb5-90"><a href="#cb5-90" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">path</span><span class="kw">:</span><span class="at"> /Users/yunai/file_test</span></span>
|
||
<span id="cb5-91"><a href="#cb5-91" aria-hidden="true" tabindex="-1"></a><span class="at"> </span></span>
|
||
<span id="cb5-92"><a href="#cb5-92" aria-hidden="true" tabindex="-1"></a><span class="co"> # 短信配置</span></span>
|
||
<span id="cb5-93"><a href="#cb5-93" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">sms</span><span class="kw">:</span></span>
|
||
<span id="cb5-94"><a href="#cb5-94" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">alibaba</span><span class="kw">:</span></span>
|
||
<span id="cb5-95"><a href="#cb5-95" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">access-key-id</span><span class="kw">:</span><span class="at"> ${SMS_ACCESS_KEY_ID:}</span></span>
|
||
<span id="cb5-96"><a href="#cb5-96" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">access-key-secret</span><span class="kw">:</span><span class="at"> ${SMS_ACCESS_KEY_SECRET:}</span></span>
|
||
<span id="cb5-97"><a href="#cb5-97" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">signature</span><span class="kw">:</span><span class="at"> 福建水务</span></span>
|
||
<span id="cb5-98"><a href="#cb5-98" aria-hidden="true" tabindex="-1"></a><span class="at"> </span><span class="fu">template-code</span><span class="kw">:</span><span class="at"> SMS_123456</span></span></code></pre></div>
|
||
<p><strong>多租户配置实现:</strong></p>
|
||
<div class="sourceCode" id="cb6"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Component</span></span>
|
||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="at">@Slf4j</span></span>
|
||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> WaterTenantConfiguration <span class="op">{</span></span>
|
||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
|
||
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> TenantProperties tenantProperties<span class="op">;</span></span>
|
||
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> <span class="co">/**</span></span>
|
||
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> <span class="co">*</span> <span class="co">多租户字段处理器</span></span>
|
||
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> <span class="co">*/</span></span>
|
||
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> <span class="at">@Bean</span></span>
|
||
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> TenantLineHandler <span class="fu">tenantLineHandler</span><span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">TenantLineHandler</span><span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
|
||
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">Expression</span> <span class="fu">getTenantId</span><span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// 从当前登录用户上下文获取租户ID</span></span>
|
||
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a> <span class="bu">Long</span> tenantId <span class="op">=</span> TenantContextHolder<span class="op">.</span><span class="fu">getTenantId</span><span class="op">();</span></span>
|
||
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tenantId <span class="op">==</span> <span class="kw">null</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">null</span><span class="op">;</span></span>
|
||
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">LongValue</span><span class="op">(</span>tenantId<span class="op">);</span></span>
|
||
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
|
||
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">getTenantIdColumn</span><span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="st">"tenant_id"</span><span class="op">;</span></span>
|
||
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
|
||
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">boolean</span> <span class="fu">ignoreTable</span><span class="op">(</span><span class="bu">String</span> tableName<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a> <span class="co">// 忽略的表不进行多租户处理</span></span>
|
||
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> tenantProperties<span class="op">.</span><span class="fu">getIgnoreTables</span><span class="op">().</span><span class="fu">contains</span><span class="op">(</span>tableName<span class="op">);</span></span>
|
||
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a> <span class="op">};</span></span>
|
||
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a> <span class="co">/**</span></span>
|
||
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a> <span class="co">*</span> <span class="co">多租户拦截器</span></span>
|
||
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a> <span class="co">*/</span></span>
|
||
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a> <span class="at">@Bean</span></span>
|
||
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> MybatisPlusInterceptor <span class="fu">mybatisPlusInterceptor</span><span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a> MybatisPlusInterceptor interceptor <span class="op">=</span> <span class="kw">new</span> <span class="fu">MybatisPlusInterceptor</span><span class="op">();</span></span>
|
||
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a> <span class="co">// 多租户插件</span></span>
|
||
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a> TenantLineInnerInterceptor tenantInterceptor <span class="op">=</span> <span class="kw">new</span> <span class="fu">TenantLineInnerInterceptor</span><span class="op">();</span></span>
|
||
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a> tenantInterceptor<span class="op">.</span><span class="fu">setTenantLineHandler</span><span class="op">(</span><span class="fu">tenantLineHandler</span><span class="op">());</span></span>
|
||
<span id="cb6-47"><a href="#cb6-47" aria-hidden="true" tabindex="-1"></a> interceptor<span class="op">.</span><span class="fu">addInnerInterceptor</span><span class="op">(</span>tenantInterceptor<span class="op">);</span></span>
|
||
<span id="cb6-48"><a href="#cb6-48" aria-hidden="true" tabindex="-1"></a> <span class="co">// 分页插件</span></span>
|
||
<span id="cb6-49"><a href="#cb6-49" aria-hidden="true" tabindex="-1"></a> interceptor<span class="op">.</span><span class="fu">addInnerInterceptor</span><span class="op">(</span><span class="kw">new</span> <span class="fu">PaginationInnerInterceptor</span><span class="op">(</span>DbType<span class="op">.</span><span class="fu">MYSQL</span><span class="op">));</span></span>
|
||
<span id="cb6-50"><a href="#cb6-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> interceptor<span class="op">;</span></span>
|
||
<span id="cb6-51"><a href="#cb6-51" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb6-52"><a href="#cb6-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><strong>权限控制配置:</strong></p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="at">@EnableWebSecurity</span></span>
|
||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="at">@EnableMethodSecurity</span><span class="op">(</span>prePostEnabled <span class="op">=</span> <span class="kw">true</span><span class="op">,</span> securedEnabled <span class="op">=</span> <span class="kw">true</span><span class="op">)</span></span>
|
||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="at">@Configuration</span></span>
|
||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> WaterSecurityConfiguration <span class="op">{</span></span>
|
||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
|
||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> SecurityProperties securityProperties<span class="op">;</span></span>
|
||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="at">@Bean</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> SecurityFilterChain <span class="fu">filterChain</span><span class="op">(</span>HttpSecurity httpSecurity<span class="op">,</span></span>
|
||
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="at">@Lazy</span> TokenAuthenticationFilter tokenAuthenticationFilter<span class="op">)</span> <span class="kw">throws</span> <span class="bu">Exception</span> <span class="op">{</span></span>
|
||
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> httpSecurity</span>
|
||
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// 设置 URL 安全权限</span></span>
|
||
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">authorizeHttpRequests</span><span class="op">(</span>c <span class="op">-></span> c</span>
|
||
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// 1. 静态资源,可匿名访问</span></span>
|
||
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">requestMatchers</span><span class="op">(</span>HttpMethod<span class="op">.</span><span class="fu">GET</span><span class="op">,</span> <span class="st">"/*.html"</span><span class="op">,</span> <span class="st">"/**/*.html"</span><span class="op">,</span> <span class="st">"/**/*.css"</span><span class="op">,</span> <span class="st">"/**/*.js"</span><span class="op">).</span><span class="fu">permitAll</span><span class="op">()</span></span>
|
||
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// 2. 设置 @PermitAll 无需认证</span></span>
|
||
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">requestMatchers</span><span class="op">(</span>securityProperties<span class="op">.</span><span class="fu">getPermitAllUrls</span><span class="op">().</span><span class="fu">toArray</span><span class="op">(</span><span class="kw">new</span> <span class="bu">String</span><span class="op">[</span><span class="dv">0</span><span class="op">])).</span><span class="fu">permitAll</span><span class="op">()</span></span>
|
||
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// 3. 兜底规则,必须认证</span></span>
|
||
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">anyRequest</span><span class="op">().</span><span class="fu">authenticated</span><span class="op">()</span></span>
|
||
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a> <span class="op">)</span></span>
|
||
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a> <span class="co">// 设置处理器</span></span>
|
||
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">exceptionHandling</span><span class="op">(</span>c <span class="op">-></span> c<span class="op">.</span><span class="fu">authenticationEntryPoint</span><span class="op">(</span>authenticationEntryPoint<span class="op">)</span></span>
|
||
<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">accessDeniedHandler</span><span class="op">(</span>accessDeniedHandler<span class="op">))</span></span>
|
||
<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a> <span class="co">// 添加 Token Filter</span></span>
|
||
<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">addFilterBefore</span><span class="op">(</span>tokenAuthenticationFilter<span class="op">,</span> UsernamePasswordAuthenticationFilter<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
|
||
<span id="cb7-27"><a href="#cb7-27" aria-hidden="true" tabindex="-1"></a> <span class="co">// 不创建 SecurityContext</span></span>
|
||
<span id="cb7-28"><a href="#cb7-28" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">sessionManagement</span><span class="op">(</span>c <span class="op">-></span> c<span class="op">.</span><span class="fu">sessionCreationPolicy</span><span class="op">(</span>SessionCreationPolicy<span class="op">.</span><span class="fu">STATELESS</span><span class="op">))</span></span>
|
||
<span id="cb7-29"><a href="#cb7-29" aria-hidden="true" tabindex="-1"></a> <span class="co">// 禁用 CSRF,因为使用 token 机制</span></span>
|
||
<span id="cb7-30"><a href="#cb7-30" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">csrf</span><span class="op">(</span>AbstractHttpConfigurer<span class="op">::</span>disable<span class="op">)</span></span>
|
||
<span id="cb7-31"><a href="#cb7-31" aria-hidden="true" tabindex="-1"></a> <span class="co">// 禁用 cors</span></span>
|
||
<span id="cb7-32"><a href="#cb7-32" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">cors</span><span class="op">(</span>AbstractHttpConfigurer<span class="op">::</span>disable<span class="op">)</span></span>
|
||
<span id="cb7-33"><a href="#cb7-33" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">build</span><span class="op">();</span></span>
|
||
<span id="cb7-34"><a href="#cb7-34" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb7-35"><a href="#cb7-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h3 data-number="1.4.4" id="客户端技术架构"><span
|
||
class="header-section-number">1.4.4</span> 2.4 客户端技术架构</h3>
|
||
<ul>
|
||
<li>前端框架:基于yudao-ui-admin-vue3框架定制开发
|
||
<ul>
|
||
<li>核心框架:Vue 3.x + TypeScript</li>
|
||
<li>组件库:Element Plus,现代化UI组件</li>
|
||
<li>状态管理:Pinia,新一代的Vue状态管理库</li>
|
||
<li>路由管理:Vue Router</li>
|
||
<li>HTTP工具:Axios,请求拦截与统一处理</li>
|
||
<li>CSS框架:Tailwind CSS / UnoCSS,原子化CSS</li>
|
||
<li>图表组件:ECharts,强大的可视化图表库</li>
|
||
<li>富文本编辑器:WangEditor</li>
|
||
<li>文件上传:基于Element Plus的上传组件</li>
|
||
<li>权限控制:细粒度的按钮级权限控制</li>
|
||
<li>动态表格:支持拖拽、排序、筛选</li>
|
||
<li>代码规范:ESLint + Prettier,标准化代码风格</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h4 data-number="1.4.4.1" id="前端项目结构配置"><span
|
||
class="header-section-number">1.4.4.1</span> 2.4.1 前端项目结构配置</h4>
|
||
<p><strong>package.json 依赖配置:</strong></p>
|
||
<div class="sourceCode" id="cb8"><pre
|
||
class="sourceCode json"><code class="sourceCode json"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"name"</span><span class="fu">:</span> <span class="st">"water-biz-ui-admin"</span><span class="fu">,</span></span>
|
||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"version"</span><span class="fu">:</span> <span class="st">"1.0.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"description"</span><span class="fu">:</span> <span class="st">"福建水务营收系统管理后台"</span><span class="fu">,</span></span>
|
||
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"dependencies"</span><span class="fu">:</span> <span class="fu">{</span></span>
|
||
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@element-plus/icons-vue"</span><span class="fu">:</span> <span class="st">"^2.1.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@vueuse/core"</span><span class="fu">:</span> <span class="st">"^10.5.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">"axios"</span><span class="fu">:</span> <span class="st">"^1.6.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">"echarts"</span><span class="fu">:</span> <span class="st">"^5.4.3"</span><span class="fu">,</span></span>
|
||
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">"element-plus"</span><span class="fu">:</span> <span class="st">"^2.4.2"</span><span class="fu">,</span></span>
|
||
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">"pinia"</span><span class="fu">:</span> <span class="st">"^2.1.7"</span><span class="fu">,</span></span>
|
||
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">"vue"</span><span class="fu">:</span> <span class="st">"^3.3.8"</span><span class="fu">,</span></span>
|
||
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">"vue-router"</span><span class="fu">:</span> <span class="st">"^4.2.5"</span><span class="fu">,</span></span>
|
||
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@wangeditor/editor"</span><span class="fu">:</span> <span class="st">"^5.1.23"</span><span class="fu">,</span></span>
|
||
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@wangeditor/editor-for-vue"</span><span class="fu">:</span> <span class="st">"^5.1.12"</span></span>
|
||
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">},</span></span>
|
||
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">"devDependencies"</span><span class="fu">:</span> <span class="fu">{</span></span>
|
||
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@types/node"</span><span class="fu">:</span> <span class="st">"^20.8.7"</span><span class="fu">,</span></span>
|
||
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@typescript-eslint/eslint-plugin"</span><span class="fu">:</span> <span class="st">"^6.9.1"</span><span class="fu">,</span></span>
|
||
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@typescript-eslint/parser"</span><span class="fu">:</span> <span class="st">"^6.9.1"</span><span class="fu">,</span></span>
|
||
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@vitejs/plugin-vue"</span><span class="fu">:</span> <span class="st">"^4.4.1"</span><span class="fu">,</span></span>
|
||
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a> <span class="dt">"eslint"</span><span class="fu">:</span> <span class="st">"^8.52.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a> <span class="dt">"eslint-plugin-vue"</span><span class="fu">:</span> <span class="st">"^9.17.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a> <span class="dt">"prettier"</span><span class="fu">:</span> <span class="st">"^3.0.3"</span><span class="fu">,</span></span>
|
||
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a> <span class="dt">"typescript"</span><span class="fu">:</span> <span class="st">"^5.2.2"</span><span class="fu">,</span></span>
|
||
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a> <span class="dt">"vite"</span><span class="fu">:</span> <span class="st">"^4.5.0"</span><span class="fu">,</span></span>
|
||
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a> <span class="dt">"vue-tsc"</span><span class="fu">:</span> <span class="st">"^1.8.22"</span></span>
|
||
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
|
||
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
||
<p><strong>vite.config.ts 构建配置:</strong></p>
|
||
<div class="sourceCode" id="cb9"><pre
|
||
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { defineConfig } <span class="im">from</span> <span class="st">'vite'</span></span>
|
||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> vue <span class="im">from</span> <span class="st">'@vitejs/plugin-vue'</span></span>
|
||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { resolve } <span class="im">from</span> <span class="st">'path'</span></span>
|
||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> <span class="fu">defineConfig</span>({</span>
|
||
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> plugins<span class="op">:</span> [<span class="fu">vue</span>()]<span class="op">,</span></span>
|
||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> resolve<span class="op">:</span> {</span>
|
||
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> alias<span class="op">:</span> {</span>
|
||
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> <span class="st">'@'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src'</span>)<span class="op">,</span></span>
|
||
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a> <span class="st">'~'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src'</span>)<span class="op">,</span></span>
|
||
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> <span class="st">'#'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'types'</span>)</span>
|
||
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> server<span class="op">:</span> {</span>
|
||
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a> host<span class="op">:</span> <span class="st">'0.0.0.0'</span><span class="op">,</span></span>
|
||
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a> port<span class="op">:</span> <span class="dv">3000</span><span class="op">,</span></span>
|
||
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a> open<span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
|
||
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a> proxy<span class="op">:</span> {</span>
|
||
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a> <span class="st">'/admin-api'</span><span class="op">:</span> {</span>
|
||
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a> target<span class="op">:</span> <span class="st">'http://127.0.0.1:48080'</span><span class="op">,</span></span>
|
||
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a> changeOrigin<span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
|
||
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a> ws<span class="op">:</span> <span class="kw">true</span></span>
|
||
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a> build<span class="op">:</span> {</span>
|
||
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a> target<span class="op">:</span> <span class="st">'es2015'</span><span class="op">,</span></span>
|
||
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a> outDir<span class="op">:</span> <span class="st">'dist'</span><span class="op">,</span></span>
|
||
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a> assetsDir<span class="op">:</span> <span class="st">'static'</span><span class="op">,</span></span>
|
||
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a> sourcemap<span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
|
||
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a> chunkSizeWarningLimit<span class="op">:</span> <span class="dv">1500</span><span class="op">,</span></span>
|
||
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a> rollupOptions<span class="op">:</span> {</span>
|
||
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a> output<span class="op">:</span> {</span>
|
||
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a> chunkFileNames<span class="op">:</span> <span class="st">'static/js/[name]-[hash].js'</span><span class="op">,</span></span>
|
||
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a> entryFileNames<span class="op">:</span> <span class="st">'static/js/[name]-[hash].js'</span><span class="op">,</span></span>
|
||
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a> assetFileNames<span class="op">:</span> <span class="st">'static/[ext]/[name]-[hash].[ext]'</span></span>
|
||
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
|
||
<p><strong>src/stores/user.ts 用户状态管理:</strong></p>
|
||
<div class="sourceCode" id="cb10"><pre
|
||
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { defineStore } <span class="im">from</span> <span class="st">'pinia'</span></span>
|
||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { ref<span class="op">,</span> computed } <span class="im">from</span> <span class="st">'vue'</span></span>
|
||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { UserApi<span class="op">,</span> UserVO } <span class="im">from</span> <span class="st">'@/api/system/user'</span></span>
|
||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { getAccessToken<span class="op">,</span> removeToken } <span class="im">from</span> <span class="st">'@/utils/auth'</span></span>
|
||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">const</span> useUserStore <span class="op">=</span> <span class="fu">defineStore</span>(<span class="st">'user'</span><span class="op">,</span> () <span class="kw">=></span> {</span>
|
||
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> userInfo <span class="op">=</span> <span class="fu">ref</span><span class="op"><</span>UserVO<span class="op">></span>()</span>
|
||
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> permissions <span class="op">=</span> <span class="fu">ref</span><span class="op"><</span><span class="dt">string</span>[]<span class="op">></span>([])</span>
|
||
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> roles <span class="op">=</span> <span class="fu">ref</span><span class="op"><</span><span class="dt">string</span>[]<span class="op">></span>([])</span>
|
||
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> nickname <span class="op">=</span> <span class="fu">computed</span>(() <span class="kw">=></span> userInfo<span class="op">.</span><span class="at">value</span><span class="op">?.</span><span class="at">nickname</span> <span class="op">??</span> <span class="st">''</span>)</span>
|
||
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> avatar <span class="op">=</span> <span class="fu">computed</span>(() <span class="kw">=></span> userInfo<span class="op">.</span><span class="at">value</span><span class="op">?.</span><span class="at">avatar</span> <span class="op">??</span> <span class="st">''</span>)</span>
|
||
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> email <span class="op">=</span> <span class="fu">computed</span>(() <span class="kw">=></span> userInfo<span class="op">.</span><span class="at">value</span><span class="op">?.</span><span class="at">email</span> <span class="op">??</span> <span class="st">''</span>)</span>
|
||
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// 获取用户信息</span></span>
|
||
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> getUserInfo <span class="op">=</span> <span class="kw">async</span> () <span class="kw">=></span> {</span>
|
||
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> res <span class="op">=</span> <span class="cf">await</span> UserApi<span class="op">.</span><span class="fu">getUserProfile</span>()</span>
|
||
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a> userInfo<span class="op">.</span><span class="at">value</span> <span class="op">=</span> res</span>
|
||
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a> permissions<span class="op">.</span><span class="at">value</span> <span class="op">=</span> res<span class="op">.</span><span class="at">permissions</span></span>
|
||
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a> roles<span class="op">.</span><span class="at">value</span> <span class="op">=</span> res<span class="op">.</span><span class="at">roles</span></span>
|
||
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a> <span class="co">// 用户登出</span></span>
|
||
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> logout <span class="op">=</span> <span class="kw">async</span> () <span class="kw">=></span> {</span>
|
||
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">try</span> {</span>
|
||
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">await</span> UserApi<span class="op">.</span><span class="fu">logout</span>()</span>
|
||
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a> } <span class="cf">finally</span> {</span>
|
||
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">await</span> <span class="fu">resetToken</span>()</span>
|
||
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a> <span class="co">// 重置令牌</span></span>
|
||
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> resetToken <span class="op">=</span> <span class="kw">async</span> () <span class="kw">=></span> {</span>
|
||
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a> userInfo<span class="op">.</span><span class="at">value</span> <span class="op">=</span> <span class="kw">undefined</span></span>
|
||
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a> permissions<span class="op">.</span><span class="at">value</span> <span class="op">=</span> []</span>
|
||
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a> roles<span class="op">.</span><span class="at">value</span> <span class="op">=</span> []</span>
|
||
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a> <span class="fu">removeToken</span>()</span>
|
||
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-40"><a href="#cb10-40" aria-hidden="true" tabindex="-1"></a> <span class="co">// 检查权限</span></span>
|
||
<span id="cb10-41"><a href="#cb10-41" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> hasPermission <span class="op">=</span> (permission<span class="op">:</span> <span class="dt">string</span>) <span class="kw">=></span> {</span>
|
||
<span id="cb10-42"><a href="#cb10-42" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> permissions<span class="op">.</span><span class="at">value</span><span class="op">.</span><span class="fu">includes</span>(permission)</span>
|
||
<span id="cb10-43"><a href="#cb10-43" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-44"><a href="#cb10-44" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-45"><a href="#cb10-45" aria-hidden="true" tabindex="-1"></a> <span class="co">// 检查角色</span></span>
|
||
<span id="cb10-46"><a href="#cb10-46" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> hasRole <span class="op">=</span> (role<span class="op">:</span> <span class="dt">string</span>) <span class="kw">=></span> {</span>
|
||
<span id="cb10-47"><a href="#cb10-47" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> roles<span class="op">.</span><span class="at">value</span><span class="op">.</span><span class="fu">includes</span>(role)</span>
|
||
<span id="cb10-48"><a href="#cb10-48" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-49"><a href="#cb10-49" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb10-50"><a href="#cb10-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> {</span>
|
||
<span id="cb10-51"><a href="#cb10-51" aria-hidden="true" tabindex="-1"></a> userInfo<span class="op">,</span></span>
|
||
<span id="cb10-52"><a href="#cb10-52" aria-hidden="true" tabindex="-1"></a> permissions<span class="op">,</span></span>
|
||
<span id="cb10-53"><a href="#cb10-53" aria-hidden="true" tabindex="-1"></a> roles<span class="op">,</span></span>
|
||
<span id="cb10-54"><a href="#cb10-54" aria-hidden="true" tabindex="-1"></a> nickname<span class="op">,</span></span>
|
||
<span id="cb10-55"><a href="#cb10-55" aria-hidden="true" tabindex="-1"></a> avatar<span class="op">,</span></span>
|
||
<span id="cb10-56"><a href="#cb10-56" aria-hidden="true" tabindex="-1"></a> email<span class="op">,</span></span>
|
||
<span id="cb10-57"><a href="#cb10-57" aria-hidden="true" tabindex="-1"></a> getUserInfo<span class="op">,</span></span>
|
||
<span id="cb10-58"><a href="#cb10-58" aria-hidden="true" tabindex="-1"></a> logout<span class="op">,</span></span>
|
||
<span id="cb10-59"><a href="#cb10-59" aria-hidden="true" tabindex="-1"></a> resetToken<span class="op">,</span></span>
|
||
<span id="cb10-60"><a href="#cb10-60" aria-hidden="true" tabindex="-1"></a> hasPermission<span class="op">,</span></span>
|
||
<span id="cb10-61"><a href="#cb10-61" aria-hidden="true" tabindex="-1"></a> hasRole</span>
|
||
<span id="cb10-62"><a href="#cb10-62" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb10-63"><a href="#cb10-63" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
|
||
<p><strong>src/utils/request.ts HTTP请求封装:</strong></p>
|
||
<div class="sourceCode" id="cb11"><pre
|
||
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> axios<span class="op">,</span> { AxiosResponse<span class="op">,</span> InternalAxiosRequestConfig } <span class="im">from</span> <span class="st">'axios'</span></span>
|
||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { ElMessage<span class="op">,</span> ElMessageBox } <span class="im">from</span> <span class="st">'element-plus'</span></span>
|
||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { getAccessToken<span class="op">,</span> getRefreshToken<span class="op">,</span> removeToken } <span class="im">from</span> <span class="st">'@/utils/auth'</span></span>
|
||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { useUserStore } <span class="im">from</span> <span class="st">'@/stores/user'</span></span>
|
||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">// 创建 axios 实例</span></span>
|
||
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> service <span class="op">=</span> axios<span class="op">.</span><span class="fu">create</span>({</span>
|
||
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> baseURL<span class="op">:</span> import<span class="op">.</span><span class="at">meta</span><span class="op">.</span><span class="at">env</span><span class="op">.</span><span class="at">VITE_BASE_URL</span><span class="op">,</span></span>
|
||
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> timeout<span class="op">:</span> <span class="dv">50000</span><span class="op">,</span></span>
|
||
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> withCredentials<span class="op">:</span> <span class="kw">false</span></span>
|
||
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>})</span>
|
||
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="co">// 请求拦截器</span></span>
|
||
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>service<span class="op">.</span><span class="at">interceptors</span><span class="op">.</span><span class="at">request</span><span class="op">.</span><span class="fu">use</span>(</span>
|
||
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a> (config<span class="op">:</span> InternalAxiosRequestConfig) <span class="kw">=></span> {</span>
|
||
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// 添加 token</span></span>
|
||
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> accessToken <span class="op">=</span> <span class="fu">getAccessToken</span>()</span>
|
||
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (accessToken <span class="op">&&</span> config<span class="op">.</span><span class="at">headers</span>) {</span>
|
||
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a> config<span class="op">.</span><span class="at">headers</span><span class="op">.</span><span class="at">Authorization</span> <span class="op">=</span> <span class="vs">`Bearer </span><span class="sc">${</span>accessToken<span class="sc">}</span><span class="vs">`</span></span>
|
||
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a> <span class="co">// 添加租户ID</span></span>
|
||
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> tenantId <span class="op">=</span> localStorage<span class="op">.</span><span class="fu">getItem</span>(<span class="st">'tenantId'</span>)</span>
|
||
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (tenantId <span class="op">&&</span> config<span class="op">.</span><span class="at">headers</span>) {</span>
|
||
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a> config<span class="op">.</span><span class="at">headers</span>[<span class="st">'tenant-id'</span>] <span class="op">=</span> tenantId</span>
|
||
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> config</span>
|
||
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a> error <span class="kw">=></span> {</span>
|
||
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(error)</span>
|
||
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">Promise</span><span class="op">.</span><span class="fu">reject</span>(error)</span>
|
||
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a>)</span>
|
||
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a><span class="co">// 响应拦截器</span></span>
|
||
<span id="cb11-37"><a href="#cb11-37" aria-hidden="true" tabindex="-1"></a>service<span class="op">.</span><span class="at">interceptors</span><span class="op">.</span><span class="at">response</span><span class="op">.</span><span class="fu">use</span>(</span>
|
||
<span id="cb11-38"><a href="#cb11-38" aria-hidden="true" tabindex="-1"></a> (response<span class="op">:</span> AxiosResponse) <span class="kw">=></span> {</span>
|
||
<span id="cb11-39"><a href="#cb11-39" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> { data } <span class="op">=</span> response</span>
|
||
<span id="cb11-40"><a href="#cb11-40" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> { code<span class="op">,</span> msg } <span class="op">=</span> data</span>
|
||
<span id="cb11-41"><a href="#cb11-41" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb11-42"><a href="#cb11-42" aria-hidden="true" tabindex="-1"></a> <span class="co">// 业务请求成功</span></span>
|
||
<span id="cb11-43"><a href="#cb11-43" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (code <span class="op">===</span> <span class="dv">0</span>) {</span>
|
||
<span id="cb11-44"><a href="#cb11-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> data</span>
|
||
<span id="cb11-45"><a href="#cb11-45" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-46"><a href="#cb11-46" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb11-47"><a href="#cb11-47" aria-hidden="true" tabindex="-1"></a> <span class="co">// token 过期,尝试刷新</span></span>
|
||
<span id="cb11-48"><a href="#cb11-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (code <span class="op">===</span> <span class="dv">401</span>) {</span>
|
||
<span id="cb11-49"><a href="#cb11-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="fu">handleTokenExpired</span>()</span>
|
||
<span id="cb11-50"><a href="#cb11-50" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-51"><a href="#cb11-51" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span id="cb11-52"><a href="#cb11-52" aria-hidden="true" tabindex="-1"></a> <span class="co">// 业务请求失败</span></span>
|
||
<span id="cb11-53"><a href="#cb11-53" aria-hidden="true" tabindex="-1"></a> ElMessage<span class="op">.</span><span class="fu">error</span>(msg <span class="op">||</span> <span class="st">'系统未知错误,请反馈给管理员'</span>)</span>
|
||
<span id="cb11-54"><a href="#cb11-54" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">Promise</span><span class="op">.</span><span class="fu">reject</span>(<span class="kw">new</span> <span class="bu">Error</span>(msg <span class="op">||</span> <span class="st">'Error'</span>))</span>
|
||
<span id="cb11-55"><a href="#cb11-55" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb11-56"><a href="#cb11-56" aria-hidden="true" tabindex="-1"></a> error <span class="kw">=></span> {</span>
|
||
<span id="cb11-57"><a href="#cb11-57" aria-hidden="true" tabindex="-1"></a> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">'err'</span> <span class="op">+</span> error)</span>
|
||
<span id="cb11-58"><a href="#cb11-58" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> { message } <span class="op">=</span> error</span>
|
||
<span id="cb11-59"><a href="#cb11-59" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (message <span class="op">===</span> <span class="st">'Network Error'</span>) {</span>
|
||
<span id="cb11-60"><a href="#cb11-60" aria-hidden="true" tabindex="-1"></a> message <span class="op">=</span> <span class="st">'后端接口连接异常'</span></span>
|
||
<span id="cb11-61"><a href="#cb11-61" aria-hidden="true" tabindex="-1"></a> } <span class="cf">else</span> <span class="cf">if</span> (message<span class="op">.</span><span class="fu">includes</span>(<span class="st">'timeout'</span>)) {</span>
|
||
<span id="cb11-62"><a href="#cb11-62" aria-hidden="true" tabindex="-1"></a> message <span class="op">=</span> <span class="st">'系统接口请求超时'</span></span>
|
||
<span id="cb11-63"><a href="#cb11-63" aria-hidden="true" tabindex="-1"></a> } <span class="cf">else</span> <span class="cf">if</span> (message<span class="op">.</span><span class="fu">includes</span>(<span class="st">'Request failed with status code'</span>)) {</span>
|
||
<span id="cb11-64"><a href="#cb11-64" aria-hidden="true" tabindex="-1"></a> message <span class="op">=</span> <span class="st">'系统接口'</span> <span class="op">+</span> message<span class="op">.</span><span class="fu">substr</span>(message<span class="op">.</span><span class="at">length</span> <span class="op">-</span> <span class="dv">3</span>) <span class="op">+</span> <span class="st">'异常'</span></span>
|
||
<span id="cb11-65"><a href="#cb11-65" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-66"><a href="#cb11-66" aria-hidden="true" tabindex="-1"></a> ElMessage<span class="op">.</span><span class="fu">error</span>(message)</span>
|
||
<span id="cb11-67"><a href="#cb11-67" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">Promise</span><span class="op">.</span><span class="fu">reject</span>(error)</span>
|
||
<span id="cb11-68"><a href="#cb11-68" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb11-69"><a href="#cb11-69" aria-hidden="true" tabindex="-1"></a>)</span>
|
||
<span id="cb11-70"><a href="#cb11-70" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb11-71"><a href="#cb11-71" aria-hidden="true" tabindex="-1"></a><span class="co">// 处理 token 过期</span></span>
|
||
<span id="cb11-72"><a href="#cb11-72" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> handleTokenExpired <span class="op">=</span> <span class="kw">async</span> () <span class="kw">=></span> {</span>
|
||
<span id="cb11-73"><a href="#cb11-73" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> userStore <span class="op">=</span> <span class="fu">useUserStore</span>()</span>
|
||
<span id="cb11-74"><a href="#cb11-74" aria-hidden="true" tabindex="-1"></a> ElMessageBox<span class="op">.</span><span class="fu">alert</span>(<span class="st">'登录状态已过期,您可以继续留在该页面,或者重新登录'</span><span class="op">,</span> <span class="st">'系统提示'</span><span class="op">,</span> {</span>
|
||
<span id="cb11-75"><a href="#cb11-75" aria-hidden="true" tabindex="-1"></a> confirmButtonText<span class="op">:</span> <span class="st">'重新登录'</span><span class="op">,</span></span>
|
||
<span id="cb11-76"><a href="#cb11-76" aria-hidden="true" tabindex="-1"></a> type<span class="op">:</span> <span class="st">'warning'</span></span>
|
||
<span id="cb11-77"><a href="#cb11-77" aria-hidden="true" tabindex="-1"></a> })<span class="op">.</span><span class="fu">then</span>(() <span class="kw">=></span> {</span>
|
||
<span id="cb11-78"><a href="#cb11-78" aria-hidden="true" tabindex="-1"></a> userStore<span class="op">.</span><span class="fu">resetToken</span>()<span class="op">.</span><span class="fu">then</span>(() <span class="kw">=></span> {</span>
|
||
<span id="cb11-79"><a href="#cb11-79" aria-hidden="true" tabindex="-1"></a> location<span class="op">.</span><span class="fu">reload</span>()</span>
|
||
<span id="cb11-80"><a href="#cb11-80" aria-hidden="true" tabindex="-1"></a> })</span>
|
||
<span id="cb11-81"><a href="#cb11-81" aria-hidden="true" tabindex="-1"></a> })</span>
|
||
<span id="cb11-82"><a href="#cb11-82" aria-hidden="true" tabindex="-1"></a>}</span>
|
||
<span id="cb11-83"><a href="#cb11-83" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb11-84"><a href="#cb11-84" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> service</span></code></pre></div>
|
||
<h3 data-number="1.4.5" id="前端技术架构详细设计"><span
|
||
class="header-section-number">1.4.5</span> 2.5 前端技术架构详细设计</h3>
|
||
<h4 data-number="1.4.5.1" id="web管理端架构-yudao-ui-admin-vue3"><span
|
||
class="header-section-number">1.4.5.1</span> 2.5.1 Web管理端架构
|
||
(yudao-ui-admin-vue3)</h4>
|
||
<p><strong>技术栈组成:</strong></p>
|
||
<p><strong>图表 5</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_5.png"
|
||
alt="图表 5" />
|
||
<figcaption aria-hidden="true">图表 5</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "开发框架"
|
||
A1[Vue 3.2.47 Composition API]
|
||
A2[TypeScript 4.9.4]
|
||
A3[Vite 4.0.0 构建工具]
|
||
end
|
||
|
||
subgraph "UI组件库"
|
||
B1[Element Plus 2.3.14]
|
||
B2[Element Plus Icons]
|
||
B3[自定义组件库]
|
||
end
|
||
|
||
subgraph "状态管理"
|
||
C1[Pinia 2.0.28]
|
||
C2[持久化插件]
|
||
C3[全局状态管理]
|
||
end
|
||
|
||
subgraph "路由系统"
|
||
D1[Vue Router 4.1.6]
|
||
D2[路由守卫]
|
||
D3[动态路由]
|
||
D4[权限控制]
|
||
end
|
||
|
||
subgraph "HTTP通信"
|
||
E1[Axios 1.2.2]
|
||
E2[请求拦截器]
|
||
E3[响应拦截器]
|
||
E4[错误处理]
|
||
end
|
||
|
||
subgraph "工具库"
|
||
F1[Lodash 工具函数]
|
||
F2[dayjs 时间处理]
|
||
F3[nprogress 进度条]
|
||
F4[js-cookie Cookie管理]
|
||
F5[crypto-js 加密解密]
|
||
end
|
||
|
||
A1 --> B1
|
||
A1 --> C1
|
||
A1 --> D1
|
||
A1 --> E1
|
||
B1 --> B3
|
||
C1 --> C2
|
||
D1 --> D2
|
||
E1 --> E2
|
||
</code></pre>
|
||
</details>
|
||
<p><strong>项目结构设计:</strong></p>
|
||
<pre class="text"><code>yudao-ui-admin-vue3/
|
||
├── public/ # 静态资源
|
||
├── src/
|
||
│ ├── api/ # API接口定义
|
||
│ │ └── water/ # 水务业务API
|
||
│ │ ├── customer/ # 客户管理API
|
||
│ │ ├── meter/ # 抄表管理API
|
||
│ │ ├── billing/ # 收费管理API
|
||
│ │ └── workflow/ # 工单管理API
|
||
│ ├── assets/ # 静态资源
|
||
│ ├── components/ # 全局组件
|
||
│ │ ├── Dialog/ # 弹窗组件
|
||
│ │ ├── Form/ # 表单组件
|
||
│ │ ├── Table/ # 表格组件
|
||
│ │ └── Upload/ # 上传组件
|
||
│ ├── layout/ # 布局组件
|
||
│ ├── router/ # 路由配置
|
||
│ ├── stores/ # Pinia状态管理
|
||
│ ├── styles/ # 全局样式
|
||
│ ├── utils/ # 工具函数
|
||
│ ├── views/ # 页面组件
|
||
│ │ └── water/ # 水务业务页面
|
||
│ │ ├── customer/ # 客户管理
|
||
│ │ ├── meter/ # 抄表管理
|
||
│ │ ├── billing/ # 收费管理
|
||
│ │ └── workflow/ # 工单管理
|
||
│ └── App.vue
|
||
├── types/ # TypeScript类型定义
|
||
├── vite.config.ts # Vite配置
|
||
├── tsconfig.json # TypeScript配置
|
||
└── package.json # 项目依赖</code></pre>
|
||
<p><strong>核心配置示例:</strong></p>
|
||
<div class="sourceCode" id="cb14"><pre
|
||
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// vite.config.ts - Vite构建配置</span></span>
|
||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { defineConfig } <span class="im">from</span> <span class="st">'vite'</span></span>
|
||
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> vue <span class="im">from</span> <span class="st">'@vitejs/plugin-vue'</span></span>
|
||
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { resolve } <span class="im">from</span> <span class="st">'path'</span></span>
|
||
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="im">default</span> <span class="fu">defineConfig</span>({</span>
|
||
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> plugins<span class="op">:</span> [<span class="fu">vue</span>()]<span class="op">,</span></span>
|
||
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> resolve<span class="op">:</span> {</span>
|
||
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> alias<span class="op">:</span> {</span>
|
||
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a> <span class="st">'@'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src'</span>)<span class="op">,</span></span>
|
||
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a> <span class="st">'@/api'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src/api'</span>)<span class="op">,</span></span>
|
||
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a> <span class="st">'@/components'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src/components'</span>)<span class="op">,</span></span>
|
||
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a> <span class="st">'@/utils'</span><span class="op">:</span> <span class="fu">resolve</span>(<span class="bu">__dirname</span><span class="op">,</span> <span class="st">'src/utils'</span>)</span>
|
||
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a> server<span class="op">:</span> {</span>
|
||
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a> port<span class="op">:</span> <span class="dv">80</span><span class="op">,</span></span>
|
||
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a> proxy<span class="op">:</span> {</span>
|
||
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a> <span class="st">'/admin-api'</span><span class="op">:</span> {</span>
|
||
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a> target<span class="op">:</span> <span class="st">'http://127.0.0.1:48080'</span><span class="op">,</span></span>
|
||
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a> changeOrigin<span class="op">:</span> <span class="kw">true</span><span class="op">,</span></span>
|
||
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a> rewrite<span class="op">:</span> (path) <span class="kw">=></span> path<span class="op">.</span><span class="fu">replace</span>(<span class="ss">/</span><span class="sc">^\/</span><span class="ss">admin-api/</span><span class="op">,</span> <span class="st">'/admin-api'</span>)</span>
|
||
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
|
||
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a> build<span class="op">:</span> {</span>
|
||
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a> outDir<span class="op">:</span> <span class="st">'dist'</span><span class="op">,</span></span>
|
||
<span id="cb14-28"><a href="#cb14-28" aria-hidden="true" tabindex="-1"></a> sourcemap<span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
|
||
<span id="cb14-29"><a href="#cb14-29" aria-hidden="true" tabindex="-1"></a> rollupOptions<span class="op">:</span> {</span>
|
||
<span id="cb14-30"><a href="#cb14-30" aria-hidden="true" tabindex="-1"></a> output<span class="op">:</span> {</span>
|
||
<span id="cb14-31"><a href="#cb14-31" aria-hidden="true" tabindex="-1"></a> chunkFileNames<span class="op">:</span> <span class="st">'js/[name]-[hash].js'</span><span class="op">,</span></span>
|
||
<span id="cb14-32"><a href="#cb14-32" aria-hidden="true" tabindex="-1"></a> entryFileNames<span class="op">:</span> <span class="st">'js/[name]-[hash].js'</span><span class="op">,</span></span>
|
||
<span id="cb14-33"><a href="#cb14-33" aria-hidden="true" tabindex="-1"></a> assetFileNames<span class="op">:</span> <span class="st">'[ext]/[name]-[hash].[ext]'</span></span>
|
||
<span id="cb14-34"><a href="#cb14-34" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-35"><a href="#cb14-35" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-36"><a href="#cb14-36" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb14-37"><a href="#cb14-37" aria-hidden="true" tabindex="-1"></a>})</span></code></pre></div>
|
||
<h4 data-number="1.4.5.2" id="移动端架构-uni-app"><span
|
||
class="header-section-number">1.4.5.2</span> 2.5.2 移动端架构
|
||
(uni-app)</h4>
|
||
<p><strong>技术栈组成:</strong></p>
|
||
<p><strong>图表 6</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_6.png"
|
||
alt="图表 6" />
|
||
<figcaption aria-hidden="true">图表 6</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "跨平台框架"
|
||
M1[uni-app 3.x]
|
||
M2[Vue 3 Composition API]
|
||
M3[TypeScript支持]
|
||
end
|
||
|
||
subgraph "UI组件库"
|
||
N1[uView UI 2.0]
|
||
N2[uni-ui组件]
|
||
N3[自定义水务组件]
|
||
end
|
||
|
||
subgraph "状态管理"
|
||
O1[Vuex 4.x]
|
||
O2[uni-app存储]
|
||
O3[缓存管理]
|
||
end
|
||
|
||
subgraph "设备能力"
|
||
P1[相机API<br/>水表拍照]
|
||
P2[NFC读取<br/>水表标签]
|
||
P3[GPS定位<br/>抄表轨迹]
|
||
P4[扫码API<br/>二维码扫描]
|
||
end
|
||
|
||
subgraph "网络通信"
|
||
Q1[uni.request<br/>HTTP请求]
|
||
Q2[WebSocket<br/>实时通信]
|
||
Q3[文件上传<br/>图片处理]
|
||
end
|
||
|
||
M1 --> N1
|
||
M1 --> O1
|
||
M1 --> P1
|
||
M1 --> Q1
|
||
N1 --> N3
|
||
P1 --> P2
|
||
Q1 --> Q2
|
||
</code></pre>
|
||
</details>
|
||
<p><strong>移动端项目结构:</strong></p>
|
||
<pre class="text"><code>water-mobile-app/
|
||
├── pages/ # 页面目录
|
||
│ ├── index/ # 首页
|
||
│ ├── meter/ # 抄表功能
|
||
│ │ ├── task/ # 抄表任务
|
||
│ │ ├── read/ # 抄表录入
|
||
│ │ └── history/ # 抄表历史
|
||
│ ├── workflow/ # 工单管理
|
||
│ └── personal/ # 个人中心
|
||
├── components/ # 组件目录
|
||
│ ├── meter-reader/ # 水表读数组件
|
||
│ ├── map-trace/ # 地图轨迹组件
|
||
│ └── camera-scan/ # 相机扫描组件
|
||
├── static/ # 静态资源
|
||
├── store/ # 状态管理
|
||
├── utils/ # 工具函数
|
||
├── api/ # 接口定义
|
||
├── manifest.json # 应用配置
|
||
└── pages.json # 页面配置</code></pre>
|
||
<h4 data-number="1.4.5.3" id="客户端小程序架构"><span
|
||
class="header-section-number">1.4.5.3</span> 2.5.3 客户端小程序架构</h4>
|
||
<p><strong>微信小程序技术栈:</strong> - 开发框架:微信小程序原生框架 -
|
||
UI组件:WeUI + 自定义组件 - 状态管理:小程序全局数据管理 -
|
||
支付集成:微信支付API - 地图服务:腾讯地图API</p>
|
||
<p><strong>支付宝小程序技术栈:</strong> -
|
||
开发框架:支付宝小程序原生框架<br />
|
||
- UI组件:mini-antui + 自定义组件 - 状态管理:小程序全局数据管理 -
|
||
支付集成:支付宝支付API - 地图服务:高德地图API</p>
|
||
<h4 data-number="1.4.5.4" id="前端工程化配置"><span
|
||
class="header-section-number">1.4.5.4</span> 2.5.4 前端工程化配置</h4>
|
||
<p><strong>代码规范:</strong></p>
|
||
<div class="sourceCode" id="cb17"><pre
|
||
class="sourceCode json"><code class="sourceCode json"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="er">//</span> <span class="er">.eslintrc.js</span> <span class="er">-</span> <span class="er">ESLint配置</span></span>
|
||
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
||
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"extends"</span><span class="fu">:</span> <span class="ot">[</span></span>
|
||
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"@vue/typescript/recommended"</span><span class="ot">,</span></span>
|
||
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"@vue/prettier"</span><span class="ot">,</span></span>
|
||
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"@vue/prettier/@typescript-eslint"</span></span>
|
||
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a> <span class="ot">]</span><span class="fu">,</span></span>
|
||
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">"rules"</span><span class="fu">:</span> <span class="fu">{</span></span>
|
||
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@typescript-eslint/no-explicit-any"</span><span class="fu">:</span> <span class="st">"warn"</span><span class="fu">,</span></span>
|
||
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">"@typescript-eslint/no-unused-vars"</span><span class="fu">:</span> <span class="st">"error"</span><span class="fu">,</span></span>
|
||
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">"vue/multi-word-component-names"</span><span class="fu">:</span> <span class="st">"off"</span></span>
|
||
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
|
||
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
||
<p><strong>构建优化:</strong> - Vite热更新:开发环境快速构建 -
|
||
代码分割:按路由和组件懒加载 - 资源压缩:Gzip压缩和图片优化 -
|
||
CDN加速:静态资源CDN分发 - 缓存策略:浏览器缓存和Service Worker</p>
|
||
<ul>
|
||
<li>移动端:
|
||
<ul>
|
||
<li>核心框架:uni-app(跨平台)</li>
|
||
<li>组件库:uview-ui</li>
|
||
<li>小程序支持:微信小程序、支付宝小程序等</li>
|
||
<li>移动端地图:高德地图SDK(用于抄表轨迹和导航)</li>
|
||
<li>设备接入:NFC、扫码、相机等硬件设备接口</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h3 data-number="1.4.6" id="技术特性"><span
|
||
class="header-section-number">1.4.6</span> 2.6 技术特性</h3>
|
||
<ul>
|
||
<li>单点登录:OAuth2 + JWT实现统一认证</li>
|
||
<li>数据交换:基于RESTful API的系统内部数据交换与共享</li>
|
||
<li>统一报表平台:集成JimuReport,支持自定义报表设计与生成</li>
|
||
<li>大屏设计:集成GoView,支持可视化大屏设计</li>
|
||
<li>安全保障:满足安全等保三级要求
|
||
<ul>
|
||
<li>密码加密:BCrypt加密算法</li>
|
||
<li>防XSS攻击:表单数据过滤</li>
|
||
<li>防SQL注入:参数化查询</li>
|
||
<li>防CSRF攻击:Token验证</li>
|
||
</ul></li>
|
||
<li>性能规格:支持200并发用户,50并发移动设备,系统响应时间不超过3秒</li>
|
||
<li>扩展容量:支持100万客户的业务量,满足企业3-5年的业务发展需求</li>
|
||
<li>支持功能:
|
||
<ul>
|
||
<li>支付管理:微信支付、支付宝支付等</li>
|
||
<li>短信服务:阿里云、腾讯云等多家短信服务商</li>
|
||
<li>AI能力:
|
||
<ul>
|
||
<li>智能抄表:基于图像识别的水表读数</li>
|
||
<li>异常分析:基于AI的用水异常分析</li>
|
||
</ul></li>
|
||
<li>API网关:支持API权限管理、限流熔断、白名单控制</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h2 data-number="1.5" id="三应用架构"><span
|
||
class="header-section-number">1.5</span> 三、应用架构</h2>
|
||
<h3 data-number="1.5.1" id="微服务应用架构图"><span
|
||
class="header-section-number">1.5.1</span> 3.1 微服务应用架构图</h3>
|
||
<p><strong>图表 7</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_7.png"
|
||
alt="图表 7" />
|
||
<figcaption aria-hidden="true">图表 7</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "网关层"
|
||
GW[API网关<br/>Spring Cloud Gateway]
|
||
AUTH[认证服务<br/>OAuth2 + JWT]
|
||
end
|
||
|
||
subgraph "基础服务层"
|
||
subgraph "系统服务"
|
||
SYS[系统管理服务<br/>用户/角色/权限]
|
||
TENANT[租户管理服务<br/>多租户隔离]
|
||
FILE[文件管理服务<br/>附件存储]
|
||
MSG[消息服务<br/>短信/邮件/推送]
|
||
end
|
||
|
||
subgraph "工作流服务"
|
||
WF[工作流引擎<br/>Flowable]
|
||
TASK[任务调度服务<br/>Quartz]
|
||
end
|
||
end
|
||
|
||
subgraph "业务服务层"
|
||
subgraph "客户域服务"
|
||
CUST[客户管理服务<br/>Customer Service]
|
||
METER[水表管理服务<br/>Meter Service]
|
||
ADDR[地址管理服务<br/>Address Service]
|
||
end
|
||
|
||
subgraph "营收域服务"
|
||
READ[抄表服务<br/>Reading Service]
|
||
BILL[账单服务<br/>Billing Service]
|
||
PAY[收费服务<br/>Payment Service]
|
||
ACC[账务服务<br/>Accounting Service]
|
||
end
|
||
|
||
subgraph "运营域服务"
|
||
ORDER[工单服务<br/>Workflow Service]
|
||
RPT[报表服务<br/>Report Service]
|
||
STATS[统计分析服务<br/>Statistics Service]
|
||
end
|
||
|
||
subgraph "接口域服务"
|
||
BANK[银行接口服务<br/>Bank Service]
|
||
PAY_GW[支付网关服务<br/>Payment Gateway]
|
||
IOT[物联网服务<br/>IoT Service]
|
||
SMS[短信服务<br/>SMS Service]
|
||
end
|
||
end
|
||
|
||
subgraph "数据层"
|
||
subgraph "业务数据库"
|
||
DB_CUST[(客户库<br/>Customer DB)]
|
||
DB_BILL[(营收库<br/>Billing DB)]
|
||
DB_RPT[(报表库<br/>Report DB)]
|
||
end
|
||
|
||
subgraph "缓存与存储"
|
||
REDIS[(Redis集群<br/>缓存/会话)]
|
||
ES[(ElasticSearch<br/>搜索引擎)]
|
||
FILE_STORE[文件存储<br/>MinIO/OSS]
|
||
end
|
||
end
|
||
|
||
%% 网关层连接
|
||
GW --> AUTH
|
||
GW --> SYS
|
||
GW --> CUST
|
||
GW --> READ
|
||
GW --> ORDER
|
||
|
||
%% 服务间调用
|
||
CUST --> METER
|
||
CUST --> ADDR
|
||
READ --> METER
|
||
READ --> CUST
|
||
BILL --> READ
|
||
BILL --> CUST
|
||
PAY --> BILL
|
||
ACC --> PAY
|
||
|
||
ORDER --> WF
|
||
ORDER --> TASK
|
||
RPT --> STATS
|
||
|
||
%% 外部接口调用
|
||
PAY --> BANK
|
||
PAY --> PAY_GW
|
||
READ --> IOT
|
||
ORDER --> SMS
|
||
|
||
%% 数据层连接
|
||
CUST --> DB_CUST
|
||
METER --> DB_CUST
|
||
BILL --> DB_BILL
|
||
PAY --> DB_BILL
|
||
RPT --> DB_RPT
|
||
|
||
SYS --> REDIS
|
||
AUTH --> REDIS
|
||
CUST --> REDIS
|
||
BILL --> ES
|
||
FILE --> FILE_STORE
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.5.2" id="服务治理架构"><span
|
||
class="header-section-number">1.5.2</span> 3.2 服务治理架构</h3>
|
||
<p><strong>图表 8</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_8.png"
|
||
alt="图表 8" />
|
||
<figcaption aria-hidden="true">图表 8</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "服务发现与注册"
|
||
NACOS[Nacos注册中心<br/>服务注册/发现/配置]
|
||
end
|
||
|
||
subgraph "服务网格层"
|
||
subgraph "负载均衡"
|
||
LB[Ribbon负载均衡<br/>客户端负载均衡]
|
||
FEIGN[OpenFeign<br/>服务间调用]
|
||
end
|
||
|
||
subgraph "容错保护"
|
||
CB[Sentinel熔断器<br/>流量控制/熔断降级]
|
||
RETRY[重试机制<br/>失败重试]
|
||
end
|
||
|
||
subgraph "链路追踪"
|
||
TRACE[SkyWalking<br/>分布式链路追踪]
|
||
METRIC[Micrometer<br/>指标收集]
|
||
end
|
||
end
|
||
|
||
subgraph "配置管理"
|
||
CONFIG[Nacos Config<br/>配置中心]
|
||
SECRET[配置加密<br/>敏感信息保护]
|
||
end
|
||
|
||
subgraph "监控告警"
|
||
MONITOR[Spring Boot Admin<br/>应用监控]
|
||
ALERT[告警系统<br/>异常通知]
|
||
LOG[ELK日志系统<br/>日志聚合分析]
|
||
end
|
||
|
||
NACOS --> LB
|
||
NACOS --> FEIGN
|
||
LB --> CB
|
||
FEIGN --> TRACE
|
||
CB --> RETRY
|
||
|
||
CONFIG --> SECRET
|
||
MONITOR --> ALERT
|
||
TRACE --> LOG
|
||
</code></pre>
|
||
</details>
|
||
<p>系统应用架构基于业务域划分,主要包括以下核心应用模块:</p>
|
||
<h3 data-number="1.5.3" id="统一平台"><span
|
||
class="header-section-number">1.5.3</span> 3.3 统一平台</h3>
|
||
<ul>
|
||
<li>单点登录:统一认证入口,支持多种登录方式</li>
|
||
<li>系统管理:组织机构、员工管理、角色权限管理、菜单配置等</li>
|
||
<li>流程节点提醒:工作流节点到期和状态变更提醒</li>
|
||
</ul>
|
||
<h3 data-number="1.5.4" id="营收系统"><span
|
||
class="header-section-number">1.5.4</span> 3.4 营收系统</h3>
|
||
<ul>
|
||
<li>系统管理:水价管理、用户档案管理、更名过户管理等</li>
|
||
<li>抄表开账:册本管理、抄表录入、复核开账等</li>
|
||
<li>收费管理:柜台收费、特殊开账、柜台结账、批量缴费等</li>
|
||
<li>账务处理:预存调整、未销调整、已销调整、分账调整等</li>
|
||
<li>发票管理:发票查询、发票开具、电子发票等</li>
|
||
<li>代收业务:实时收费、银行代扣、银行托收等</li>
|
||
<li>环卫系统:计费核定、计费退补、计费减免等</li>
|
||
<li>业务工单:业务清单、上报清单、稽查工单、移表工单等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.5" id="客户服务"><span
|
||
class="header-section-number">1.5.5</span> 3.5 客户服务</h3>
|
||
<ul>
|
||
<li>微信、支付宝服务窗:账户绑定、用水查询、在线缴费等</li>
|
||
<li>历史账单:账单查询、用水分析、账单推送等</li>
|
||
<li>电子发票:发票申请、发票查询、发票下载等</li>
|
||
<li>营业网点:网点查询、网点导航、业务指南等</li>
|
||
<li>账户流水:流水查询、明细下载、交易统计等</li>
|
||
<li>微网厅:用户注册、信息查询、业务办理等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.6" id="表务系统"><span
|
||
class="header-section-number">1.5.6</span> 3.6 表务系统</h3>
|
||
<ul>
|
||
<li>表务工单:换表工单、移表工单、拆表工单、复装工单等</li>
|
||
<li>表务仓库:新表入库、水表检定、水表领用、水表出库等</li>
|
||
<li>水表参数与基础信息:水表厂家管理、水表型号管理等</li>
|
||
<li>物联网对接与数据同步:厂家设备信息管理、远程抄表数据同步等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.7" id="报装管理"><span
|
||
class="header-section-number">1.5.7</span> 3.7 报装管理</h3>
|
||
<ul>
|
||
<li>报装流程:报装申请、方案设计、合同签订、施工管理等</li>
|
||
<li>一户一表管理:改造计划、改造实施、用户转换等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.8" id="统计分析"><span
|
||
class="header-section-number">1.5.8</span> 3.8 统计分析</h3>
|
||
<ul>
|
||
<li>报表查询:标准报表、自定义报表、报表导出打印等</li>
|
||
<li>欠费查询:欠费情况统计、欠费用户明细、欠费分析等</li>
|
||
<li>缴费记录:缴费情况统计、缴费明细查询、缴费趋势分析等</li>
|
||
<li>用水分析:用水量统计、用水趋势分析、异常用水分析等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.9" id="工程管理"><span
|
||
class="header-section-number">1.5.9</span> 3.9 工程管理</h3>
|
||
<ul>
|
||
<li>工程申请:工程立项、材料提交、前期勘察等</li>
|
||
<li>工程施工:施工计划、施工派工、施工记录等</li>
|
||
<li>工程验收:验收申请、验收检查、验收记录等</li>
|
||
<li>工程查询:工程进度查询、工程资料查询、工程统计等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.10" id="抄表app"><span
|
||
class="header-section-number">1.5.10</span> 3.10 抄表APP</h3>
|
||
<ul>
|
||
<li>首页功能:首页展示、个人信息、快捷查询等</li>
|
||
<li>抄表功能:抄表任务、NFC抄表、扫码抄表、AI录入等</li>
|
||
<li>工单管理:问题上报、问题回填、代办工单、稽查工单等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.11" id="接口服务"><span
|
||
class="header-section-number">1.5.11</span> 3.11 接口服务</h3>
|
||
<ul>
|
||
<li>API市场:API展示、API使用说明、API测试等</li>
|
||
<li>API管理:API申请、API调度看板、接口服务配置管理等</li>
|
||
<li>接口权限管理:授权管理、白名单管理、安全策略等</li>
|
||
<li>系统对外接口:查询接口、业务处理接口、状态同步接口等</li>
|
||
</ul>
|
||
<h3 data-number="1.5.12" id="系统配置"><span
|
||
class="header-section-number">1.5.12</span> 3.12 系统配置</h3>
|
||
<ul>
|
||
<li>水表参数:水表厂家、水表型号、水表量程等</li>
|
||
<li>地址参数:行政区划、地址编码、地址库等</li>
|
||
<li>价格体系:用水性质、水价标准、阶梯水价等</li>
|
||
<li>基本配置:系统参数、业务规则、打印模板等</li>
|
||
<li>催缴管理:催缴计划、催缴任务、催缴执行等</li>
|
||
<li>用户权限:菜单权限、功能权限、数据权限等</li>
|
||
<li>定时任务:任务配置、任务监控、任务日志等</li>
|
||
</ul>
|
||
<h2 data-number="1.6" id="四数据架构"><span
|
||
class="header-section-number">1.6</span> 四、数据架构</h2>
|
||
<p>系统数据架构基于客户关系数据库为核心和基础,实现客户全生命周期管理。</p>
|
||
<h3 data-number="1.6.1" id="数据分层"><span
|
||
class="header-section-number">1.6.1</span> 4.1 数据分层</h3>
|
||
<ul>
|
||
<li>数据采集层:负责从各业务系统和物联网设备采集原始数据</li>
|
||
<li>数据存储层:统一数据存储,实现分布式数据管理</li>
|
||
<li>数据服务层:提供数据服务接口</li>
|
||
<li>数据展现层:提供数据分析和可视化功能</li>
|
||
</ul>
|
||
<h3 data-number="1.6.2" id="opengauss数据库架构"><span
|
||
class="header-section-number">1.6.2</span> 4.2 OpenGauss数据库架构</h3>
|
||
<h4 data-number="1.6.2.1" id="主从高可用架构"><span
|
||
class="header-section-number">1.6.2.1</span> 4.2.1 主从高可用架构</h4>
|
||
<p><strong>图表 9</strong></p>
|
||
<figure>
|
||
<img src="temp_mermaid_water_biz_system_architecture_6403/diagram_9.png"
|
||
alt="图表 9" />
|
||
<figcaption aria-hidden="true">图表 9</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "OpenGauss高可用集群"
|
||
MASTER[("OpenGauss主库<br/>Primary Node<br/>读写操作")]
|
||
STANDBY[("OpenGauss备库<br/>Standby Node<br/>只读操作")]
|
||
CASCADE[("OpenGauss级联备库<br/>Cascade Standby<br/>负载分担")]
|
||
end
|
||
|
||
subgraph "应用层"
|
||
APP1[应用服务器1]
|
||
APP2[应用服务器2]
|
||
APP3[应用服务器3]
|
||
end
|
||
|
||
subgraph "连接池"
|
||
POOL[连接池<br/>HikariCP<br/>Druid]
|
||
end
|
||
|
||
subgraph "监控管理"
|
||
MON[OpenGauss Monitor<br/>性能监控]
|
||
BACKUP[定时备份<br/>gs_backup]
|
||
end
|
||
|
||
APP1 --> POOL
|
||
APP2 --> POOL
|
||
APP3 --> POOL
|
||
POOL --> MASTER
|
||
POOL --> STANDBY
|
||
POOL --> CASCADE
|
||
|
||
MASTER -.->|流复制| STANDBY
|
||
STANDBY -.->|级联复制| CASCADE
|
||
|
||
MON --> MASTER
|
||
MON --> STANDBY
|
||
BACKUP --> MASTER
|
||
</code></pre>
|
||
</details>
|
||
<h4 data-number="1.6.2.2" id="分片存储架构"><span
|
||
class="header-section-number">1.6.2.2</span> 4.2.2 分片存储架构</h4>
|
||
<p><strong>图表 10</strong></p>
|
||
<figure>
|
||
<img
|
||
src="temp_mermaid_water_biz_system_architecture_6403/diagram_10.png"
|
||
alt="图表 10" />
|
||
<figcaption aria-hidden="true">图表 10</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "OpenGauss分布式架构"
|
||
subgraph "协调节点"
|
||
CN1[协调节点1<br/>Coordinator Node]
|
||
CN2[协调节点2<br/>Coordinator Node]
|
||
end
|
||
|
||
subgraph "数据节点组1"
|
||
DN1_1[数据节点1-主<br/>Datanode Primary]
|
||
DN1_2[数据节点1-备<br/>Datanode Standby]
|
||
end
|
||
|
||
subgraph "数据节点组2"
|
||
DN2_1[数据节点2-主<br/>Datanode Primary]
|
||
DN2_2[数据节点2-备<br/>Datanode Standby]
|
||
end
|
||
|
||
subgraph "GTM节点"
|
||
GTM[全局事务管理器<br/>GTM Master]
|
||
GTM_S[GTM备节点<br/>GTM Standby]
|
||
end
|
||
end
|
||
|
||
CN1 --> DN1_1
|
||
CN1 --> DN2_1
|
||
CN2 --> DN1_1
|
||
CN2 --> DN2_1
|
||
|
||
DN1_1 -.->|主备同步| DN1_2
|
||
DN2_1 -.->|主备同步| DN2_2
|
||
|
||
GTM -.->|备份| GTM_S
|
||
CN1 --> GTM
|
||
CN2 --> GTM
|
||
</code></pre>
|
||
</details>
|
||
<h4 data-number="1.6.2.3" id="数据安全架构"><span
|
||
class="header-section-number">1.6.2.3</span> 4.2.3 数据安全架构</h4>
|
||
<p><strong>图表 11</strong></p>
|
||
<figure>
|
||
<img
|
||
src="temp_mermaid_water_biz_system_architecture_6403/diagram_11.png"
|
||
alt="图表 11" />
|
||
<figcaption aria-hidden="true">图表 11</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "安全防护层"
|
||
TDE[透明数据加密<br/>TDE]
|
||
RLS[行级安全<br/>Row Level Security]
|
||
MASK[动态数据脱敏<br/>Dynamic Data Masking]
|
||
AUDIT[三权分立审计<br/>Separated Audit]
|
||
end
|
||
|
||
subgraph "访问控制层"
|
||
RBAC[基于角色的访问控制<br/>RBAC]
|
||
LDAP[LDAP集成认证<br/>External Auth]
|
||
SSL[SSL/TLS加密传输<br/>Encrypted Transport]
|
||
end
|
||
|
||
subgraph "数据存储层"
|
||
ENCRYPT[存储层加密<br/>Storage Encryption]
|
||
COMPRESS[数据压缩<br/>Data Compression]
|
||
BACKUP_ENC[备份加密<br/>Backup Encryption]
|
||
end
|
||
|
||
TDE --> ENCRYPT
|
||
RLS --> RBAC
|
||
MASK --> ENCRYPT
|
||
AUDIT --> BACKUP_ENC
|
||
RBAC --> SSL
|
||
LDAP --> SSL
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.6.3" id="数据模型设计"><span
|
||
class="header-section-number">1.6.3</span> 4.3 数据模型设计</h3>
|
||
<ul>
|
||
<li><strong>客户信息模型</strong>:包含客户基础信息、表卡信息、账户信息、联系人信息等</li>
|
||
<li><strong>业务数据模型</strong>:抄表数据、收费数据、账务数据、发票数据等</li>
|
||
<li><strong>工单数据模型</strong>:表务工单、报装工单、业务工单等</li>
|
||
<li><strong>配置数据模型</strong>:系统参数、水表参数、价格体系等</li>
|
||
<li><strong>报表数据模型</strong>:统计数据、分析数据、预测数据等</li>
|
||
<li><strong>物联网数据模型</strong>:设备信息、状态信息、实时数据等</li>
|
||
</ul>
|
||
<h3 data-number="1.6.4" id="数据集成与共享"><span
|
||
class="header-section-number">1.6.4</span> 4.4 数据集成与共享</h3>
|
||
<ul>
|
||
<li><strong>统一数据标准</strong>:定义统一的数据标准和数据字典,符合OpenGauss规范</li>
|
||
<li><strong>数据集成机制</strong>:采用OpenGauss
|
||
XA事务实现系统间的数据一致性</li>
|
||
<li><strong>数据共享机制</strong>:基于OpenGauss外部数据包装器(FDW)实现跨库数据访问</li>
|
||
<li><strong>数据同步策略</strong>:支持实时流复制、定时数据同步、批量ETL处理等</li>
|
||
</ul>
|
||
<h3 data-number="1.6.5" id="opengauss特性应用"><span
|
||
class="header-section-number">1.6.5</span> 4.5 OpenGauss特性应用</h3>
|
||
<h4 data-number="1.6.5.1" id="性能优化特性"><span
|
||
class="header-section-number">1.6.5.1</span> 4.5.1 性能优化特性</h4>
|
||
<ul>
|
||
<li><strong>向量化执行引擎</strong>:批量数据处理,提升OLAP查询性能30-50%</li>
|
||
<li><strong>列存储引擎</strong>:统计报表类查询,压缩比高达10:1</li>
|
||
<li><strong>分区表技术</strong>:按月份分区存储抄表数据,支持分区裁剪</li>
|
||
<li><strong>并行查询</strong>:复杂统计查询自动并行执行</li>
|
||
<li><strong>智能优化器</strong>:自适应查询计划,持续性能优化</li>
|
||
</ul>
|
||
<h4 data-number="1.6.5.2" id="企业级特性"><span
|
||
class="header-section-number">1.6.5.2</span> 4.5.2 企业级特性</h4>
|
||
<ul>
|
||
<li><strong>在线扩容</strong>:支持不停机新增数据节点</li>
|
||
<li><strong>故障自愈</strong>:主备节点故障自动切换,RTO < 10秒</li>
|
||
<li><strong>读写分离</strong>:自动路由读请求到备节点,减轻主库压力</li>
|
||
<li><strong>负载均衡</strong>:连接池级别的智能负载均衡</li>
|
||
<li><strong>全量/增量备份</strong>:支持热备份,最小备份粒度到事务级</li>
|
||
</ul>
|
||
<h2 data-number="1.7" id="五安全架构"><span
|
||
class="header-section-number">1.7</span> 五、安全架构</h2>
|
||
<p>系统安全架构基于OpenGauss数据库的企业级安全特性,满足等保三级要求和国产化安全标准:</p>
|
||
<h3 data-number="1.7.1" id="网络安全"><span
|
||
class="header-section-number">1.7.1</span> 5.1 网络安全</h3>
|
||
<ul>
|
||
<li><strong>边界防护</strong>:防火墙、入侵检测/防御系统</li>
|
||
<li><strong>访问控制</strong>:基于角色的访问控制(RBAC)</li>
|
||
<li><strong>通信安全</strong>:SSL/TLS加密传输,支持国密算法</li>
|
||
<li><strong>安全监控</strong>:实时监控网络安全状态和异常访问</li>
|
||
</ul>
|
||
<h3 data-number="1.7.2" id="opengauss数据安全架构"><span
|
||
class="header-section-number">1.7.2</span> 5.2
|
||
OpenGauss数据安全架构</h3>
|
||
<h4 data-number="1.7.2.1" id="数据加密安全"><span
|
||
class="header-section-number">1.7.2.1</span> 5.2.1 数据加密安全</h4>
|
||
<p><strong>图表 12</strong></p>
|
||
<figure>
|
||
<img
|
||
src="temp_mermaid_water_biz_system_architecture_6403/diagram_12.png"
|
||
alt="图表 12" />
|
||
<figcaption aria-hidden="true">图表 12</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "加密层级"
|
||
L1[传输层加密<br/>SSL/TLS/国密SM]
|
||
L2[存储层加密<br/>TDE透明数据加密]
|
||
L3[字段级加密<br/>敏感字段加密]
|
||
L4[备份加密<br/>备份文件加密]
|
||
end
|
||
|
||
subgraph "密钥管理"
|
||
KMS[密钥管理系统<br/>Key Management]
|
||
HSM[硬件安全模块<br/>Hardware Security]
|
||
ROT[密钥轮换<br/>Key Rotation]
|
||
end
|
||
|
||
subgraph "国密算法"
|
||
SM2[SM2椭圆曲线<br/>非对称加密]
|
||
SM3[SM3哈希算法<br/>消息摘要]
|
||
SM4[SM4分组密码<br/>对称加密]
|
||
end
|
||
|
||
L1 --> KMS
|
||
L2 --> HSM
|
||
L3 --> ROT
|
||
L4 --> KMS
|
||
|
||
KMS --> SM2
|
||
HSM --> SM3
|
||
ROT --> SM4
|
||
</code></pre>
|
||
</details>
|
||
<h4 data-number="1.7.2.2" id="访问控制安全"><span
|
||
class="header-section-number">1.7.2.2</span> 5.2.2 访问控制安全</h4>
|
||
<p><strong>图表 13</strong></p>
|
||
<figure>
|
||
<img
|
||
src="temp_mermaid_water_biz_system_architecture_6403/diagram_13.png"
|
||
alt="图表 13" />
|
||
<figcaption aria-hidden="true">图表 13</figcaption>
|
||
</figure>
|
||
<details>
|
||
<summary>
|
||
查看图表源码
|
||
</summary>
|
||
<pre class="mermaid"><code>graph TB
|
||
subgraph "身份认证"
|
||
AUTH1[用户名密码认证]
|
||
AUTH2[LDAP集成认证]
|
||
AUTH3[Kerberos认证]
|
||
AUTH4[证书认证]
|
||
end
|
||
|
||
subgraph "权限控制"
|
||
RBAC[基于角色的权限控制<br/>Role-Based Access Control]
|
||
RLS[行级安全策略<br/>Row Level Security]
|
||
CLS[列级安全控制<br/>Column Level Security]
|
||
TENANT[多租户数据隔离<br/>Multi-Tenant Isolation]
|
||
end
|
||
|
||
subgraph "审计监控"
|
||
AUDIT[操作审计日志<br/>Audit Logging]
|
||
MONITOR[实时安全监控<br/>Security Monitoring]
|
||
ALERT[安全告警<br/>Security Alert]
|
||
REPORT[合规报告<br/>Compliance Report]
|
||
end
|
||
|
||
AUTH1 --> RBAC
|
||
AUTH2 --> RLS
|
||
AUTH3 --> CLS
|
||
AUTH4 --> TENANT
|
||
|
||
RBAC --> AUDIT
|
||
RLS --> MONITOR
|
||
CLS --> ALERT
|
||
TENANT --> REPORT
|
||
</code></pre>
|
||
</details>
|
||
<h3 data-number="1.7.3" id="数据安全特性"><span
|
||
class="header-section-number">1.7.3</span> 5.3 数据安全特性</h3>
|
||
<ul>
|
||
<li><strong>透明数据加密(TDE)</strong>:自动加密存储数据,支持SM4国密算法</li>
|
||
<li><strong>行级安全(RLS)</strong>:基于用户角色的行级数据访问控制</li>
|
||
<li><strong>列级权限</strong>:敏感字段的精细化访问控制</li>
|
||
<li><strong>动态脱敏</strong>:查询时自动脱敏显示敏感信息</li>
|
||
<li><strong>数据备份安全</strong>:备份文件自动加密,支持增量备份</li>
|
||
<li><strong>审计日志</strong>:完整记录所有数据库操作,支持合规审计</li>
|
||
</ul>
|
||
<h3 data-number="1.7.4" id="多租户安全隔离"><span
|
||
class="header-section-number">1.7.4</span> 5.4 多租户安全隔离</h3>
|
||
<ul>
|
||
<li><strong>逻辑隔离</strong>:基于tenant_id的数据隔离</li>
|
||
<li><strong>连接隔离</strong>:租户间连接池隔离</li>
|
||
<li><strong>权限隔离</strong>:租户级别的权限管理</li>
|
||
<li><strong>资源隔离</strong>:CPU、内存、IO资源限制</li>
|
||
</ul>
|
||
<h3 data-number="1.7.5" id="应用安全"><span
|
||
class="header-section-number">1.7.5</span> 5.5 应用安全</h3>
|
||
<ul>
|
||
<li><strong>身份认证</strong>:多因素认证,支持短信验证码、邮箱验证等</li>
|
||
<li><strong>授权管理</strong>:细粒度的权限控制,支持菜单、按钮、数据权限</li>
|
||
<li><strong>安全审计</strong>:用户操作审计,关键业务操作全程记录</li>
|
||
<li><strong>密码策略</strong>:密码复杂度、定期更换、失败锁定等安全策略</li>
|
||
<li><strong>会话管理</strong>:会话超时、并发限制、单点登录等</li>
|
||
</ul>
|
||
<h3 data-number="1.7.6" id="接口安全"><span
|
||
class="header-section-number">1.7.6</span> 5.6 接口安全</h3>
|
||
<ul>
|
||
<li><strong>接口认证</strong>:基于JWT Token的接口认证</li>
|
||
<li><strong>接口授权</strong>:基于角色的接口授权和权限验证</li>
|
||
<li><strong>接口加密</strong>:敏感数据的加密传输,支持国密算法</li>
|
||
<li><strong>接口防护</strong>:防重放、防篡改、防SQL注入等安全措施</li>
|
||
<li><strong>接口限流</strong>:基于IP、用户、应用的多维度限流策略</li>
|
||
</ul>
|
||
<h2 data-number="1.8" id="六部署架构"><span
|
||
class="header-section-number">1.8</span> 六、部署架构</h2>
|
||
<p>系统采用集中部署的模式,基于集团私有云环境进行部署。</p>
|
||
<h3 data-number="1.8.1" id="物理部署"><span
|
||
class="header-section-number">1.8.1</span> 6.1 物理部署</h3>
|
||
<ul>
|
||
<li><strong>生产环境</strong>:高可用集群部署
|
||
<ul>
|
||
<li>应用服务器:2台或以上服务器,负载均衡</li>
|
||
<li><strong>OpenGauss数据库集群</strong>:主从+级联备架构,支持自动故障切换</li>
|
||
<li>缓存服务器:Redis集群</li>
|
||
<li>文件服务器:冗余存储</li>
|
||
</ul></li>
|
||
<li><strong>灾备环境</strong>:异地灾备,定期数据同步,支持OpenGauss流复制</li>
|
||
<li><strong>测试环境</strong>:用于系统测试和验证,单节点OpenGauss部署</li>
|
||
<li><strong>开发环境</strong>:用于系统开发和集成测试,单节点OpenGauss部署</li>
|
||
</ul>
|
||
<h3 data-number="1.8.2" id="逻辑部署"><span
|
||
class="header-section-number">1.8.2</span> 6.2 逻辑部署</h3>
|
||
<ul>
|
||
<li><strong>应用服务器集群</strong>:负责业务逻辑处理,支持水平扩展</li>
|
||
<li><strong>OpenGauss数据库集群</strong>:负责数据存储和管理,提供高可用保障</li>
|
||
<li><strong>文件服务器</strong>:负责文档和附件存储,支持分布式存储</li>
|
||
<li><strong>缓存服务器</strong>:Redis集群提高系统性能</li>
|
||
<li><strong>负载均衡服务器</strong>:实现请求分发和负载均衡</li>
|
||
<li><strong>移动应用服务</strong>:提供移动端API服务</li>
|
||
<li><strong>API网关</strong>:统一的接口管理和控制</li>
|
||
</ul>
|
||
<h3 data-number="1.8.3" id="容器部署"><span
|
||
class="header-section-number">1.8.3</span> 6.3 容器部署</h3>
|
||
<ul>
|
||
<li>基于Docker容器技术实现微服务部署</li>
|
||
<li>使用Kubernetes进行容器编排和管理</li>
|
||
<li>支持容器的自动扩缩容和故障转移</li>
|
||
<li>实现服务的灰度发布和版本控制</li>
|
||
</ul>
|
||
<h2 data-number="1.9" id="七接口架构"><span
|
||
class="header-section-number">1.9</span> 七、接口架构</h2>
|
||
<p>系统提供标准化的接口,实现与外部系统的集成和数据交换。</p>
|
||
<h3 data-number="1.9.1" id="外部接口"><span
|
||
class="header-section-number">1.9.1</span> 7.1 外部接口</h3>
|
||
<ul>
|
||
<li>银行接口:实现与银行系统的对接,支持代扣、托收等功能</li>
|
||
<li>支付宝/微信接口:支持在线支付功能</li>
|
||
<li>短信接口:支持短信通知和验证码功能</li>
|
||
<li>集抄系统接口:实现与智能水表集中抄表系统的对接</li>
|
||
<li>政务系统接口:实现与地方政务平台和政务APP的对接</li>
|
||
<li>消火栓系统接口:实现与消火栓系统的对接</li>
|
||
<li>环卫系统接口:实现与环卫系统的对接</li>
|
||
<li>OA系统接口:实现与OA系统的工作流对接</li>
|
||
</ul>
|
||
<h3 data-number="1.9.2" id="内部接口"><span
|
||
class="header-section-number">1.9.2</span> 7.2 内部接口</h3>
|
||
<ul>
|
||
<li>ESB服务接口:系统内部模块间的数据交换</li>
|
||
<li>报表接口:提供报表数据查询和生成功能</li>
|
||
<li>查询接口:提供数据查询功能</li>
|
||
<li>业务处理接口:提供业务处理功能</li>
|
||
<li>消息通知接口:提供消息推送和通知功能</li>
|
||
<li>工作流接口:提供工作流处理和状态查询功能</li>
|
||
</ul>
|
||
<h3 data-number="1.9.3" id="接口标准"><span
|
||
class="header-section-number">1.9.3</span> 7.3 接口标准</h3>
|
||
<ul>
|
||
<li>接口协议:RESTful API、WebService、消息队列等</li>
|
||
<li>数据格式:JSON、XML等</li>
|
||
<li>接口安全:身份认证、授权、加密传输等</li>
|
||
<li>接口文档:统一的接口文档和示例代码</li>
|
||
<li>接口测试:提供接口测试工具和环境</li>
|
||
</ul>
|
||
<h3 data-number="1.9.4" id="接口服务管理"><span
|
||
class="header-section-number">1.9.4</span> 7.4 接口服务管理</h3>
|
||
<ul>
|
||
<li>API网关:统一的接口入口和管理</li>
|
||
<li>服务注册与发现:服务的自动注册和发现</li>
|
||
<li>服务路由:根据请求参数进行服务路由</li>
|
||
<li>服务降级:在服务不可用时提供降级策略</li>
|
||
</ul>
|
||
</body>
|
||
</html>
|