fujian_water_biz_doc/output/water_biz_interface_design.html

1445 lines
182 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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> 1. 接口概述</a>
<ul>
<li><a href="#接口设计原则" id="toc-接口设计原则"><span
class="toc-section-number">1.3.1</span> 1.1 接口设计原则</a></li>
<li><a href="#restful-api规范" id="toc-restful-api规范"><span
class="toc-section-number">1.3.2</span> 1.2 RESTful API规范</a>
<ul>
<li><a href="#资源命名" id="toc-资源命名"><span
class="toc-section-number">1.3.2.1</span> 1.2.1 资源命名</a></li>
<li><a href="#http方法" id="toc-http方法"><span
class="toc-section-number">1.3.2.2</span> 1.2.2 HTTP方法</a></li>
<li><a href="#状态码" id="toc-状态码"><span
class="toc-section-number">1.3.2.3</span> 1.2.3 状态码</a></li>
<li><a href="#响应格式" id="toc-响应格式"><span
class="toc-section-number">1.3.2.4</span> 1.2.4 响应格式</a></li>
</ul></li>
<li><a href="#接口文档" id="toc-接口文档"><span
class="toc-section-number">1.3.3</span> 1.3 接口文档</a></li>
</ul></li>
<li><a href="#外部接口" id="toc-外部接口"><span
class="toc-section-number">1.4</span> 2. 外部接口</a>
<ul>
<li><a href="#银行接口对接" id="toc-银行接口对接"><span
class="toc-section-number">1.4.1</span> 2.1 银行接口对接</a>
<ul>
<li><a href="#银行代扣接口" id="toc-银行代扣接口"><span
class="toc-section-number">1.4.1.1</span> 2.1.1 银行代扣接口</a></li>
<li><a href="#银行实时缴费接口" id="toc-银行实时缴费接口"><span
class="toc-section-number">1.4.1.2</span> 2.1.2
银行实时缴费接口</a></li>
</ul></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></li>
<li><a href="#短信接口" id="toc-短信接口"><span
class="toc-section-number">1.4.4</span> 2.4 短信接口</a></li>
<li><a href="#物联网集抄平台接口" id="toc-物联网集抄平台接口"><span
class="toc-section-number">1.4.5</span> 2.5 物联网集抄平台接口</a></li>
</ul></li>
<li><a href="#内部接口" id="toc-内部接口"><span
class="toc-section-number">1.5</span> 3. 内部接口</a>
<ul>
<li><a href="#客户管理api接口" id="toc-客户管理api接口"><span
class="toc-section-number">1.5.1</span> 3.1 客户管理API接口</a>
<ul>
<li><a href="#客户信息查询接口" id="toc-客户信息查询接口"><span
class="toc-section-number">1.5.1.1</span> 3.1.1
客户信息查询接口</a></li>
<li><a href="#客户分页查询接口" id="toc-客户分页查询接口"><span
class="toc-section-number">1.5.1.2</span> 3.1.2
客户分页查询接口</a></li>
<li><a href="#客户创建接口" id="toc-客户创建接口"><span
class="toc-section-number">1.5.1.3</span> 3.1.3 客户创建接口</a></li>
</ul></li>
<li><a href="#水表管理api接口" id="toc-水表管理api接口"><span
class="toc-section-number">1.5.2</span> 3.2 水表管理API接口</a>
<ul>
<li><a href="#水表信息查询接口" id="toc-水表信息查询接口"><span
class="toc-section-number">1.5.2.1</span> 3.2.1
水表信息查询接口</a></li>
<li><a href="#抄表记录创建接口" id="toc-抄表记录创建接口"><span
class="toc-section-number">1.5.2.2</span> 3.2.2
抄表记录创建接口</a></li>
<li><a href="#抄表数据批量导入接口" id="toc-抄表数据批量导入接口"><span
class="toc-section-number">1.5.2.3</span> 3.2.3
抄表数据批量导入接口</a></li>
</ul></li>
<li><a href="#账单管理api接口" id="toc-账单管理api接口"><span
class="toc-section-number">1.5.3</span> 3.3 账单管理API接口</a>
<ul>
<li><a href="#账单查询接口" id="toc-账单查询接口"><span
class="toc-section-number">1.5.3.1</span> 3.3.1 账单查询接口</a></li>
<li><a href="#账单生成接口" id="toc-账单生成接口"><span
class="toc-section-number">1.5.3.2</span> 3.3.2 账单生成接口</a></li>
</ul></li>
<li><a href="#缴费管理api接口" id="toc-缴费管理api接口"><span
class="toc-section-number">1.5.4</span> 3.4 缴费管理API接口</a>
<ul>
<li><a href="#缴费处理接口" id="toc-缴费处理接口"><span
class="toc-section-number">1.5.4.1</span> 3.4.1 缴费处理接口</a></li>
<li><a href="#在线支付接口" id="toc-在线支付接口"><span
class="toc-section-number">1.5.4.2</span> 3.4.2 在线支付接口</a></li>
</ul></li>
<li><a href="#工单接口" id="toc-工单接口"><span
class="toc-section-number">1.5.5</span> 3.4 工单接口</a>
<ul>
<li><a href="#工单创建接口" id="toc-工单创建接口"><span
class="toc-section-number">1.5.5.1</span> 3.4.1 工单创建接口</a></li>
<li><a href="#工单状态更新接口" id="toc-工单状态更新接口"><span
class="toc-section-number">1.5.5.2</span> 3.4.2
工单状态更新接口</a></li>
</ul></li>
</ul></li>
<li><a href="#接口标准" id="toc-接口标准"><span
class="toc-section-number">1.6</span> 4. 接口标准</a>
<ul>
<li><a href="#接口协议" id="toc-接口协议"><span
class="toc-section-number">1.6.1</span> 4.1 接口协议</a></li>
<li><a href="#数据格式" id="toc-数据格式"><span
class="toc-section-number">1.6.2</span> 4.2 数据格式</a></li>
<li><a href="#接口安全设计" id="toc-接口安全设计"><span
class="toc-section-number">1.6.3</span> 4.3 接口安全设计</a>
<ul>
<li><a href="#认证机制" id="toc-认证机制"><span
class="toc-section-number">1.6.3.1</span> 4.3.1 认证机制</a></li>
<li><a href="#数据加密" id="toc-数据加密"><span
class="toc-section-number">1.6.3.2</span> 4.3.2 数据加密</a></li>
<li><a href="#访问控制" id="toc-访问控制"><span
class="toc-section-number">1.6.3.3</span> 4.3.3 访问控制</a></li>
<li><a href="#接口限流" id="toc-接口限流"><span
class="toc-section-number">1.6.3.4</span> 4.3.4 接口限流</a></li>
</ul></li>
<li><a href="#错误处理机制" id="toc-错误处理机制"><span
class="toc-section-number">1.6.4</span> 4.4 错误处理机制</a>
<ul>
<li><a href="#统一异常处理" id="toc-统一异常处理"><span
class="toc-section-number">1.6.4.1</span> 4.4.1 统一异常处理</a></li>
<li><a href="#错误码定义" id="toc-错误码定义"><span
class="toc-section-number">1.6.4.2</span> 4.4.2 错误码定义</a></li>
<li><a href="#接口调用示例" id="toc-接口调用示例"><span
class="toc-section-number">1.6.4.3</span> 4.4.3 接口调用示例</a></li>
</ul></li>
<li><a href="#前端接口调用示例" id="toc-前端接口调用示例"><span
class="toc-section-number">1.6.5</span> 4.5 前端接口调用示例</a>
<ul>
<li><a href="#vue3-typescript接口封装"
id="toc-vue3-typescript接口封装"><span
class="toc-section-number">1.6.5.1</span> 4.5.1 Vue3 +
TypeScript接口封装</a></li>
<li><a href="#vue组件使用示例" id="toc-vue组件使用示例"><span
class="toc-section-number">1.6.5.2</span> 4.5.2 Vue组件使用示例</a></li>
</ul></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="#1-接口概述">1. 接口概述</a></li>
<li><a href="#2-外部接口">2. 外部接口</a></li>
<li><a href="#3-内部接口">3. 内部接口</a></li>
<li><a href="#4-接口标准">4. 接口标准</a></li>
</ul>
<h2 data-number="1.3" id="接口概述"><span
class="header-section-number">1.3</span> 1. 接口概述</h2>
<p>福建水务业务系统提供丰富的接口用于与外部系统集成以及系统内部各模块间的数据交换。接口设计遵循标准化、安全性、可扩展性的原则基于RuoYi-Vue-Pro框架采用RESTful风格设计支持JSON数据格式。</p>
<h3 data-number="1.3.1" id="接口设计原则"><span
class="header-section-number">1.3.1</span> 1.1 接口设计原则</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.3.2" id="restful-api规范"><span
class="header-section-number">1.3.2</span> 1.2 RESTful API规范</h3>
<p>系统API接口采用RESTful风格设计主要规范如下</p>
<h4 data-number="1.3.2.1" id="资源命名"><span
class="header-section-number">1.3.2.1</span> 1.2.1 资源命名</h4>
<ul>
<li>使用名词复数表示资源集合,如<code>/users</code><code>/meters</code></li>
<li>使用资源ID标识特定资源<code>/users/1</code><code>/meters/123</code></li>
<li>资源层级关系通过路径嵌套表示,如<code>/users/1/meters</code></li>
</ul>
<h4 data-number="1.3.2.2" id="http方法"><span
class="header-section-number">1.3.2.2</span> 1.2.2 HTTP方法</h4>
<ul>
<li>GET获取资源</li>
<li>POST创建资源</li>
<li>PUT更新资源全量更新</li>
<li>PATCH部分更新资源</li>
<li>DELETE删除资源</li>
</ul>
<h4 data-number="1.3.2.3" id="状态码"><span
class="header-section-number">1.3.2.3</span> 1.2.3 状态码</h4>
<ul>
<li>200 OK请求成功</li>
<li>201 Created资源创建成功</li>
<li>400 Bad Request请求参数错误</li>
<li>401 Unauthorized未授权</li>
<li>403 Forbidden权限不足</li>
<li>404 Not Found资源不存在</li>
<li>500 Internal Server Error服务器内部错误</li>
</ul>
<h4 data-number="1.3.2.4" id="响应格式"><span
class="header-section-number">1.3.2.4</span> 1.2.4 响应格式</h4>
<p>系统统一采用以下JSON格式响应</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span> <span class="er">//</span> <span class="er">业务状态码0表示成功非0表示失败</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{},</span> <span class="er">//</span> <span class="er">响应数据</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;success&quot;</span> <span class="er">//</span> <span class="er">响应消息</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p>分页查询响应格式:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;list&quot;</span><span class="fu">:</span> <span class="ot">[]</span><span class="fu">,</span> <span class="er">//</span> <span class="er">数据列表</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;total&quot;</span><span class="fu">:</span> <span class="dv">100</span><span class="fu">,</span> <span class="er">//</span> <span class="er">总记录数</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;pageNum&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span> <span class="er">//</span> <span class="er">当前页码</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;pageSize&quot;</span><span class="fu">:</span> <span class="dv">10</span> <span class="er">//</span> <span class="er">每页记录数</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">},</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;success&quot;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.3.3" id="接口文档"><span
class="header-section-number">1.3.3</span> 1.3 接口文档</h3>
<p>系统使用Knife4j基于Swagger自动生成API文档文档地址为<code>http://{系统地址}/doc.html</code></p>
<p>主要特点: - 在线接口文档:支持在线查看接口定义 -
接口调试:支持在线调试接口 - 文档导出支持导出OpenAPI规范文档 -
权限控制:支持对接口文档的访问控制</p>
<h2 data-number="1.4" id="外部接口"><span
class="header-section-number">1.4</span> 2. 外部接口</h2>
<h3 data-number="1.4.1" id="银行接口对接"><span
class="header-section-number">1.4.1</span> 2.1 银行接口对接</h3>
<h4 data-number="1.4.1.1" id="银行代扣接口"><span
class="header-section-number">1.4.1.1</span> 2.1.1 银行代扣接口</h4>
<p><strong>功能描述</strong>:通过银行系统自动从用户账户中扣除水费。</p>
<p><strong>接口详情</strong> -
<strong>接口方式</strong>文件交换FTP/SFTP -
<strong>数据格式</strong>:定长文本文件 -
<strong>交换频率</strong>每日凌晨2:00 -
<strong>文件编码</strong>GBK</p>
<p><strong>代扣文件格式</strong></p>
<pre class="text"><code>记录类型(1位) + 客户号(12位) + 户名(30位) + 银行账号(20位) + 扣款金额(12位,含2位小数) + 账期(6位) + 保留字段(19位)</code></pre>
<p><strong>代扣文件示例</strong></p>
<pre class="text"><code>1C00000000001张三 62172511001234567890000009180202412
1C00000000002李四 62172511001234567891000015460202412 </code></pre>
<p><strong>回盘文件格式</strong></p>
<pre class="text"><code>记录类型(1位) + 客户号(12位) + 银行账号(20位) + 扣款金额(12位) + 处理状态(1位) + 银行流水号(20位) + 处理时间(14位) + 失败原因(20位)</code></pre>
<p><strong>Java实现示例</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">@Service</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> BankDeductServiceImpl <span class="kw">implements</span> BankDeductService <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> SftpTemplate sftpTemplate<span class="op">;</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> BillService billService<span class="op">;</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> <span class="at">@Scheduled</span><span class="op">(</span>cron <span class="op">=</span> <span class="st">&quot;0 0 2 * * ?&quot;</span><span class="op">)</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">generateDeductFile</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> LocalDate deductDate <span class="op">=</span> LocalDate<span class="op">.</span><span class="fu">now</span><span class="op">();</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// 获取待代扣账单</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> <span class="bu">List</span><span class="op">&lt;</span>BillDO<span class="op">&gt;</span> deductBills <span class="op">=</span> billService<span class="op">.</span><span class="fu">getDeductBills</span><span class="op">(</span>deductDate<span class="op">);</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// 生成代扣文件</span></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> fileName <span class="op">=</span> <span class="st">&quot;DEDUCT_&quot;</span> <span class="op">+</span> deductDate<span class="op">.</span><span class="fu">format</span><span class="op">(</span>DateTimeFormatter<span class="op">.</span><span class="fu">ofPattern</span><span class="op">(</span><span class="st">&quot;yyyyMMdd&quot;</span><span class="op">))</span> <span class="op">+</span> <span class="st">&quot;.txt&quot;</span><span class="op">;</span></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> fileContent <span class="op">=</span> <span class="fu">buildDeductFileContent</span><span class="op">(</span>deductBills<span class="op">);</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a> <span class="co">// 上传至银行SFTP</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a> sftpTemplate<span class="op">.</span><span class="fu">put</span><span class="op">(</span>fileName<span class="op">,</span> fileContent<span class="op">.</span><span class="fu">getBytes</span><span class="op">(</span>StandardCharsets<span class="op">.</span><span class="fu">UTF_8</span><span class="op">),</span> <span class="st">&quot;/upload/&quot;</span><span class="op">);</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a> <span class="co">// 记录代扣文件日志</span></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a> DeductFileLogDO log <span class="op">=</span> <span class="kw">new</span> <span class="fu">DeductFileLogDO</span><span class="op">();</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">setFileName</span><span class="op">(</span>fileName<span class="op">);</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">setFileStatus</span><span class="op">(</span><span class="st">&quot;UPLOADED&quot;</span><span class="op">);</span></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">setRecordCount</span><span class="op">(</span>deductBills<span class="op">.</span><span class="fu">size</span><span class="op">());</span></span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a> deductFileLogMapper<span class="op">.</span><span class="fu">insert</span><span class="op">(</span>log<span class="op">);</span></span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> <span class="bu">String</span> <span class="fu">buildDeductFileContent</span><span class="op">(</span><span class="bu">List</span><span class="op">&lt;</span>BillDO<span class="op">&gt;</span> bills<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="bu">StringBuilder</span> content <span class="op">=</span> <span class="kw">new</span> <span class="bu">StringBuilder</span><span class="op">();</span></span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>BillDO bill <span class="op">:</span> bills<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a> content<span class="op">.</span><span class="fu">append</span><span class="op">(</span><span class="st">&quot;1&quot;</span><span class="op">)</span> <span class="co">// 记录类型</span></span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span>StringUtils<span class="op">.</span><span class="fu">rightPad</span><span class="op">(</span>bill<span class="op">.</span><span class="fu">getCustomerCode</span><span class="op">(),</span> <span class="dv">12</span><span class="op">))</span> <span class="co">// 客户号</span></span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span>StringUtils<span class="op">.</span><span class="fu">rightPad</span><span class="op">(</span>bill<span class="op">.</span><span class="fu">getCustomerName</span><span class="op">(),</span> <span class="dv">30</span><span class="op">))</span> <span class="co">// 户名</span></span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span>StringUtils<span class="op">.</span><span class="fu">rightPad</span><span class="op">(</span>bill<span class="op">.</span><span class="fu">getBankAccount</span><span class="op">(),</span> <span class="dv">20</span><span class="op">))</span> <span class="co">// 银行账号</span></span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span><span class="bu">String</span><span class="op">.</span><span class="fu">format</span><span class="op">(</span><span class="st">&quot;</span><span class="sc">%012d</span><span class="st">&quot;</span><span class="op">,</span> bill<span class="op">.</span><span class="fu">getTotalAmount</span><span class="op">().</span><span class="fu">multiply</span><span class="op">(</span><span class="kw">new</span> <span class="bu">BigDecimal</span><span class="op">(</span><span class="dv">100</span><span class="op">)).</span><span class="fu">intValue</span><span class="op">()))</span> <span class="co">// 金额(分)</span></span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span>bill<span class="op">.</span><span class="fu">getBillMonth</span><span class="op">().</span><span class="fu">replace</span><span class="op">(</span><span class="st">&quot;-&quot;</span><span class="op">,</span> <span class="st">&quot;&quot;</span><span class="op">))</span> <span class="co">// 账期</span></span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span>StringUtils<span class="op">.</span><span class="fu">repeat</span><span class="op">(</span><span class="st">&quot; &quot;</span><span class="op">,</span> <span class="dv">19</span><span class="op">))</span> <span class="co">// 保留字段</span></span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">append</span><span class="op">(</span><span class="st">&quot;</span></span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;);</span></span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> content<span class="op">.</span><span class="fu">toString</span><span class="op">();</span></span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.4.1.2" id="银行实时缴费接口"><span
class="header-section-number">1.4.1.2</span> 2.1.2 银行实时缴费接口</h4>
<p><strong>功能描述</strong>:用户在银行柜台、网上银行或手机银行实时缴纳水费。</p>
<p><strong>接口详情</strong> - <strong>接口方式</strong>HTTP POST -
<strong>请求URL</strong><code>https://bank.api.com/payment/water-fee</code>
- <strong>数据格式</strong>JSON - <strong>认证方式</strong>API Key +
签名</p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;merchantId&quot;</span><span class="fu">:</span> <span class="st">&quot;WATER001&quot;</span><span class="fu">,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerCode&quot;</span><span class="fu">:</span> <span class="st">&quot;C001&quot;</span><span class="fu">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billCodes&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="st">&quot;B202412190001&quot;</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;totalAmount&quot;</span><span class="fu">:</span> <span class="fl">91.80</span><span class="fu">,</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;bankAccount&quot;</span><span class="fu">:</span> <span class="st">&quot;6217251100123456789&quot;</span><span class="fu">,</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span><span class="fu">,</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;timestamp&quot;</span><span class="fu">:</span> <span class="st">&quot;20241219103000&quot;</span><span class="fu">,</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;signature&quot;</span><span class="fu">:</span> <span class="st">&quot;ABC123DEF456...&quot;</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</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">&quot;resultCode&quot;</span><span class="fu">:</span> <span class="st">&quot;0000&quot;</span><span class="fu">,</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;resultMsg&quot;</span><span class="fu">:</span> <span class="st">&quot;交易成功&quot;</span><span class="fu">,</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;transactionId&quot;</span><span class="fu">:</span> <span class="st">&quot;TXN20241219001&quot;</span><span class="fu">,</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentTime&quot;</span><span class="fu">:</span> <span class="st">&quot;20241219103001&quot;</span><span class="fu">,</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;bankSerial&quot;</span><span class="fu">:</span> <span class="st">&quot;BNK20241219001234&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.4.2" id="支付宝接口对接"><span
class="header-section-number">1.4.2</span> 2.2 支付宝接口对接</h3>
<p><strong>功能描述</strong>用户通过支付宝缴纳水费支持扫码支付和H5支付。</p>
<p><strong>接口详情</strong> - <strong>接口方式</strong>HTTP POST -
<strong>支付方式</strong>统一收单交易预创建alipay.trade.precreate
- <strong>数据格式</strong>JSON -
<strong>认证方式</strong>RSA2签名</p>
<p><strong>预创建支付请求参数</strong></p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;app_id&quot;</span><span class="fu">:</span> <span class="st">&quot;2021001234567890&quot;</span><span class="fu">,</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;method&quot;</span><span class="fu">:</span> <span class="st">&quot;alipay.trade.precreate&quot;</span><span class="fu">,</span> </span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;charset&quot;</span><span class="fu">:</span> <span class="st">&quot;UTF-8&quot;</span><span class="fu">,</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;sign_type&quot;</span><span class="fu">:</span> <span class="st">&quot;RSA2&quot;</span><span class="fu">,</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;timestamp&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19 10:30:00&quot;</span><span class="fu">,</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;version&quot;</span><span class="fu">:</span> <span class="st">&quot;1.0&quot;</span><span class="fu">,</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;notify_url&quot;</span><span class="fu">:</span> <span class="st">&quot;https://water.example.com/api/payment/alipay/notify&quot;</span><span class="fu">,</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;biz_content&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;out_trade_no&quot;</span><span class="fu">:</span> <span class="st">&quot;P202412190002&quot;</span><span class="fu">,</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;total_amount&quot;</span><span class="fu">:</span> <span class="st">&quot;91.80&quot;</span><span class="fu">,</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;subject&quot;</span><span class="fu">:</span> <span class="st">&quot;水费缴费&quot;</span><span class="fu">,</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;body&quot;</span><span class="fu">:</span> <span class="st">&quot;2024年12月水费-客户编号:C001&quot;</span><span class="fu">,</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;store_id&quot;</span><span class="fu">:</span> <span class="st">&quot;WATER_STORE_001&quot;</span><span class="fu">,</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;timeout_express&quot;</span><span class="fu">:</span> <span class="st">&quot;30m&quot;</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>支付宝响应参数</strong></p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;alipay_trade_precreate_response&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="st">&quot;10000&quot;</span><span class="fu">,</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;Success&quot;</span><span class="fu">,</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;out_trade_no&quot;</span><span class="fu">:</span> <span class="st">&quot;P202412190002&quot;</span><span class="fu">,</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;qr_code&quot;</span><span class="fu">:</span> <span class="st">&quot;https://qr.alipay.com/bax08945xtdnfwgqmwi200b4&quot;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">},</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;sign&quot;</span><span class="fu">:</span> <span class="st">&quot;ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&quot;</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Java实现示例</strong></p>
<div class="sourceCode" id="cb11"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Service</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> AlipayServiceImpl <span class="kw">implements</span> AlipayService <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> AlipayClient alipayClient<span class="op">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> AlipayPaymentRespVO <span class="fu">createPayment</span><span class="op">(</span>AlipayPaymentReqVO request<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> AlipayTradePrecreateRequest alipayRequest <span class="op">=</span> <span class="kw">new</span> <span class="fu">AlipayTradePrecreateRequest</span><span class="op">();</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> alipayRequest<span class="op">.</span><span class="fu">setNotifyUrl</span><span class="op">(</span><span class="st">&quot;https://water.example.com/api/payment/alipay/notify&quot;</span><span class="op">);</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> AlipayTradePrecreateModel model <span class="op">=</span> <span class="kw">new</span> <span class="fu">AlipayTradePrecreateModel</span><span class="op">();</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a> model<span class="op">.</span><span class="fu">setOutTradeNo</span><span class="op">(</span>request<span class="op">.</span><span class="fu">getPaymentCode</span><span class="op">());</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a> model<span class="op">.</span><span class="fu">setTotalAmount</span><span class="op">(</span>request<span class="op">.</span><span class="fu">getTotalAmount</span><span class="op">().</span><span class="fu">toString</span><span class="op">());</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a> model<span class="op">.</span><span class="fu">setSubject</span><span class="op">(</span><span class="st">&quot;水费缴费&quot;</span><span class="op">);</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a> model<span class="op">.</span><span class="fu">setBody</span><span class="op">(</span><span class="st">&quot;账单号:&quot;</span> <span class="op">+</span> <span class="bu">String</span><span class="op">.</span><span class="fu">join</span><span class="op">(</span><span class="st">&quot;,&quot;</span><span class="op">,</span> request<span class="op">.</span><span class="fu">getBillCodes</span><span class="op">()));</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a> model<span class="op">.</span><span class="fu">setTimeoutExpress</span><span class="op">(</span><span class="st">&quot;30m&quot;</span><span class="op">);</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a> alipayRequest<span class="op">.</span><span class="fu">setBizModel</span><span class="op">(</span>model<span class="op">);</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 class="cf">try</span> <span class="op">{</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a> AlipayTradePrecreateResponse response <span class="op">=</span> alipayClient<span class="op">.</span><span class="fu">execute</span><span class="op">(</span>alipayRequest<span class="op">);</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>response<span class="op">.</span><span class="fu">isSuccess</span><span class="op">())</span> <span class="op">{</span></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> AlipayPaymentRespVO<span class="op">.</span><span class="fu">builder</span><span class="op">()</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">paymentCode</span><span class="op">(</span>request<span class="op">.</span><span class="fu">getPaymentCode</span><span class="op">())</span></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">qrCode</span><span class="op">(</span>response<span class="op">.</span><span class="fu">getQrCode</span><span class="op">())</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">outTradeNo</span><span class="op">(</span>response<span class="op">.</span><span class="fu">getOutTradeNo</span><span class="op">())</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">build</span><span class="op">();</span></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="fu">BizException</span><span class="op">(</span>ALIPAY_PAY_FAILED<span class="op">,</span> response<span class="op">.</span><span class="fu">getSubMsg</span><span class="op">());</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span>AlipayApiException e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="fu">BizException</span><span class="op">(</span>ALIPAY_PAY_ERROR<span class="op">,</span> e<span class="op">.</span><span class="fu">getErrMsg</span><span class="op">());</span></span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="1.4.3" id="微信支付接口对接"><span
class="header-section-number">1.4.3</span> 2.3 微信支付接口对接</h3>
<p><strong>功能描述</strong>:用户通过微信支付缴纳水费,支持扫码支付和小程序支付。</p>
<p><strong>接口详情</strong> - <strong>接口方式</strong>HTTP POST -
<strong>支付方式</strong>Native支付扫码/ JSAPI支付小程序 -
<strong>请求URL</strong><code>https://api.mch.weixin.qq.com/v3/pay/transactions/native</code>
- <strong>数据格式</strong>JSON -
<strong>认证方式</strong>微信支付V3签名</p>
<p><strong>统一下单请求参数</strong></p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;appid&quot;</span><span class="fu">:</span> <span class="st">&quot;wx8888888888888888&quot;</span><span class="fu">,</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;mchid&quot;</span><span class="fu">:</span> <span class="st">&quot;1900000109&quot;</span><span class="fu">,</span> </span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;description&quot;</span><span class="fu">:</span> <span class="st">&quot;水费缴费-2024年12月&quot;</span><span class="fu">,</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;out_trade_no&quot;</span><span class="fu">:</span> <span class="st">&quot;P202412190003&quot;</span><span class="fu">,</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;notify_url&quot;</span><span class="fu">:</span> <span class="st">&quot;https://water.example.com/api/payment/wechat/notify&quot;</span><span class="fu">,</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;amount&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;total&quot;</span><span class="fu">:</span> <span class="dv">9180</span><span class="fu">,</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;currency&quot;</span><span class="fu">:</span> <span class="st">&quot;CNY&quot;</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">},</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;attach&quot;</span><span class="fu">:</span> <span class="st">&quot;客户编号:C001,账单号:B202412190001&quot;</span><span class="fu">,</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;goods_tag&quot;</span><span class="fu">:</span> <span class="st">&quot;WATER_FEE&quot;</span><span class="fu">,</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;time_expire&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19T11:00:00+08:00&quot;</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>微信支付响应参数</strong></p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code_url&quot;</span><span class="fu">:</span> <span class="st">&quot;weixin://wxpay/bizpayurl?pr=HuaLcAKwa&quot;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>支付结果通知参数</strong></p>
<div class="sourceCode" id="cb14"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="st">&quot;EV-2018022511223320873&quot;</span><span class="fu">,</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;create_time&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19T10:30:00+08:00&quot;</span><span class="fu">,</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;resource_type&quot;</span><span class="fu">:</span> <span class="st">&quot;encrypt-resource&quot;</span><span class="fu">,</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;event_type&quot;</span><span class="fu">:</span> <span class="st">&quot;TRANSACTION.SUCCESS&quot;</span><span class="fu">,</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;summary&quot;</span><span class="fu">:</span> <span class="st">&quot;支付成功&quot;</span><span class="fu">,</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;resource&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;original_type&quot;</span><span class="fu">:</span> <span class="st">&quot;transaction&quot;</span><span class="fu">,</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;algorithm&quot;</span><span class="fu">:</span> <span class="st">&quot;AEAD_AES_256_GCM&quot;</span><span class="fu">,</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;ciphertext&quot;</span><span class="fu">:</span> <span class="st">&quot;...&quot;</span><span class="fu">,</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;associated_data&quot;</span><span class="fu">:</span> <span class="st">&quot;transaction&quot;</span><span class="fu">,</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;nonce&quot;</span><span class="fu">:</span> <span class="st">&quot;...&quot;</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.4.4" id="短信接口"><span
class="header-section-number">1.4.4</span> 2.4 短信接口</h3>
<p><strong>功能描述</strong>:向用户发送各类业务通知短信。</p>
<p><strong>接口规范</strong> - 接口方式HTTP接口 - 数据格式JSON -
交换频率:实时</p>
<h3 data-number="1.4.5" id="物联网集抄平台接口"><span
class="header-section-number">1.4.5</span> 2.5 物联网集抄平台接口</h3>
<p><strong>功能描述</strong>:与物联网集抄平台交互,获取智能水表数据。</p>
<p><strong>接口规范</strong> - 接口方式HTTP接口或WebService -
数据格式JSON或XML - 交换频率:定时或实时</p>
<h2 data-number="1.5" id="内部接口"><span
class="header-section-number">1.5</span> 3. 内部接口</h2>
<h3 data-number="1.5.1" id="客户管理api接口"><span
class="header-section-number">1.5.1</span> 3.1 客户管理API接口</h3>
<h4 data-number="1.5.1.1" id="客户信息查询接口"><span
class="header-section-number">1.5.1.1</span> 3.1.1 客户信息查询接口</h4>
<p><strong>功能描述</strong>根据客户ID查询客户详细信息。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>GET -
<strong>请求路径</strong><code>/admin-api/water/customer/{id}</code> -
<strong>请求头</strong><code>Authorization: Bearer {token}</code></p>
<p><strong>请求参数</strong> | 参数名 | 类型 | 必填 | 说明 | 示例 |
|——-|——|——|——|——| | id | Long | 是 | 客户ID | 1 |</p>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb15"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerCode&quot;</span><span class="fu">:</span> <span class="st">&quot;C001&quot;</span><span class="fu">,</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span><span class="fu">,</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerType&quot;</span><span class="fu">:</span> <span class="st">&quot;RESIDENT&quot;</span><span class="fu">,</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;phone&quot;</span><span class="fu">:</span> <span class="st">&quot;13800138000&quot;</span><span class="fu">,</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;address&quot;</span><span class="fu">:</span> <span class="st">&quot;福建省福州市台江区XX街道XX号&quot;</span><span class="fu">,</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;createTime&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19 10:00:00&quot;</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>RuoYi-Vue-Pro代码示例</strong></p>
<div class="sourceCode" id="cb16"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="at">@RestController</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="at">@RequestMapping</span><span class="op">(</span><span class="st">&quot;/admin-api/water/customer&quot;</span><span class="op">)</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="at">@Tag</span><span class="op">(</span>name <span class="op">=</span> <span class="st">&quot;管理后台 - 客户管理&quot;</span><span class="op">)</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="at">@Validated</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> CustomerController <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> CustomerService customerService<span class="op">;</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a> <span class="at">@GetMapping</span><span class="op">(</span><span class="st">&quot;/{id}&quot;</span><span class="op">)</span></span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a> <span class="at">@Operation</span><span class="op">(</span>summary <span class="op">=</span> <span class="st">&quot;获得客户&quot;</span><span class="op">)</span></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a> <span class="at">@Parameter</span><span class="op">(</span>name <span class="op">=</span> <span class="st">&quot;id&quot;</span><span class="op">,</span> description <span class="op">=</span> <span class="st">&quot;编号&quot;</span><span class="op">,</span> required <span class="op">=</span> <span class="kw">true</span><span class="op">,</span> example <span class="op">=</span> <span class="st">&quot;1024&quot;</span><span class="op">)</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a> <span class="at">@PreAuthorize</span><span class="op">(</span><span class="st">&quot;@ss.hasPermission(&#39;water:customer:query&#39;)&quot;</span><span class="op">)</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;</span>CustomerRespVO<span class="op">&gt;</span> <span class="fu">getCustomer</span><span class="op">(</span><span class="at">@PathVariable</span><span class="op">(</span><span class="st">&quot;id&quot;</span><span class="op">)</span> <span class="bu">Long</span> id<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a> CustomerDO customer <span class="op">=</span> customerService<span class="op">.</span><span class="fu">getCustomer</span><span class="op">(</span>id<span class="op">);</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="fu">success</span><span class="op">(</span>BeanUtils<span class="op">.</span><span class="fu">toBean</span><span class="op">(</span>customer<span class="op">,</span> CustomerRespVO<span class="op">.</span><span class="fu">class</span><span class="op">));</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.5.1.2" id="客户分页查询接口"><span
class="header-section-number">1.5.1.2</span> 3.1.2 客户分页查询接口</h4>
<p><strong>功能描述</strong>:分页查询客户列表信息。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>GET -
<strong>请求路径</strong><code>/admin-api/water/customer/page</code></p>
<p><strong>请求参数</strong> | 参数名 | 类型 | 必填 | 说明 | 示例 |
|——-|——|——|——|——| | pageNo | Integer | 否 | 页码默认1 | 1 | | pageSize
| Integer | 否 | 每页条数默认10 | 10 | | customerName | String | 否 |
客户名称 | 张三 | | customerCode | String | 否 | 客户编号 | C001 | |
customerType | String | 否 | 客户类型 | RESIDENT | | phone | String | 否
| 联系电话 | 138 |</p>
<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="fu">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;list&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">{</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerCode&quot;</span><span class="fu">:</span> <span class="st">&quot;C001&quot;</span><span class="fu">,</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span><span class="fu">,</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerType&quot;</span><span class="fu">:</span> <span class="st">&quot;RESIDENT&quot;</span><span class="fu">,</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;phone&quot;</span><span class="fu">:</span> <span class="st">&quot;13800138000&quot;</span><span class="fu">,</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;address&quot;</span><span class="fu">:</span> <span class="st">&quot;福建省福州市台江区XX街道XX号&quot;</span><span class="fu">,</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;status&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;createTime&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19 10:00:00&quot;</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a> <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;total&quot;</span><span class="fu">:</span> <span class="dv">1</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h4 data-number="1.5.1.3" id="客户创建接口"><span
class="header-section-number">1.5.1.3</span> 3.1.3 客户创建接口</h4>
<p><strong>功能描述</strong>:创建新客户记录。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/customer/create</code></p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb18"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerCode&quot;</span><span class="fu">:</span> <span class="st">&quot;C002&quot;</span><span class="fu">,</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;李四&quot;</span><span class="fu">,</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerType&quot;</span><span class="fu">:</span> <span class="st">&quot;RESIDENT&quot;</span><span class="fu">,</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;idType&quot;</span><span class="fu">:</span> <span class="st">&quot;ID_CARD&quot;</span><span class="fu">,</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;idNumber&quot;</span><span class="fu">:</span> <span class="st">&quot;350103199001011234&quot;</span><span class="fu">,</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;phone&quot;</span><span class="fu">:</span> <span class="st">&quot;13900139000&quot;</span><span class="fu">,</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;address&quot;</span><span class="fu">:</span> <span class="st">&quot;福建省福州市鼓楼区XX街道XX号&quot;</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb19"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="dv">2</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Service层代码示例</strong></p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Service</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="at">@Validated</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> CustomerServiceImpl <span class="kw">implements</span> CustomerService <span class="op">{</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> CustomerMapper customerMapper<span class="op">;</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">Long</span> <span class="fu">createCustomer</span><span class="op">(</span>CustomerSaveReqVO createReqVO<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// 校验客户编号唯一性</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a> <span class="fu">validateCustomerCodeUnique</span><span class="op">(</span>createReqVO<span class="op">.</span><span class="fu">getCustomerCode</span><span class="op">());</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// 创建客户</span></span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a> CustomerDO customer <span class="op">=</span> BeanUtils<span class="op">.</span><span class="fu">toBean</span><span class="op">(</span>createReqVO<span class="op">,</span> CustomerDO<span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a> customerMapper<span class="op">.</span><span class="fu">insert</span><span class="op">(</span>customer<span class="op">);</span></span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> customer<span class="op">.</span><span class="fu">getId</span><span class="op">();</span></span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> <span class="dt">void</span> <span class="fu">validateCustomerCodeUnique</span><span class="op">(</span><span class="bu">String</span> customerCode<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a> CustomerDO existCustomer <span class="op">=</span> customerMapper<span class="op">.</span><span class="fu">selectByCustomerCode</span><span class="op">(</span>customerCode<span class="op">);</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>existCustomer <span class="op">!=</span> <span class="kw">null</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">throw</span> <span class="fu">exception</span><span class="op">(</span>CUSTOMER_CODE_DUPLICATE<span class="op">);</span></span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="1.5.2" id="水表管理api接口"><span
class="header-section-number">1.5.2</span> 3.2 水表管理API接口</h3>
<h4 data-number="1.5.2.1" id="水表信息查询接口"><span
class="header-section-number">1.5.2.1</span> 3.2.1 水表信息查询接口</h4>
<p><strong>功能描述</strong>根据水表ID查询水表详细信息。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>GET -
<strong>请求路径</strong><code>/admin-api/water/meter/{id}</code> -
<strong>请求头</strong><code>Authorization: Bearer {token}</code></p>
<p><strong>请求参数</strong> | 参数名 | 类型 | 必填 | 说明 | 示例 |
|——-|——|——|——|——| | id | Long | 是 | 水表ID | 1 |</p>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb21"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterCode&quot;</span><span class="fu">:</span> <span class="st">&quot;M001&quot;</span><span class="fu">,</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterNo&quot;</span><span class="fu">:</span> <span class="st">&quot;20241219001&quot;</span><span class="fu">,</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterType&quot;</span><span class="fu">:</span> <span class="st">&quot;SMART&quot;</span><span class="fu">,</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterModel&quot;</span><span class="fu">:</span> <span class="st">&quot;LXSY-15E&quot;</span><span class="fu">,</span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterCaliber&quot;</span><span class="fu">:</span> <span class="st">&quot;15mm&quot;</span><span class="fu">,</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;installDate&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-01-15&quot;</span><span class="fu">,</span></span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;installPosition&quot;</span><span class="fu">:</span> <span class="st">&quot;1层水表井&quot;</span><span class="fu">,</span></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;initialReading&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="er">.00</span><span class="fu">,</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;currentReading&quot;</span><span class="fu">:</span> <span class="fl">156.32</span><span class="fu">,</span></span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readingCycle&quot;</span><span class="fu">:</span> <span class="st">&quot;MONTHLY&quot;</span><span class="fu">,</span></span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterStatus&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span></span>
<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Controller代码示例</strong></p>
<div class="sourceCode" id="cb22"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="at">@RestController</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="at">@RequestMapping</span><span class="op">(</span><span class="st">&quot;/admin-api/water/meter&quot;</span><span class="op">)</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="at">@Tag</span><span class="op">(</span>name <span class="op">=</span> <span class="st">&quot;管理后台 - 水表管理&quot;</span><span class="op">)</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="at">@Validated</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> MeterController <span class="op">{</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> MeterService meterService<span class="op">;</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="at">@GetMapping</span><span class="op">(</span><span class="st">&quot;/{id}&quot;</span><span class="op">)</span></span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a> <span class="at">@Operation</span><span class="op">(</span>summary <span class="op">=</span> <span class="st">&quot;获得水表&quot;</span><span class="op">)</span></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a> <span class="at">@Parameter</span><span class="op">(</span>name <span class="op">=</span> <span class="st">&quot;id&quot;</span><span class="op">,</span> description <span class="op">=</span> <span class="st">&quot;编号&quot;</span><span class="op">,</span> required <span class="op">=</span> <span class="kw">true</span><span class="op">)</span></span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a> <span class="at">@PreAuthorize</span><span class="op">(</span><span class="st">&quot;@ss.hasPermission(&#39;water:meter:query&#39;)&quot;</span><span class="op">)</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;</span>MeterRespVO<span class="op">&gt;</span> <span class="fu">getMeter</span><span class="op">(</span><span class="at">@PathVariable</span><span class="op">(</span><span class="st">&quot;id&quot;</span><span class="op">)</span> <span class="bu">Long</span> id<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a> MeterDO meter <span class="op">=</span> meterService<span class="op">.</span><span class="fu">getMeter</span><span class="op">(</span>id<span class="op">);</span></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="fu">success</span><span class="op">(</span>BeanUtils<span class="op">.</span><span class="fu">toBean</span><span class="op">(</span>meter<span class="op">,</span> MeterRespVO<span class="op">.</span><span class="fu">class</span><span class="op">));</span></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.5.2.2" id="抄表记录创建接口"><span
class="header-section-number">1.5.2.2</span> 3.2.2 抄表记录创建接口</h4>
<p><strong>功能描述</strong>:创建新的抄表记录。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/reading/create</code></p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb23"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readingDate&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19&quot;</span><span class="fu">,</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readingValue&quot;</span><span class="fu">:</span> <span class="fl">156.32</span><span class="fu">,</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readingType&quot;</span><span class="fu">:</span> <span class="st">&quot;MANUAL&quot;</span><span class="fu">,</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readerId&quot;</span><span class="fu">:</span> <span class="st">&quot;R001&quot;</span><span class="fu">,</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;photoUrl&quot;</span><span class="fu">:</span> <span class="st">&quot;https://example.com/photos/reading001.jpg&quot;</span><span class="fu">,</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;remark&quot;</span><span class="fu">:</span> <span class="st">&quot;正常抄表&quot;</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb24"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span> </span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="dv">1</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Service层实现示例</strong></p>
<div class="sourceCode" id="cb25"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Service</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="at">@Validated</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> MeterReadingServiceImpl <span class="kw">implements</span> MeterReadingService <span class="op">{</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> MeterReadingMapper readingMapper<span class="op">;</span></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> MeterService meterService<span class="op">;</span></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a> <span class="at">@Transactional</span><span class="op">(</span>rollbackFor <span class="op">=</span> <span class="bu">Exception</span><span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">Long</span> <span class="fu">createReading</span><span class="op">(</span>MeterReadingSaveReqVO createReqVO<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// 校验水表存在性</span></span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a> MeterDO meter <span class="op">=</span> meterService<span class="op">.</span><span class="fu">validateMeterExists</span><span class="op">(</span>createReqVO<span class="op">.</span><span class="fu">getMeterId</span><span class="op">());</span></span>
<span id="cb25-15"><a href="#cb25-15" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-16"><a href="#cb25-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// 校验读数合理性</span></span>
<span id="cb25-17"><a href="#cb25-17" aria-hidden="true" tabindex="-1"></a> <span class="fu">validateReadingValue</span><span class="op">(</span>createReqVO<span class="op">.</span><span class="fu">getMeterId</span><span class="op">(),</span> createReqVO<span class="op">.</span><span class="fu">getReadingValue</span><span class="op">());</span></span>
<span id="cb25-18"><a href="#cb25-18" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-19"><a href="#cb25-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// 创建抄表记录</span></span>
<span id="cb25-20"><a href="#cb25-20" aria-hidden="true" tabindex="-1"></a> MeterReadingDO reading <span class="op">=</span> BeanUtils<span class="op">.</span><span class="fu">toBean</span><span class="op">(</span>createReqVO<span class="op">,</span> MeterReadingDO<span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb25-21"><a href="#cb25-21" aria-hidden="true" tabindex="-1"></a> reading<span class="op">.</span><span class="fu">setReadingCode</span><span class="op">(</span><span class="fu">generateReadingCode</span><span class="op">());</span></span>
<span id="cb25-22"><a href="#cb25-22" aria-hidden="true" tabindex="-1"></a> reading<span class="op">.</span><span class="fu">setCustomerId</span><span class="op">(</span>meter<span class="op">.</span><span class="fu">getCustomerId</span><span class="op">());</span></span>
<span id="cb25-23"><a href="#cb25-23" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-24"><a href="#cb25-24" aria-hidden="true" tabindex="-1"></a> <span class="co">// 计算用水量</span></span>
<span id="cb25-25"><a href="#cb25-25" aria-hidden="true" tabindex="-1"></a> <span class="bu">BigDecimal</span> waterUsage <span class="op">=</span> <span class="fu">calculateWaterUsage</span><span class="op">(</span>meter<span class="op">.</span><span class="fu">getCurrentReading</span><span class="op">(),</span> </span>
<span id="cb25-26"><a href="#cb25-26" aria-hidden="true" tabindex="-1"></a> createReqVO<span class="op">.</span><span class="fu">getReadingValue</span><span class="op">());</span></span>
<span id="cb25-27"><a href="#cb25-27" aria-hidden="true" tabindex="-1"></a> reading<span class="op">.</span><span class="fu">setWaterUsage</span><span class="op">(</span>waterUsage<span class="op">);</span></span>
<span id="cb25-28"><a href="#cb25-28" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-29"><a href="#cb25-29" aria-hidden="true" tabindex="-1"></a> readingMapper<span class="op">.</span><span class="fu">insert</span><span class="op">(</span>reading<span class="op">);</span></span>
<span id="cb25-30"><a href="#cb25-30" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-31"><a href="#cb25-31" aria-hidden="true" tabindex="-1"></a> <span class="co">// 更新水表当前读数</span></span>
<span id="cb25-32"><a href="#cb25-32" aria-hidden="true" tabindex="-1"></a> meterService<span class="op">.</span><span class="fu">updateCurrentReading</span><span class="op">(</span>createReqVO<span class="op">.</span><span class="fu">getMeterId</span><span class="op">(),</span> </span>
<span id="cb25-33"><a href="#cb25-33" aria-hidden="true" tabindex="-1"></a> createReqVO<span class="op">.</span><span class="fu">getReadingValue</span><span class="op">());</span></span>
<span id="cb25-34"><a href="#cb25-34" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb25-35"><a href="#cb25-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> reading<span class="op">.</span><span class="fu">getId</span><span class="op">();</span></span>
<span id="cb25-36"><a href="#cb25-36" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb25-37"><a href="#cb25-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.5.2.3" id="抄表数据批量导入接口"><span
class="header-section-number">1.5.2.3</span> 3.2.3
抄表数据批量导入接口</h4>
<p><strong>功能描述</strong>批量导入抄表数据支持Excel文件上传。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/reading/import</code>
- <strong>Content-Type</strong><code>multipart/form-data</code></p>
<p><strong>请求参数</strong> | 参数名 | 类型 | 必填 | 说明 | 示例 |
|——-|——|——|——|——| | file | MultipartFile | 是 | Excel文件 |
reading_data.xlsx | | updateSupport | Boolean | 否 | 是否更新已有数据 |
false |</p>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb26"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;successCount&quot;</span><span class="fu">:</span> <span class="dv">95</span><span class="fu">,</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;failureCount&quot;</span><span class="fu">:</span> <span class="dv">5</span><span class="fu">,</span></span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;failureList&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">{</span></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;lineNumber&quot;</span><span class="fu">:</span> <span class="dv">3</span><span class="fu">,</span></span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterCode&quot;</span><span class="fu">:</span> <span class="st">&quot;M003&quot;</span><span class="fu">,</span> </span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;errorMsg&quot;</span><span class="fu">:</span> <span class="st">&quot;水表不存在&quot;</span></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="ot">]</span></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.5.3" id="账单管理api接口"><span
class="header-section-number">1.5.3</span> 3.3 账单管理API接口</h3>
<h4 data-number="1.5.3.1" id="账单查询接口"><span
class="header-section-number">1.5.3.1</span> 3.3.1 账单查询接口</h4>
<p><strong>功能描述</strong>根据客户ID和查询条件查询账单信息。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>GET -
<strong>请求路径</strong><code>/admin-api/water/bill/page</code></p>
<p><strong>请求参数</strong> | 参数名 | 类型 | 必填 | 说明 | 示例 |
|——-|——|——|——|——| | pageNo | Integer | 否 | 页码默认1 | 1 | | pageSize
| Integer | 否 | 每页条数默认10 | 10 | | customerId | Long | 否 |
客户ID | 1 | | billMonth | String | 否 | 账期 | 2024-12 | | billStatus |
Integer | 否 | 账单状态 | 0 |</p>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb27"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;list&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">{</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billCode&quot;</span><span class="fu">:</span> <span class="st">&quot;B202412190001&quot;</span><span class="fu">,</span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billMonth&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12&quot;</span><span class="fu">,</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billDate&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12-19&quot;</span><span class="fu">,</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;waterUsage&quot;</span><span class="fu">:</span> <span class="fl">25.50</span><span class="fu">,</span></span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;waterFee&quot;</span><span class="fu">:</span> <span class="fl">76.50</span><span class="fu">,</span></span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;sewageFee&quot;</span><span class="fu">:</span> <span class="fl">15.30</span><span class="fu">,</span></span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;totalAmount&quot;</span><span class="fu">:</span> <span class="fl">91.80</span><span class="fu">,</span></span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paidAmount&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="er">.00</span><span class="fu">,</span></span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;balanceAmount&quot;</span><span class="fu">:</span> <span class="fl">91.80</span><span class="fu">,</span></span>
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;dueDate&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-19&quot;</span><span class="fu">,</span></span>
<span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billStatus&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span><span class="fu">,</span></span>
<span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;meterCode&quot;</span><span class="fu">:</span> <span class="st">&quot;M001&quot;</span></span>
<span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a> <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;total&quot;</span><span class="fu">:</span> <span class="dv">1</span></span>
<span id="cb27-24"><a href="#cb27-24" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb27-25"><a href="#cb27-25" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h4 data-number="1.5.3.2" id="账单生成接口"><span
class="header-section-number">1.5.3.2</span> 3.3.2 账单生成接口</h4>
<p><strong>功能描述</strong>:根据抄表记录生成水费账单。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/bill/generate</code></p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb28"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billMonth&quot;</span><span class="fu">:</span> <span class="st">&quot;2024-12&quot;</span><span class="fu">,</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerIds&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="dv">1</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;readingIds&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="dv">1</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;dueDate&quot;</span><span class="fu">:</span> <span class="st">&quot;2025-01-19&quot;</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb29"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;generateCount&quot;</span><span class="fu">:</span> <span class="dv">3</span><span class="fu">,</span></span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;successList&quot;</span><span class="fu">:</span> <span class="ot">[</span></span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">{</span></span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;totalAmount&quot;</span><span class="fu">:</span> <span class="fl">91.80</span></span>
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> <span class="ot">]</span><span class="fu">,</span></span>
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;failureList&quot;</span><span class="fu">:</span> <span class="ot">[]</span></span>
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Service层代码示例</strong></p>
<div class="sourceCode" id="cb30"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Service</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="at">@Validated</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> BillServiceImpl <span class="kw">implements</span> BillService <span class="op">{</span></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> BillMapper billMapper<span class="op">;</span></span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> MeterReadingService readingService<span class="op">;</span></span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> WaterPriceService priceService<span class="op">;</span></span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a> <span class="at">@Transactional</span><span class="op">(</span>rollbackFor <span class="op">=</span> <span class="bu">Exception</span><span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> BillGenerateRespVO <span class="fu">generateBills</span><span class="op">(</span>BillGenerateReqVO generateReqVO<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a> BillGenerateRespVO result <span class="op">=</span> <span class="kw">new</span> <span class="fu">BillGenerateRespVO</span><span class="op">();</span></span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a> <span class="bu">List</span><span class="op">&lt;</span>BillGenerateDetailVO<span class="op">&gt;</span> successList <span class="op">=</span> <span class="kw">new</span> <span class="bu">ArrayList</span><span class="op">&lt;&gt;();</span></span>
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a> <span class="bu">List</span><span class="op">&lt;</span>BillGenerateDetailVO<span class="op">&gt;</span> failureList <span class="op">=</span> <span class="kw">new</span> <span class="bu">ArrayList</span><span class="op">&lt;&gt;();</span></span>
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="bu">Long</span> readingId <span class="op">:</span> generateReqVO<span class="op">.</span><span class="fu">getReadingIds</span><span class="op">())</span> <span class="op">{</span></span>
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true" tabindex="-1"></a> <span class="co">// 获取抄表记录</span></span>
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true" tabindex="-1"></a> MeterReadingDO reading <span class="op">=</span> readingService<span class="op">.</span><span class="fu">getReading</span><span class="op">(</span>readingId<span class="op">);</span></span>
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true" tabindex="-1"></a> <span class="co">// 计算水费</span></span>
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a> WaterFeeCalculateDTO feeResult <span class="op">=</span> priceService<span class="op">.</span><span class="fu">calculateWaterFee</span><span class="op">(</span></span>
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a> reading<span class="op">.</span><span class="fu">getCustomerId</span><span class="op">(),</span> reading<span class="op">.</span><span class="fu">getWaterUsage</span><span class="op">());</span></span>
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a> <span class="co">// 创建账单</span></span>
<span id="cb30-29"><a href="#cb30-29" aria-hidden="true" tabindex="-1"></a> BillDO bill <span class="op">=</span> <span class="kw">new</span> <span class="fu">BillDO</span><span class="op">();</span></span>
<span id="cb30-30"><a href="#cb30-30" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setBillCode</span><span class="op">(</span><span class="fu">generateBillCode</span><span class="op">());</span></span>
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setBillMonth</span><span class="op">(</span>generateReqVO<span class="op">.</span><span class="fu">getBillMonth</span><span class="op">());</span></span>
<span id="cb30-32"><a href="#cb30-32" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setCustomerId</span><span class="op">(</span>reading<span class="op">.</span><span class="fu">getCustomerId</span><span class="op">());</span></span>
<span id="cb30-33"><a href="#cb30-33" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setMeterId</span><span class="op">(</span>reading<span class="op">.</span><span class="fu">getMeterId</span><span class="op">());</span></span>
<span id="cb30-34"><a href="#cb30-34" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setReadingId</span><span class="op">(</span>readingId<span class="op">);</span></span>
<span id="cb30-35"><a href="#cb30-35" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setWaterUsage</span><span class="op">(</span>reading<span class="op">.</span><span class="fu">getWaterUsage</span><span class="op">());</span></span>
<span id="cb30-36"><a href="#cb30-36" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setWaterFee</span><span class="op">(</span>feeResult<span class="op">.</span><span class="fu">getWaterFee</span><span class="op">());</span></span>
<span id="cb30-37"><a href="#cb30-37" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setSewageFee</span><span class="op">(</span>feeResult<span class="op">.</span><span class="fu">getSewageFee</span><span class="op">());</span></span>
<span id="cb30-38"><a href="#cb30-38" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setTotalAmount</span><span class="op">(</span>feeResult<span class="op">.</span><span class="fu">getTotalAmount</span><span class="op">());</span></span>
<span id="cb30-39"><a href="#cb30-39" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">setDueDate</span><span class="op">(</span>generateReqVO<span class="op">.</span><span class="fu">getDueDate</span><span class="op">());</span></span>
<span id="cb30-40"><a href="#cb30-40" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-41"><a href="#cb30-41" aria-hidden="true" tabindex="-1"></a> billMapper<span class="op">.</span><span class="fu">insert</span><span class="op">(</span>bill<span class="op">);</span></span>
<span id="cb30-42"><a href="#cb30-42" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-43"><a href="#cb30-43" aria-hidden="true" tabindex="-1"></a> successList<span class="op">.</span><span class="fu">add</span><span class="op">(</span><span class="fu">buildSuccessDetail</span><span class="op">(</span>reading<span class="op">.</span><span class="fu">getCustomerId</span><span class="op">(),</span> </span>
<span id="cb30-44"><a href="#cb30-44" aria-hidden="true" tabindex="-1"></a> bill<span class="op">.</span><span class="fu">getId</span><span class="op">(),</span> feeResult<span class="op">.</span><span class="fu">getTotalAmount</span><span class="op">()));</span></span>
<span id="cb30-45"><a href="#cb30-45" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-46"><a href="#cb30-46" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span><span class="bu">Exception</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-47"><a href="#cb30-47" aria-hidden="true" tabindex="-1"></a> failureList<span class="op">.</span><span class="fu">add</span><span class="op">(</span><span class="fu">buildFailureDetail</span><span class="op">(</span>readingId<span class="op">,</span> e<span class="op">.</span><span class="fu">getMessage</span><span class="op">()));</span></span>
<span id="cb30-48"><a href="#cb30-48" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb30-49"><a href="#cb30-49" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb30-50"><a href="#cb30-50" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb30-51"><a href="#cb30-51" aria-hidden="true" tabindex="-1"></a> result<span class="op">.</span><span class="fu">setGenerateCount</span><span class="op">(</span>successList<span class="op">.</span><span class="fu">size</span><span class="op">());</span></span>
<span id="cb30-52"><a href="#cb30-52" aria-hidden="true" tabindex="-1"></a> result<span class="op">.</span><span class="fu">setSuccessList</span><span class="op">(</span>successList<span class="op">);</span></span>
<span id="cb30-53"><a href="#cb30-53" aria-hidden="true" tabindex="-1"></a> result<span class="op">.</span><span class="fu">setFailureList</span><span class="op">(</span>failureList<span class="op">);</span></span>
<span id="cb30-54"><a href="#cb30-54" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result<span class="op">;</span></span>
<span id="cb30-55"><a href="#cb30-55" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb30-56"><a href="#cb30-56" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="1.5.4" id="缴费管理api接口"><span
class="header-section-number">1.5.4</span> 3.4 缴费管理API接口</h3>
<h4 data-number="1.5.4.1" id="缴费处理接口"><span
class="header-section-number">1.5.4.1</span> 3.4.1 缴费处理接口</h4>
<p><strong>功能描述</strong>:处理客户缴费操作。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/payment/create</code></p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb31"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billIds&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="dv">1</span><span class="ot">,</span> <span class="dv">2</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentType&quot;</span><span class="fu">:</span> <span class="st">&quot;NORMAL&quot;</span><span class="fu">,</span></span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentChannel&quot;</span><span class="fu">:</span> <span class="st">&quot;CASH&quot;</span><span class="fu">,</span></span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentAmount&quot;</span><span class="fu">:</span> <span class="fl">183.60</span><span class="fu">,</span></span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;actualAmount&quot;</span><span class="fu">:</span> <span class="fl">200.00</span><span class="fu">,</span></span>
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;operatorId&quot;</span><span class="fu">:</span> <span class="st">&quot;OP001&quot;</span><span class="fu">,</span></span>
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;outletCode&quot;</span><span class="fu">:</span> <span class="st">&quot;OUT001&quot;</span><span class="fu">,</span></span>
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;remark&quot;</span><span class="fu">:</span> <span class="st">&quot;现金缴费&quot;</span></span>
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb32"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentCode&quot;</span><span class="fu">:</span> <span class="st">&quot;P202412190001&quot;</span><span class="fu">,</span></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;changeAmount&quot;</span><span class="fu">:</span> <span class="fl">16.40</span><span class="fu">,</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;invoiceNo&quot;</span><span class="fu">:</span> <span class="st">&quot;INV20241219001&quot;</span></span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h4 data-number="1.5.4.2" id="在线支付接口"><span
class="header-section-number">1.5.4.2</span> 3.4.2 在线支付接口</h4>
<p><strong>功能描述</strong>:处理在线支付(微信、支付宝等)。</p>
<p><strong>接口详情</strong> - <strong>请求方式</strong>POST -
<strong>请求路径</strong><code>/admin-api/water/payment/online-pay</code></p>
<p><strong>请求参数</strong></p>
<div class="sourceCode" id="cb33"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerId&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;billIds&quot;</span><span class="fu">:</span> <span class="ot">[</span><span class="dv">1</span><span class="ot">]</span><span class="fu">,</span></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentChannel&quot;</span><span class="fu">:</span> <span class="st">&quot;WECHAT&quot;</span><span class="fu">,</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentAmount&quot;</span><span class="fu">:</span> <span class="fl">91.80</span><span class="fu">,</span></span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;returnUrl&quot;</span><span class="fu">:</span> <span class="st">&quot;https://water.example.com/payment/callback&quot;</span><span class="fu">,</span></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;notifyUrl&quot;</span><span class="fu">:</span> <span class="st">&quot;https://water.example.com/api/payment/notify&quot;</span></span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>响应参数</strong></p>
<div class="sourceCode" id="cb34"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;paymentCode&quot;</span><span class="fu">:</span> <span class="st">&quot;P202412190002&quot;</span><span class="fu">,</span></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;prepayId&quot;</span><span class="fu">:</span> <span class="st">&quot;wx20241219001234567890&quot;</span><span class="fu">,</span></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;payUrl&quot;</span><span class="fu">:</span> <span class="st">&quot;weixin://wxpay/bizpayurl?pr=abc123&quot;</span><span class="fu">,</span></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;qrCode&quot;</span><span class="fu">:</span> <span class="st">&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...&quot;</span></span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.5.5" id="工单接口"><span
class="header-section-number">1.5.5</span> 3.4 工单接口</h3>
<h4 data-number="1.5.5.1" id="工单创建接口"><span
class="header-section-number">1.5.5.1</span> 3.4.1 工单创建接口</h4>
<p><strong>功能描述</strong>:创建业务工单。</p>
<p><strong>接口规范</strong> - 请求方式POST -
请求路径:/api/workorders - 请求/返回格式JSON</p>
<h4 data-number="1.5.5.2" id="工单状态更新接口"><span
class="header-section-number">1.5.5.2</span> 3.4.2 工单状态更新接口</h4>
<p><strong>功能描述</strong>:更新工单处理状态。</p>
<p><strong>接口规范</strong> - 请求方式PUT -
请求路径:/api/workorders/{workorderId}/status - 请求/返回格式JSON</p>
<h2 data-number="1.6" id="接口标准"><span
class="header-section-number">1.6</span> 4. 接口标准</h2>
<h3 data-number="1.6.1" id="接口协议"><span
class="header-section-number">1.6.1</span> 4.1 接口协议</h3>
<p>系统接口主要采用以下协议:</p>
<ul>
<li><strong>RESTful
API</strong>:适用于系统内部模块间的交互以及移动应用等轻量级客户端</li>
<li><strong>WebService</strong>:适用于与外部系统的集成,特别是银行等传统机构</li>
<li><strong>消息队列</strong>:适用于异步处理的场景,如批量数据处理、通知推送等</li>
</ul>
<h3 data-number="1.6.2" id="数据格式"><span
class="header-section-number">1.6.2</span> 4.2 数据格式</h3>
<p>接口数据主要采用以下格式:</p>
<ul>
<li><strong>JSON</strong>主要用于RESTful
API接口结构简单清晰适合Web应用</li>
<li><strong>XML</strong>主要用于WebService接口兼容性好适合与传统系统对接</li>
<li><strong>文本文件</strong>:主要用于批量数据交换,如银行代扣文件等</li>
</ul>
<h3 data-number="1.6.3" id="接口安全设计"><span
class="header-section-number">1.6.3</span> 4.3 接口安全设计</h3>
<p>接口安全采用多层防护机制:</p>
<h4 data-number="1.6.3.1" id="认证机制"><span
class="header-section-number">1.6.3.1</span> 4.3.1 认证机制</h4>
<p><strong>JWT令牌认证</strong></p>
<div class="sourceCode" id="cb35"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="at">@RestController</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> AuthController <span class="op">{</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> AuthService authService<span class="op">;</span></span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@PostMapping</span><span class="op">(</span><span class="st">&quot;/admin-api/system/auth/login&quot;</span><span class="op">)</span></span>
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;</span>AuthLoginRespVO<span class="op">&gt;</span> <span class="fu">login</span><span class="op">(</span><span class="at">@Valid</span> <span class="at">@RequestBody</span> AuthLoginReqVO reqVO<span class="op">)</span> <span class="op">{</span></span>
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// 验证用户名密码</span></span>
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a> AdminUserDO user <span class="op">=</span> authService<span class="op">.</span><span class="fu">authenticate</span><span class="op">(</span>reqVO<span class="op">.</span><span class="fu">getUsername</span><span class="op">(),</span> reqVO<span class="op">.</span><span class="fu">getPassword</span><span class="op">());</span></span>
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// 生成JWT Token</span></span>
<span id="cb35-13"><a href="#cb35-13" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> token <span class="op">=</span> authService<span class="op">.</span><span class="fu">createToken</span><span class="op">(</span>user<span class="op">.</span><span class="fu">getId</span><span class="op">(),</span> user<span class="op">.</span><span class="fu">getTenantId</span><span class="op">());</span></span>
<span id="cb35-14"><a href="#cb35-14" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb35-15"><a href="#cb35-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="fu">success</span><span class="op">(</span>AuthLoginRespVO<span class="op">.</span><span class="fu">builder</span><span class="op">()</span></span>
<span id="cb35-16"><a href="#cb35-16" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">userId</span><span class="op">(</span>user<span class="op">.</span><span class="fu">getId</span><span class="op">())</span></span>
<span id="cb35-17"><a href="#cb35-17" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">accessToken</span><span class="op">(</span>token<span class="op">)</span></span>
<span id="cb35-18"><a href="#cb35-18" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">refreshToken</span><span class="op">(</span>authService<span class="op">.</span><span class="fu">createRefreshToken</span><span class="op">(</span>user<span class="op">.</span><span class="fu">getId</span><span class="op">()))</span></span>
<span id="cb35-19"><a href="#cb35-19" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">expiresTime</span><span class="op">(</span>LocalDateTime<span class="op">.</span><span class="fu">now</span><span class="op">().</span><span class="fu">plusHours</span><span class="op">(</span><span class="dv">2</span><span class="op">))</span></span>
<span id="cb35-20"><a href="#cb35-20" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span><span class="fu">build</span><span class="op">());</span></span>
<span id="cb35-21"><a href="#cb35-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb35-22"><a href="#cb35-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>API Key认证</strong>(外部系统):</p>
<div class="sourceCode" id="cb36"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Component</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> ApiKeyAuthenticationFilter <span class="kw">extends</span> OncePerRequestFilter <span class="op">{</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">doFilterInternal</span><span class="op">(</span>HttpServletRequest request<span class="op">,</span> </span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a> HttpServletResponse response<span class="op">,</span> </span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a> FilterChain filterChain<span class="op">)</span> <span class="kw">throws</span> ServletException<span class="op">,</span> <span class="bu">IOException</span> <span class="op">{</span></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> apiKey <span class="op">=</span> request<span class="op">.</span><span class="fu">getHeader</span><span class="op">(</span><span class="st">&quot;X-API-KEY&quot;</span><span class="op">);</span></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> timestamp <span class="op">=</span> request<span class="op">.</span><span class="fu">getHeader</span><span class="op">(</span><span class="st">&quot;X-TIMESTAMP&quot;</span><span class="op">);</span></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> signature <span class="op">=</span> request<span class="op">.</span><span class="fu">getHeader</span><span class="op">(</span><span class="st">&quot;X-SIGNATURE&quot;</span><span class="op">);</span></span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// 验证API Key</span></span>
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span>apiKeyService<span class="op">.</span><span class="fu">validateApiKey</span><span class="op">(</span>apiKey<span class="op">))</span> <span class="op">{</span></span>
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">writeErrorResponse</span><span class="op">(</span>response<span class="op">,</span> <span class="st">&quot;Invalid API Key&quot;</span><span class="op">);</span></span>
<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-18"><a href="#cb36-18" aria-hidden="true" tabindex="-1"></a> <span class="co">// 验证时间戳(防重放攻击)</span></span>
<span id="cb36-19"><a href="#cb36-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span><span class="fu">validateTimestamp</span><span class="op">(</span>timestamp<span class="op">))</span> <span class="op">{</span></span>
<span id="cb36-20"><a href="#cb36-20" aria-hidden="true" tabindex="-1"></a> <span class="fu">writeErrorResponse</span><span class="op">(</span>response<span class="op">,</span> <span class="st">&quot;Request expired&quot;</span><span class="op">);</span></span>
<span id="cb36-21"><a href="#cb36-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb36-22"><a href="#cb36-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb36-23"><a href="#cb36-23" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-24"><a href="#cb36-24" aria-hidden="true" tabindex="-1"></a> <span class="co">// 验证签名</span></span>
<span id="cb36-25"><a href="#cb36-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span><span class="fu">validateSignature</span><span class="op">(</span>request<span class="op">,</span> signature<span class="op">))</span> <span class="op">{</span></span>
<span id="cb36-26"><a href="#cb36-26" aria-hidden="true" tabindex="-1"></a> <span class="fu">writeErrorResponse</span><span class="op">(</span>response<span class="op">,</span> <span class="st">&quot;Invalid signature&quot;</span><span class="op">);</span></span>
<span id="cb36-27"><a href="#cb36-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb36-28"><a href="#cb36-28" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb36-29"><a href="#cb36-29" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb36-30"><a href="#cb36-30" aria-hidden="true" tabindex="-1"></a> filterChain<span class="op">.</span><span class="fu">doFilter</span><span class="op">(</span>request<span class="op">,</span> response<span class="op">);</span></span>
<span id="cb36-31"><a href="#cb36-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb36-32"><a href="#cb36-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.6.3.2" id="数据加密"><span
class="header-section-number">1.6.3.2</span> 4.3.2 数据加密</h4>
<p><strong>敏感数据加密</strong></p>
<div class="sourceCode" id="cb37"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Component</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> DataEncryptionService <span class="op">{</span></span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> <span class="dt">final</span> AESUtil aesUtil<span class="op">;</span></span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">encryptPersonalInfo</span><span class="op">(</span><span class="bu">String</span> plainText<span class="op">)</span> <span class="op">{</span></span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>StrUtil<span class="op">.</span><span class="fu">isBlank</span><span class="op">(</span>plainText<span class="op">))</span> <span class="op">{</span></span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> plainText<span class="op">;</span></span>
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> aesUtil<span class="op">.</span><span class="fu">encrypt</span><span class="op">(</span>plainText<span class="op">);</span></span>
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">decryptPersonalInfo</span><span class="op">(</span><span class="bu">String</span> cipherText<span class="op">)</span> <span class="op">{</span></span>
<span id="cb37-14"><a href="#cb37-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>StrUtil<span class="op">.</span><span class="fu">isBlank</span><span class="op">(</span>cipherText<span class="op">))</span> <span class="op">{</span></span>
<span id="cb37-15"><a href="#cb37-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> cipherText<span class="op">;</span></span>
<span id="cb37-16"><a href="#cb37-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb37-17"><a href="#cb37-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> aesUtil<span class="op">.</span><span class="fu">decrypt</span><span class="op">(</span>cipherText<span class="op">);</span></span>
<span id="cb37-18"><a href="#cb37-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb37-19"><a href="#cb37-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.6.3.3" id="访问控制"><span
class="header-section-number">1.6.3.3</span> 4.3.3 访问控制</h4>
<p><strong>IP白名单控制</strong></p>
<div class="sourceCode" id="cb38"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Component</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> IpWhitelistFilter <span class="kw">extends</span> OncePerRequestFilter <span class="op">{</span></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Value</span><span class="op">(</span><span class="st">&quot;${water.security.ip-whitelist}&quot;</span><span class="op">)</span></span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> <span class="bu">List</span><span class="op">&lt;</span><span class="bu">String</span><span class="op">&gt;</span> ipWhitelist<span class="op">;</span></span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a> <span class="at">@Override</span></span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">doFilterInternal</span><span class="op">(</span>HttpServletRequest request<span class="op">,</span> </span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a> HttpServletResponse response<span class="op">,</span> </span>
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a> FilterChain filterChain<span class="op">)</span> <span class="kw">throws</span> ServletException<span class="op">,</span> <span class="bu">IOException</span> <span class="op">{</span></span>
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> clientIp <span class="op">=</span> <span class="fu">getClientIpAddress</span><span class="op">(</span>request<span class="op">);</span></span>
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span><span class="fu">isIpAllowed</span><span class="op">(</span>clientIp<span class="op">))</span> <span class="op">{</span></span>
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a> response<span class="op">.</span><span class="fu">setStatus</span><span class="op">(</span>HttpStatus<span class="op">.</span><span class="fu">FORBIDDEN</span><span class="op">.</span><span class="fu">value</span><span class="op">());</span></span>
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true" tabindex="-1"></a> response<span class="op">.</span><span class="fu">getWriter</span><span class="op">().</span><span class="fu">write</span><span class="op">(</span><span class="st">&quot;{</span><span class="sc">\&quot;</span><span class="st">code</span><span class="sc">\&quot;</span><span class="st">:403,</span><span class="sc">\&quot;</span><span class="st">msg</span><span class="sc">\&quot;</span><span class="st">:</span><span class="sc">\&quot;</span><span class="st">IP access denied</span><span class="sc">\&quot;</span><span class="st">}&quot;</span><span class="op">);</span></span>
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb38-19"><a href="#cb38-19" aria-hidden="true" tabindex="-1"></a> filterChain<span class="op">.</span><span class="fu">doFilter</span><span class="op">(</span>request<span class="op">,</span> response<span class="op">);</span></span>
<span id="cb38-20"><a href="#cb38-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb38-21"><a href="#cb38-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.6.3.4" id="接口限流"><span
class="header-section-number">1.6.3.4</span> 4.3.4 接口限流</h4>
<p><strong>基于Redis的令牌桶限流</strong></p>
<div class="sourceCode" id="cb39"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="at">@Component</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> RateLimitService <span class="op">{</span></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@Resource</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">private</span> StringRedisTemplate redisTemplate<span class="op">;</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">boolean</span> <span class="fu">allowRequest</span><span class="op">(</span><span class="bu">String</span> key<span class="op">,</span> <span class="dt">int</span> maxRequests<span class="op">,</span> <span class="bu">Duration</span> window<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> redisKey <span class="op">=</span> <span class="st">&quot;rate_limit:&quot;</span> <span class="op">+</span> key<span class="op">;</span></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> script <span class="op">=</span> <span class="st">&quot;&quot;&quot;</span></span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="st"> local key = KEYS[1]</span></span>
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a><span class="st"> local window = tonumber(ARGV[1])</span></span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a><span class="st"> local limit = tonumber(ARGV[2])</span></span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a><span class="st"> local current = redis.call(&#39;get&#39;, key)</span></span>
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a><span class="st"> if current == false then</span></span>
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a><span class="st"> redis.call(&#39;setex&#39;, key, window, 1)</span></span>
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a><span class="st"> return 1</span></span>
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a><span class="st"> end</span></span>
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a><span class="st"> if tonumber(current) &lt; limit then</span></span>
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a><span class="st"> return redis.call(&#39;incr&#39;, key)</span></span>
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true" tabindex="-1"></a><span class="st"> else</span></span>
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true" tabindex="-1"></a><span class="st"> return 0</span></span>
<span id="cb39-22"><a href="#cb39-22" aria-hidden="true" tabindex="-1"></a><span class="st"> end</span></span>
<span id="cb39-23"><a href="#cb39-23" aria-hidden="true" tabindex="-1"></a><span class="st"> &quot;&quot;&quot;</span><span class="op">;</span></span>
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb39-25"><a href="#cb39-25" aria-hidden="true" tabindex="-1"></a> DefaultRedisScript<span class="op">&lt;</span><span class="bu">Long</span><span class="op">&gt;</span> redisScript <span class="op">=</span> <span class="kw">new</span> DefaultRedisScript<span class="op">&lt;&gt;(</span>script<span class="op">,</span> <span class="bu">Long</span><span class="op">.</span><span class="fu">class</span><span class="op">);</span></span>
<span id="cb39-26"><a href="#cb39-26" aria-hidden="true" tabindex="-1"></a> <span class="bu">Long</span> result <span class="op">=</span> redisTemplate<span class="op">.</span><span class="fu">execute</span><span class="op">(</span>redisScript<span class="op">,</span> </span>
<span id="cb39-27"><a href="#cb39-27" aria-hidden="true" tabindex="-1"></a> <span class="bu">Collections</span><span class="op">.</span><span class="fu">singletonList</span><span class="op">(</span>redisKey<span class="op">),</span> </span>
<span id="cb39-28"><a href="#cb39-28" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span><span class="op">.</span><span class="fu">valueOf</span><span class="op">(</span>window<span class="op">.</span><span class="fu">getSeconds</span><span class="op">()),</span></span>
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span><span class="op">.</span><span class="fu">valueOf</span><span class="op">(</span>maxRequests<span class="op">));</span></span>
<span id="cb39-30"><a href="#cb39-30" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb39-31"><a href="#cb39-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result <span class="op">!=</span> <span class="kw">null</span> <span class="op">&amp;&amp;</span> result <span class="op">&gt;</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb39-32"><a href="#cb39-32" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb39-33"><a href="#cb39-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="1.6.4" id="错误处理机制"><span
class="header-section-number">1.6.4</span> 4.4 错误处理机制</h3>
<h4 data-number="1.6.4.1" id="统一异常处理"><span
class="header-section-number">1.6.4.1</span> 4.4.1 统一异常处理</h4>
<div class="sourceCode" id="cb40"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="at">@RestControllerAdvice</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">class</span> GlobalExceptionHandler <span class="op">{</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a> <span class="at">@ExceptionHandler</span><span class="op">(</span>ServiceException<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;?&gt;</span> <span class="fu">serviceExceptionHandler</span><span class="op">(</span>ServiceException ex<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">info</span><span class="op">(</span><span class="st">&quot;[serviceExceptionHandler]&quot;</span><span class="op">,</span> ex<span class="op">);</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> CommonResult<span class="op">.</span><span class="fu">error</span><span class="op">(</span>ex<span class="op">.</span><span class="fu">getCode</span><span class="op">(),</span> ex<span class="op">.</span><span class="fu">getMessage</span><span class="op">());</span></span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="at">@ExceptionHandler</span><span class="op">(</span>ConstraintViolationException<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;?&gt;</span> <span class="fu">constraintViolationExceptionHandler</span><span class="op">(</span>ConstraintViolationException ex<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">info</span><span class="op">(</span><span class="st">&quot;[constraintViolationExceptionHandler]&quot;</span><span class="op">,</span> ex<span class="op">);</span></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> CommonResult<span class="op">.</span><span class="fu">error</span><span class="op">(</span>BAD_REQUEST<span class="op">.</span><span class="fu">getCode</span><span class="op">(),</span> <span class="st">&quot;请求参数不正确:&quot;</span> <span class="op">+</span> ex<span class="op">.</span><span class="fu">getMessage</span><span class="op">());</span></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a> <span class="at">@ExceptionHandler</span><span class="op">(</span>MethodArgumentNotValidException<span class="op">.</span><span class="fu">class</span><span class="op">)</span></span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> CommonResult<span class="op">&lt;?&gt;</span> <span class="fu">methodArgumentNotValidExceptionHandler</span><span class="op">(</span>MethodArgumentNotValidException ex<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a> log<span class="op">.</span><span class="fu">info</span><span class="op">(</span><span class="st">&quot;[methodArgumentNotValidExceptionHandler]&quot;</span><span class="op">,</span> ex<span class="op">);</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a> FieldError fieldError <span class="op">=</span> ex<span class="op">.</span><span class="fu">getBindingResult</span><span class="op">().</span><span class="fu">getFieldError</span><span class="op">();</span></span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> fieldError <span class="op">!=</span> <span class="kw">null</span><span class="op">;</span></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> CommonResult<span class="op">.</span><span class="fu">error</span><span class="op">(</span>BAD_REQUEST<span class="op">.</span><span class="fu">getCode</span><span class="op">(),</span> <span class="st">&quot;请求参数不正确:&quot;</span> <span class="op">+</span> fieldError<span class="op">.</span><span class="fu">getDefaultMessage</span><span class="op">());</span></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.6.4.2" id="错误码定义"><span
class="header-section-number">1.6.4.2</span> 4.4.2 错误码定义</h4>
<div class="sourceCode" id="cb41"><pre
class="sourceCode java"><code class="sourceCode java"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">interface</span> ErrorCodeConstants <span class="op">{</span></span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ========== 通用错误码 1-000-000-000 ==========</span></span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> ErrorCode SUCCESS <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">0</span><span class="op">,</span> <span class="st">&quot;成功&quot;</span><span class="op">);</span></span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> ErrorCode BAD_REQUEST <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">400</span><span class="op">,</span> <span class="st">&quot;请求参数不正确&quot;</span><span class="op">);</span></span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a> ErrorCode UNAUTHORIZED <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">401</span><span class="op">,</span> <span class="st">&quot;账号未登录&quot;</span><span class="op">);</span></span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a> ErrorCode FORBIDDEN <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">403</span><span class="op">,</span> <span class="st">&quot;没有该操作权限&quot;</span><span class="op">);</span></span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a> ErrorCode NOT_FOUND <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">404</span><span class="op">,</span> <span class="st">&quot;请求未找到&quot;</span><span class="op">);</span></span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a> ErrorCode METHOD_NOT_ALLOWED <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">405</span><span class="op">,</span> <span class="st">&quot;请求方法不正确&quot;</span><span class="op">);</span></span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a> ErrorCode INTERNAL_SERVER_ERROR <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">500</span><span class="op">,</span> <span class="st">&quot;系统异常&quot;</span><span class="op">);</span></span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// ========== 客户管理错误码 1-001-000-000 ==========</span></span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a> ErrorCode CUSTOMER_NOT_EXISTS <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_001_000_001</span><span class="op">,</span> <span class="st">&quot;客户不存在&quot;</span><span class="op">);</span></span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a> ErrorCode CUSTOMER_CODE_DUPLICATE <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_001_000_002</span><span class="op">,</span> <span class="st">&quot;客户编号已存在&quot;</span><span class="op">);</span></span>
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true" tabindex="-1"></a> ErrorCode CUSTOMER_STATUS_INVALID <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_001_000_003</span><span class="op">,</span> <span class="st">&quot;客户状态不正确&quot;</span><span class="op">);</span></span>
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// ========== 水表管理错误码 1-002-000-000 ==========</span></span>
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true" tabindex="-1"></a> ErrorCode METER_NOT_EXISTS <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_002_000_001</span><span class="op">,</span> <span class="st">&quot;水表不存在&quot;</span><span class="op">);</span></span>
<span id="cb41-19"><a href="#cb41-19" aria-hidden="true" tabindex="-1"></a> ErrorCode METER_CODE_DUPLICATE <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_002_000_002</span><span class="op">,</span> <span class="st">&quot;水表编号已存在&quot;</span><span class="op">);</span></span>
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a> ErrorCode METER_READING_INVALID <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_002_000_003</span><span class="op">,</span> <span class="st">&quot;水表读数不正确&quot;</span><span class="op">);</span></span>
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true" tabindex="-1"></a> <span class="co">// ========== 账单管理错误码 1-003-000-000 ==========</span></span>
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true" tabindex="-1"></a> ErrorCode BILL_NOT_EXISTS <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_003_000_001</span><span class="op">,</span> <span class="st">&quot;账单不存在&quot;</span><span class="op">);</span></span>
<span id="cb41-24"><a href="#cb41-24" aria-hidden="true" tabindex="-1"></a> ErrorCode BILL_ALREADY_PAID <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_003_000_002</span><span class="op">,</span> <span class="st">&quot;账单已缴费&quot;</span><span class="op">);</span></span>
<span id="cb41-25"><a href="#cb41-25" aria-hidden="true" tabindex="-1"></a> ErrorCode BILL_AMOUNT_INVALID <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_003_000_003</span><span class="op">,</span> <span class="st">&quot;账单金额不正确&quot;</span><span class="op">);</span></span>
<span id="cb41-26"><a href="#cb41-26" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb41-27"><a href="#cb41-27" aria-hidden="true" tabindex="-1"></a> <span class="co">// ========== 缴费管理错误码 1-004-000-000 ==========</span></span>
<span id="cb41-28"><a href="#cb41-28" aria-hidden="true" tabindex="-1"></a> ErrorCode PAYMENT_FAILED <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_004_000_001</span><span class="op">,</span> <span class="st">&quot;缴费失败&quot;</span><span class="op">);</span></span>
<span id="cb41-29"><a href="#cb41-29" aria-hidden="true" tabindex="-1"></a> ErrorCode PAYMENT_AMOUNT_INSUFFICIENT <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_004_000_002</span><span class="op">,</span> <span class="st">&quot;缴费金额不足&quot;</span><span class="op">);</span></span>
<span id="cb41-30"><a href="#cb41-30" aria-hidden="true" tabindex="-1"></a> ErrorCode PAYMENT_CHANNEL_UNAVAILABLE <span class="op">=</span> <span class="kw">new</span> <span class="fu">ErrorCode</span><span class="op">(</span><span class="dv">1_004_000_003</span><span class="op">,</span> <span class="st">&quot;缴费渠道不可用&quot;</span><span class="op">);</span></span>
<span id="cb41-31"><a href="#cb41-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 data-number="1.6.4.3" id="接口调用示例"><span
class="header-section-number">1.6.4.3</span> 4.4.3 接口调用示例</h4>
<p><strong>成功响应示例</strong></p>
<div class="sourceCode" id="cb42"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">0</span><span class="fu">,</span></span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;操作成功&quot;</span><span class="fu">,</span></span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="fu">{</span></span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;id&quot;</span><span class="fu">:</span> <span class="dv">1</span><span class="fu">,</span></span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;customerName&quot;</span><span class="fu">:</span> <span class="st">&quot;张三&quot;</span></span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">}</span></span>
<span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>失败响应示例</strong></p>
<div class="sourceCode" id="cb43"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;code&quot;</span><span class="fu">:</span> <span class="dv">1001000001</span><span class="fu">,</span></span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;msg&quot;</span><span class="fu">:</span> <span class="st">&quot;客户不存在&quot;</span><span class="fu">,</span></span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;data&quot;</span><span class="fu">:</span> <span class="kw">null</span></span>
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<h3 data-number="1.6.5" id="前端接口调用示例"><span
class="header-section-number">1.6.5</span> 4.5 前端接口调用示例</h3>
<h4 data-number="1.6.5.1" id="vue3-typescript接口封装"><span
class="header-section-number">1.6.5.1</span> 4.5.1 Vue3 +
TypeScript接口封装</h4>
<div class="sourceCode" id="cb44"><pre
class="sourceCode typescript"><code class="sourceCode typescript"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="co">// api/water/customer.ts</span></span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> { request } <span class="im">from</span> <span class="st">&#39;@/utils/request&#39;</span></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">interface</span> CustomerVO {</span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a> id<span class="op">:</span> <span class="dt">number</span></span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a> customerCode<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a> customerName<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a> customerType<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a> phone<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a> address<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a> status<span class="op">:</span> <span class="dt">number</span></span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a> createTime<span class="op">:</span> <span class="dt">string</span></span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">interface</span> CustomerPageReqVO <span class="kw">extends</span> PageParam {</span>
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a> customerName<span class="op">?:</span> <span class="dt">string</span></span>
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a> customerCode<span class="op">?:</span> <span class="dt">string</span></span>
<span id="cb44-18"><a href="#cb44-18" aria-hidden="true" tabindex="-1"></a> customerType<span class="op">?:</span> <span class="dt">string</span></span>
<span id="cb44-19"><a href="#cb44-19" aria-hidden="true" tabindex="-1"></a> phone<span class="op">?:</span> <span class="dt">string</span></span>
<span id="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb44-21"><a href="#cb44-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-22"><a href="#cb44-22" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">const</span> CustomerApi <span class="op">=</span> {</span>
<span id="cb44-23"><a href="#cb44-23" aria-hidden="true" tabindex="-1"></a> <span class="co">// 获取客户分页</span></span>
<span id="cb44-24"><a href="#cb44-24" aria-hidden="true" tabindex="-1"></a> getCustomerPage<span class="op">:</span> (params<span class="op">:</span> CustomerPageReqVO) <span class="kw">=&gt;</span> {</span>
<span id="cb44-25"><a href="#cb44-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> request<span class="op">.</span><span class="fu">get</span><span class="op">&lt;</span>PageResult<span class="op">&lt;</span>CustomerVO<span class="op">&gt;&gt;</span>({ url<span class="op">:</span> <span class="st">&#39;/water/customer/page&#39;</span><span class="op">,</span> params })</span>
<span id="cb44-26"><a href="#cb44-26" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
<span id="cb44-27"><a href="#cb44-27" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb44-28"><a href="#cb44-28" aria-hidden="true" tabindex="-1"></a> <span class="co">// 获取客户详情</span></span>
<span id="cb44-29"><a href="#cb44-29" aria-hidden="true" tabindex="-1"></a> getCustomer<span class="op">:</span> (id<span class="op">:</span> <span class="dt">number</span>) <span class="kw">=&gt;</span> {</span>
<span id="cb44-30"><a href="#cb44-30" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> request<span class="op">.</span><span class="fu">get</span><span class="op">&lt;</span>CustomerVO<span class="op">&gt;</span>({ url<span class="op">:</span> <span class="vs">`/water/customer/</span><span class="sc">${</span>id<span class="sc">}</span><span class="vs">`</span> })</span>
<span id="cb44-31"><a href="#cb44-31" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
<span id="cb44-32"><a href="#cb44-32" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb44-33"><a href="#cb44-33" aria-hidden="true" tabindex="-1"></a> <span class="co">// 创建客户</span></span>
<span id="cb44-34"><a href="#cb44-34" aria-hidden="true" tabindex="-1"></a> createCustomer<span class="op">:</span> (data<span class="op">:</span> CustomerSaveReqVO) <span class="kw">=&gt;</span> {</span>
<span id="cb44-35"><a href="#cb44-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> request<span class="op">.</span><span class="fu">post</span><span class="op">&lt;</span><span class="dt">number</span><span class="op">&gt;</span>({ url<span class="op">:</span> <span class="st">&#39;/water/customer/create&#39;</span><span class="op">,</span> data })</span>
<span id="cb44-36"><a href="#cb44-36" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
<span id="cb44-37"><a href="#cb44-37" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb44-38"><a href="#cb44-38" aria-hidden="true" tabindex="-1"></a> <span class="co">// 更新客户</span></span>
<span id="cb44-39"><a href="#cb44-39" aria-hidden="true" tabindex="-1"></a> updateCustomer<span class="op">:</span> (data<span class="op">:</span> CustomerSaveReqVO) <span class="kw">=&gt;</span> {</span>
<span id="cb44-40"><a href="#cb44-40" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> request<span class="op">.</span><span class="fu">put</span><span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span>({ url<span class="op">:</span> <span class="st">&#39;/water/customer/update&#39;</span><span class="op">,</span> data })</span>
<span id="cb44-41"><a href="#cb44-41" aria-hidden="true" tabindex="-1"></a> }<span class="op">,</span></span>
<span id="cb44-42"><a href="#cb44-42" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb44-43"><a href="#cb44-43" aria-hidden="true" tabindex="-1"></a> <span class="co">// 删除客户</span></span>
<span id="cb44-44"><a href="#cb44-44" aria-hidden="true" tabindex="-1"></a> deleteCustomer<span class="op">:</span> (id<span class="op">:</span> <span class="dt">number</span>) <span class="kw">=&gt;</span> {</span>
<span id="cb44-45"><a href="#cb44-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> request<span class="op">.</span><span class="fu">delete</span><span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span>({ url<span class="op">:</span> <span class="vs">`/water/customer/delete?id=</span><span class="sc">${</span>id<span class="sc">}</span><span class="vs">`</span> })</span>
<span id="cb44-46"><a href="#cb44-46" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb44-47"><a href="#cb44-47" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<h4 data-number="1.6.5.2" id="vue组件使用示例"><span
class="header-section-number">1.6.5.2</span> 4.5.2 Vue组件使用示例</h4>
```vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { CustomerApi, CustomerVO } from '@/api/water/customer'
import { formatDate } from '@/utils/formatTime'
const customerList = ref<CustomerVO[]>([])
const loading = ref(true)
const total = ref(0)
const queryParams = ref({
pageNo: 1,
pageSize: 10,
customerName: '',
customerCode: ''
})
const getCustomerList = async () => {
loading.value = true
try {
const data = await CustomerApi.getCustomerPage(queryParams.value)
customerList.value = data.list
total.value = data.total
} catch (error) {
console.error('获取客户列表失败:', error)
} finally {
loading.value = false
}
}
const handleQuery = () => {
queryParams.value.pageNo = 1
getCustomerList()
}
const handleReset = () => {
queryParams.value = {
pageNo: 1,
pageSize: 10,
customerName: '',
customerCode: ''
}
getCustomerList()
}
onMounted(() => {
getCustomerList()
})
</script>
<template>
<div class="app-container">
<pre><code>&lt;!-- 查询表单 --&gt;
&lt;el-form :model=&quot;queryParams&quot; ref=&quot;queryFormRef&quot; inline&gt;
&lt;el-form-item label=&quot;客户名称&quot; prop=&quot;customerName&quot;&gt;
&lt;el-input v-model=&quot;queryParams.customerName&quot; placeholder=&quot;请输入客户名称&quot; /&gt;
&lt;/el-form-item&gt;
&lt;el-form-item label=&quot;客户编号&quot; prop=&quot;customerCode&quot;&gt;
&lt;el-input v-model=&quot;queryParams.customerCode&quot; placeholder=&quot;请输入客户编号&quot; /&gt;
&lt;/el-form-item&gt;
&lt;el-form-item&gt;
&lt;el-button type=&quot;primary&quot; @click=&quot;handleQuery&quot;&gt;搜索&lt;/el-button&gt;
&lt;el-button @click=&quot;handleReset&quot;&gt;重置&lt;/el-button&gt;
&lt;/el-form-item&gt;
&lt;/el-form&gt;
&lt;!-- 数据表格 --&gt;
&lt;el-table v-loading=&quot;loading&quot; :data=&quot;customerList&quot;&gt;
&lt;el-table-column label=&quot;客户编号&quot; prop=&quot;customerCode&quot; /&gt;
&lt;el-table-column label=&quot;客户名称&quot; prop=&quot;customerName&quot; /&gt;
&lt;el-table-column label=&quot;联系电话&quot; prop=&quot;phone&quot; /&gt;
&lt;el-table-column label=&quot;创建时间&quot; prop=&quot;createTime&quot; :formatter=&quot;formatDate&quot; /&gt;
&lt;/el-table&gt;
&lt;!-- 分页组件 --&gt;
&lt;Pagination
:total=&quot;total&quot;
v-model:page=&quot;queryParams.pageNo&quot;
v-model:limit=&quot;queryParams.pageSize&quot;
@pagination=&quot;getCustomerList&quot;
/&gt;</code></pre>
</div>
<p></template></p>
</body>
</html>