diff --git a/DOC_TOOLKIT_GUIDE.md b/DOC_TOOLKIT_GUIDE.md index 9bf39c8..5467f30 100644 --- a/DOC_TOOLKIT_GUIDE.md +++ b/DOC_TOOLKIT_GUIDE.md @@ -210,7 +210,7 @@ make generate-sequence ### 6.1 文件命名规范 -``` +```text water_biz_[模块名]_design.md # 模块设计文档 water_biz_database_design.md # 数据库设计文档 water_biz_interface_design.md # 接口设计文档 @@ -245,15 +245,14 @@ water_biz_deployment_design.md # 部署设计文档 必须使用 Mermaid 语法: -```markdown -# 架构图 +**架构图示例**: ```mermaid graph TD A[前端] --> B[后端] B --> C[数据库] ``` -# ER图 +**ER图示例**: ```mermaid erDiagram USER ||--o{ ORDER : places @@ -262,7 +261,6 @@ erDiagram string name } ``` -``` ## 七、常见问题 diff --git a/QUICK_START.md b/QUICK_START.md index 4601dd5..e01c7f8 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -10,7 +10,7 @@ cat project_progress.md ``` 预期输出: -``` +```text 项目进度跟踪信息,包含各文档完成状态 ``` @@ -22,7 +22,7 @@ cat task_checklist.md ``` 预期输出: -``` +```text 当前阶段的所有待完成任务,包含优先级和状态 ``` diff --git a/output/merged_docs.md b/output/merged_docs.md index 759613c..32ba807 100644 --- a/output/merged_docs.md +++ b/output/merged_docs.md @@ -893,7 +893,7 @@ graph TB ``` **项目结构设计:** -``` +```text yudao-ui-admin-vue3/ ├── public/ # 静态资源 ├── src/ @@ -1014,7 +1014,7 @@ graph TB ``` **移动端项目结构:** -``` +```text water-mobile-app/ ├── pages/ # 页面目录 │ ├── index/ # 首页 diff --git a/output/福建水务营收系统概要设计文档.docx b/output/福建水务营收系统概要设计文档.docx index a4f5c58..90f576e 100644 Binary files a/output/福建水务营收系统概要设计文档.docx and b/output/福建水务营收系统概要设计文档.docx differ diff --git a/output/福建水务营收系统概要设计文档.html b/output/福建水务营收系统概要设计文档.html index 25c9ba7..44968b4 100644 --- a/output/福建水务营收系统概要设计文档.html +++ b/output/福建水务营收系统概要设计文档.html @@ -146,503 +146,378 @@ margin: 20px 0;
2025年06月09日
福建水务营收系统是基于RuoYi-Vue-Pro和yudao-ui-admin-vue3框架开发的一套现代化水务营收管理系统,旨在满足原有系统的所有功能需求,并通过技术升级提升系统的性能、安全性和用户体验。
-对于多人协作编写文档,建议按照以下方式进行分工:
-每个功能模块的设计文档应包含以下内容:
-# [模块名称]设计说明
-
-## 1. 功能概述
-[简要描述该模块的主要功能和目标]
-
-## 2. 功能列表
-[列出该模块包含的所有功能点]
-
-## 3. 业务流程
-[使用流程图描述主要业务流程]
-
-## 4. 数据模型
-[描述该模块涉及的主要数据实体及关系]
-
-## 5. 接口设计
-[描述该模块提供的接口,包括参数、返回值等]
-
-## 6. 界面设计
-[提供界面原型或描述,说明界面交互逻辑]
-
-## 7. 安全考虑
-[描述该模块的安全控制措施]
-
-## 8. 特殊说明
-[其他需要说明的事项]为了使用Cursor更高效地完成概要设计文档,建议配置以下规则:
-最终交付物应包括:
-福建水务营收系统概要设计文档包含以下几个主要部分:
-设计计划文档明确了概要设计文档的编写计划、时间规划、人员分工和文档规范,为后续设计工作提供了指导框架。主要内容包括:
-系统架构设计描述了福建水务营收系统的总体架构、技术框架和实现方案,为系统开发提供了技术指导。主要内容包括:
-模块功能设计详细描述了系统各个功能模块的设计,包括功能需求、业务流程、实现方式等。主要内容包括:
-数据库设计描述了系统的数据模型、表结构和数据库优化策略,为数据存储和管理提供了技术方案。主要内容包括:
-接口设计描述了系统内部模块间的接口和与外部系统的集成接口,为系统集成提供了技术方案。主要内容包括:
-部署运维设计描述了系统的部署架构、运维方案和灾备策略,为系统运行维护提供了技术支持。主要内容包括:
-| 项目信息 | +详情 | +
|---|---|
| 项目名称 | +福建水务营收系统 | +
| 文档类型 | +概要设计文档 | +
| 技术框架 | +RuoYi-Vue-Pro + yudao-ui-admin-vue3 | +
| 文档版本 | +v1.0 | +
| 编写日期 | +2024-12-19 | +
| 文档状态 | +✅ 基本完成 | +
福建水投集团注册资本46亿元,经营范围为水利项目投资及管理,水利工程建筑设计与施工及相关技术服务;水资源开发与利用,水的生产与供应、污水处理及其再生利用,水生态产业投资、运营及相关配套服务;水利设施周边配套土地等资源综合开发利用等。
-在全省40多个县市区投资重大水利项目超过450亿元,实现全省全覆盖,大幅控制我省岛屿、沿海经济发达以及经济发展潜力大、后劲足的地区水资源、水务市场。目前,集团公司总资产超173亿元,净资产超70亿元,拥有全级次子公司超过67家,职工人数超3500人。
-当前,福建水投集团针对营收、新装、表务等核心业务系统,在集团下属各水务公司中,在用的业务系统均来自不同的系统集成商,存在业务不统一、软件功能不完善、自动化数据处理水平低、升级维护工作量大、自建硬件环境导致运营成本过高等弊端,加上由于业务、数据过度分散,不利于集团化的集中管理、统一资源管理理念。
-随着互联网技术的飞速发展,以及市场竞争日益激烈的今天,集中企业优势、发展企业已成社会共识。通过应用系统集中部署,可以在此基础上实现先进的集团化管理理念。目前集团已经搭建起私有云,需要在信息系统建设方面,统一构建SaaS模式服务平台,服务于集团、各分公司、营业网点,以便于实现集中式生产控制、集中式财务控制、集中物资管理、公司领导对下属各水务公司的集中管理和综合报表上报、分析的功能。
-福建水务业务系统是以客户关系数据库为核心和基础的综合管理平台,包含客户完整的资料和数据,实现客户全生命周期管理。系统建设的主要目标包括:
-统一资源服务:在集团现有基础上,建设统一的数字水务系统运行资源环境,为集团下属各分公司提供日常业务的IT运营环境服务。
统一平台应用:根据业务需要,在集团所属分公司在用的营收、新装、表务系统基础上进行全面改造升级,统一业务,集中汇集数据,形成统一、多租户管理模式的营业收费系统。集团所属各分公司不再独立建设业务系统基础设施和开发应用系统,实现”一个业务平台、一网通平台”的建设目标。
统一业务平台功能:建设平台具备集团、分公司、分公司所属业务站点多租户管理模式,实现对用水客户的营收业务、新装业务、表务业务管理功能;各租户之间独立,数据统一汇总到集团数据中心。
统一对外接口:整合统一用户资源,与相关业务系统对接提供标准的接口和能力。
统一对外服务:统一对外服务标准,为百姓提供便民服务,做到从”群众跑路”到”数据跑腿”的转变,简化百姓办事流程、提高办事效率、提升百姓的获得感,塑造良好的企业形象。
通过系统的建设,实现福建省水投数字科技有限公司客户服务管理领域的业务流程梳理再造、组织架构的优化、管理制度的建设、绩效考核标准的建设。构建以客户为中心的客户服务平台,将客户的所有信息进行有机的关联,方便企业对客户信息进行综合分析和管理,为客户提供更多、更便捷、更主动的个性化服务,提高客户服务的质量和客户满意度。
-福建水务业务系统的功能范围涵盖客户服务全生命周期,主要包括以下功能模块:
-统一平台:员工管理、权限管理、组织机构、系统菜单配置、角色配置、水表厂家、水表型号、水表量程等。
营收系统:
-表务系统:
-报装系统:
-客户服务:
-外部接口:
-福建水务业务系统的用户主要包括以下几类:
-集团管理人员:负责对全集团业务数据进行统计分析、监督管理。
分公司管理人员:负责分公司业务管理、数据统计分析。
营业网点工作人员:负责日常营业收费、客户服务等工作。
抄表员:负责水表抄读、录入等工作。
表务人员:负责水表安装、更换、维修等工作。
报装人员:负责新用户报装、立户等工作。
系统管理员:负责系统参数配置、用户权限管理等工作。
最终用户:通过微信、支付宝服务窗、微网厅等渠道使用系统服务的水务客户。
福建水务业务系统具有以下特点:
-多租户架构:支持集团、分公司、营业站点多层级租户管理模式,各租户数据相互隔离,同时数据可统一汇总到集团数据中心。
一体化设计:将营收、表务、报装等业务系统集成为一体,实现业务流程的无缝衔接。
全渠道服务:支持营业厅柜台、自助终端、移动APP、微信小程序、支付宝服务窗等多种服务渠道。
智能化应用:引入智能抄表、智能分析等功能,提高业务处理效率和准确性。
标准化接口:提供标准化的接口,支持与银行、支付平台、短信平台等外部系统的集成。
安全可靠:系统满足安全等保三级要求,确保系统和数据的安全性。
高性能扩展:系统支持100万客户规模,满足企业未来3-5年的业务发展需求。
福建水务业务系统的建设将为企业带来以下价值:
-降低IT成本:通过统一平台建设,减少重复投资,降低硬件采购、系统运维等成本。
提高管理效率:实现业务流程优化再造,提高业务处理效率,降低人力成本。
增强数据价值:实现数据的集中管理和统一分析,为管理决策提供有力支持。
提升服务质量:为客户提供便捷、多渠道的服务方式,提高客户满意度。
支持业务创新:为业务创新提供灵活的技术支持,增强企业市场竞争力。
福建水务业务系统采用多层架构设计,旨在支持集团化的集中管理、统一资源管理的业务需求。系统架构的设计目标是实现”一个业务平台、一网通平台”的建设目标,为集团及下属各分公司提供统一的营业收费系统。
+福建水务营收系统采用多层架构设计,旨在支持集团化的集中管理、统一资源管理的业务需求。系统架构的设计目标是实现”一个业务平台、一网通平台”的建设目标,为集团及下属各分公司提供统一的营业收费系统。
系统架构主要包括以下核心特点: - 多租户架构:支持集团、分公司、营业站点的多层级租户管理模式 - 统一资源服务:统一的数字水务系统运行资源环境 - 统一平台应用:统一业务流程,集中汇集数据 - 统一对外接口:提供标准的接口和能力
-系统整体架构如下图所示:
-graph TB
+ subgraph "用户层"
+ A1[Web管理端<br/>yudao-ui-admin-vue3]
+ A2[移动抄表端<br/>uni-app]
+ A3[客户微信端<br/>微信小程序]
+ A4[客户支付宝端<br/>支付宝小程序]
+ end
+
+ subgraph "网关层"
+ B1[Nginx负载均衡]
+ B2[API网关<br/>统一认证/权限控制]
+ end
+
+ subgraph "应用层"
+ C1[营收管理<br/>RuoYi-Vue-Pro]
+ C2[客户服务<br/>RuoYi-Vue-Pro]
+ C3[表务管理<br/>RuoYi-Vue-Pro]
+ C4[统计分析<br/>RuoYi-Vue-Pro]
+ end
+
+ subgraph "服务层"
+ D1[权限服务<br/>Spring Security]
+ D2[工作流服务<br/>Flowable]
+ D3[消息服务<br/>Redis MQ]
+ D4[文件服务<br/>MinIO/OSS]
+ end
+
+ subgraph "数据层"
+ E1[(OpenGauss 5.0+<br/>主从架构)]
+ E2[(Redis 6.0<br/>集群缓存)]
+ E3[文件存储<br/>分布式存储]
+ end
+
+ subgraph "外部接口"
+ F1[银行接口<br/>代扣/托收]
+ F2[支付接口<br/>微信/支付宝]
+ F3[短信接口<br/>阿里云/腾讯云]
+ F4[物联网接口<br/>智能水表]
+ end
+
+ A1 --> B1
+ A2 --> B1
+ A3 --> B1
+ A4 --> B1
+
+ B1 --> B2
+ B2 --> C1
+ B2 --> C2
+ B2 --> C3
+ B2 --> C4
+
+ C1 --> D1
+ C1 --> D2
+ C1 --> D3
+ C1 --> D4
+ C2 --> D1
+ C2 --> D3
+ C3 --> D1
+ C3 --> D2
+ C4 --> D1
+
+ D1 --> E1
+ D2 --> E1
+ D3 --> E2
+ D4 --> E3
+
+ C1 --> F1
+ C1 --> F2
+ C2 --> F3
+ C3 --> F4
+graph TB
+ subgraph "DMZ区域"
+ LB1[负载均衡器<br/>Nginx Cluster]
+ WAF[Web应用防火墙]
+ end
+
+ subgraph "应用服务区"
+ subgraph "Web服务集群"
+ WEB1[Web服务器1<br/>8核32G]
+ WEB2[Web服务器2<br/>8核32G]
+ end
+
+ subgraph "应用服务集群"
+ APP1[应用服务器1<br/>16核64G]
+ APP2[应用服务器2<br/>16核64G]
+ end
+ end
+
+ subgraph "数据服务区"
+ subgraph "数据库集群"
+ DB1[OpenGauss主库<br/>32核128G]
+ DB2[OpenGauss从库<br/>32核128G]
+ end
+
+ subgraph "缓存集群"
+ REDIS1[Redis主节点<br/>16核32G]
+ REDIS2[Redis从节点<br/>16核32G]
+ REDIS3[Redis哨兵<br/>8核16G]
+ end
+
+ subgraph "文件存储"
+ FILE1[文件服务器1<br/>8核32G 10TB]
+ FILE2[文件服务器2<br/>8核32G 10TB]
+ end
+ end
+
+ subgraph "管理服务区"
+ MONITOR[监控服务器<br/>8核16G]
+ BACKUP[备份服务器<br/>8核32G 20TB]
+ JUMP[跳板服务器<br/>4核8G]
+ end
+
+ Internet --> WAF
+ WAF --> LB1
+ LB1 --> WEB1
+ LB1 --> WEB2
+
+ WEB1 --> APP1
+ WEB1 --> APP2
+ WEB2 --> APP1
+ WEB2 --> APP2
+
+ APP1 --> DB1
+ APP2 --> DB1
+ DB1 --> DB2
+
+ APP1 --> REDIS1
+ APP2 --> REDIS1
+ REDIS1 --> REDIS2
+ REDIS3 --> REDIS1
+ REDIS3 --> REDIS2
+
+ APP1 --> FILE1
+ APP2 --> FILE2
+ FILE1 --> FILE2
+
+ MONITOR --> APP1
+ MONITOR --> APP2
+ MONITOR --> DB1
+ MONITOR --> REDIS1
+
+ BACKUP --> DB1
+ BACKUP --> FILE1
+系统采用B/S和M/S相结合的架构模式,具体技术栈如下:
-graph TB
+ subgraph "前端技术栈"
+ FE1[Vue 3.2+ TypeScript]
+ FE2[Element Plus UI]
+ FE3[Vite 构建工具]
+ FE4[Pinia 状态管理]
+ FE5[Vue Router 路由]
+ FE6[Axios HTTP请求]
+ FE7[ECharts 图表]
+ FE8[富文本编辑器]
+ end
+
+ subgraph "后端技术栈"
+ BE1[Spring Boot 3.x]
+ BE2[Spring Security 6.x]
+ BE3[MyBatis Plus 3.x]
+ BE4[Redis 6.0+]
+ BE5[OpenGauss 5.0+]
+ BE6[Knife4j API文档]
+ BE7[Jackson JSON处理]
+ BE8[Maven 依赖管理]
+ end
+
+ subgraph "中间件技术栈"
+ MW1[Nginx 负载均衡]
+ MW2[Redis 缓存集群]
+ MW3[Flowable 工作流]
+ MW4[Quartz 定时任务]
+ MW5[MinIO 文件存储]
+ MW6[RocketMQ 消息队列]
+ MW7[ElasticSearch 搜索]
+ MW8[Sentinel 熔断限流]
+ end
+
+ subgraph "移动端技术栈"
+ MB1[uni-app 跨平台]
+ MB2[uView UI组件]
+ MB3[微信小程序]
+ MB4[支付宝小程序]
+ MB5[H5响应式]
+ MB6[高德地图SDK]
+ MB7[NFC设备接口]
+ end
+
+ subgraph "监控运维技术栈"
+ OP1[SkyWalking APM]
+ OP2[Spring Boot Admin]
+ OP3[Docker 容器化]
+ OP4[Kubernetes 编排]
+ OP5[Jenkins CI/CD]
+ OP6[Prometheus 监控]
+ OP7[Grafana 仪表盘]
+ OP8[ELK 日志分析]
+ end
+
+ FE1 --> BE1
+ FE6 --> BE1
+ BE1 --> BE2
+ BE1 --> BE3
+ BE3 --> BE5
+ BE1 --> BE4
+ BE1 --> MW3
+ BE1 --> MW4
+ MW1 --> BE1
+ BE1 --> MW5
+ BE1 --> MW6
+ BE1 --> MW7
+ MW8 --> BE1
+
+ MB1 --> BE1
+ MB3 --> BE1
+ MB4 --> BE1
+
+ OP1 --> BE1
+ OP2 --> BE1
+ OP3 --> BE1
+ OP4 --> OP3
+ OP5 --> OP4
+ OP6 --> BE1
+ OP7 --> OP6
+ OP8 --> BE1
+flowchart TD
+ subgraph "数据采集层"
+ A1[移动抄表APP<br/>数据采集]
+ A2[智能水表<br/>远程数据]
+ A3[Web管理端<br/>业务录入]
+ A4[客户端小程序<br/>用户数据]
+ A5[外部系统<br/>接口数据]
+ end
+
+ subgraph "数据接入层"
+ B1[API网关<br/>数据验证]
+ B2[数据清洗<br/>格式转换]
+ B3[消息队列<br/>异步处理]
+ B4[数据缓存<br/>临时存储]
+ end
+
+ subgraph "业务处理层"
+ C1[抄表服务<br/>水量计算]
+ C2[收费服务<br/>账单生成]
+ C3[账务服务<br/>财务处理]
+ C4[工单服务<br/>流程处理]
+ C5[统计服务<br/>数据分析]
+ end
+
+ subgraph "数据存储层"
+ D1[(MySQL主库<br/>核心业务数据)]
+ D2[(MySQL从库<br/>查询数据)]
+ D3[(Redis缓存<br/>热点数据)]
+ D4[文件存储<br/>附件图片]
+ D5[(备份库<br/>历史数据)]
+ end
+
+ subgraph "数据服务层"
+ E1[查询服务<br/>数据检索]
+ E2[报表服务<br/>统计分析]
+ E3[接口服务<br/>对外开放]
+ E4[推送服务<br/>消息通知]
+ end
+
+ subgraph "数据展现层"
+ F1[管理后台<br/>业务操作]
+ F2[统计大屏<br/>可视化展示]
+ F3[移动端<br/>现场作业]
+ F4[客户端<br/>自助服务]
+ F5[第三方系统<br/>数据集成]
+ end
+
+ %% 数据流向关系
+ A1 --> B1
+ A2 --> B2
+ A3 --> B1
+ A4 --> B1
+ A5 --> B3
+
+ B1 --> B4
+ B2 --> B3
+ B3 --> C1
+ B4 --> C2
+
+ C1 --> D1
+ C2 --> D1
+ C3 --> D1
+ C4 --> D1
+ C5 --> D2
+
+ D1 --> D2
+ D1 --> D3
+ D1 --> D5
+
+ D2 --> E1
+ D3 --> E1
+ D1 --> E2
+ D2 --> E3
+
+ E1 --> F1
+ E2 --> F2
+ E3 --> F3
+ E4 --> F4
+ E3 --> F5
+
+ %% 反向数据流
+ F1 -.-> C2
+ F3 -.-> C1
+ F4 -.-> C3
+ F5 -.-> C4
+application.yml主配置文件:
+# 服务端口配置
+server:
+ port: 48080
+ servlet:
+ context-path: /admin-api
+
+# Spring Boot 配置
+spring:
+ application:
+ name: water-biz-server
+ profiles:
+ active: local
+
+ # 数据源配置
+ datasource:
+ druid:
+ url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+ username: root
+ password: ${MYSQL_PASSWORD:123456}
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ # 连接池配置
+ initial-size: 10
+ min-idle: 10
+ max-active: 20
+ max-wait: 60000
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ test-on-borrow: false
+ test-on-return: false
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+
+ # Redis 配置
+ redis:
+ host: 127.0.0.1
+ port: 6379
+ password: ${REDIS_PASSWORD:}
+ database: 1
+ timeout: 6000ms
+ lettuce:
+ pool:
+ max-active: 32
+ max-wait: 6000ms
+ max-idle: 32
+ min-idle: 8
+
+# MyBatis Plus 配置
+mybatis-plus:
+ configuration:
+ map-underscore-to-camel-case: true
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ global-config:
+ db-config:
+ id-type: NONE
+ logic-delete-field: deleted
+ logic-delete-value: 1
+ logic-not-delete-value: 0
+ type-aliases-package: cn.iocoder.yudao.module.*.dal.dataobject
+
+# 水务系统多租户配置
+yudao:
+ tenant:
+ enable: true
+ ignore-urls:
+ - /admin-api/water/tenant/get-id-by-name
+ - /admin-api/infra/file/*/get/**
+ ignore-tables:
+ - water_tenant
+ - water_system_config
+ - water_dict_data
+ - water_dict_type
+
+ # 水务系统安全配置
+ security:
+ permit-all-urls:
+ - /admin-api/water/auth/login
+ - /admin-api/water/auth/logout
+ - /admin-api/water/auth/refresh-token
+ - /admin-api/water/captcha/get
+ - /admin-api/water/sms/send
+
+ # 文件存储配置
+ file:
+ config:
+ type: local
+ local:
+ domain: http://127.0.0.1:48080
+ path: /Users/yunai/file_test
+
+ # 短信配置
+ sms:
+ alibaba:
+ access-key-id: ${SMS_ACCESS_KEY_ID:}
+ access-key-secret: ${SMS_ACCESS_KEY_SECRET:}
+ signature: 福建水务
+ template-code: SMS_123456多租户配置实现:
+@Component
+@Slf4j
+public class WaterTenantConfiguration {
+
+ @Resource
+ private TenantProperties tenantProperties;
+
+ /**
+ * 多租户字段处理器
+ */
+ @Bean
+ public TenantLineHandler tenantLineHandler() {
+ return new TenantLineHandler() {
+
+ @Override
+ public Expression getTenantId() {
+ // 从当前登录用户上下文获取租户ID
+ Long tenantId = TenantContextHolder.getTenantId();
+ if (tenantId == null) {
+ return null;
+ }
+ return new LongValue(tenantId);
+ }
+
+ @Override
+ public String getTenantIdColumn() {
+ return "tenant_id";
+ }
+
+ @Override
+ public boolean ignoreTable(String tableName) {
+ // 忽略的表不进行多租户处理
+ return tenantProperties.getIgnoreTables().contains(tableName);
+ }
+ };
+ }
+
+ /**
+ * 多租户拦截器
+ */
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ // 多租户插件
+ TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
+ tenantInterceptor.setTenantLineHandler(tenantLineHandler());
+ interceptor.addInnerInterceptor(tenantInterceptor);
+ // 分页插件
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ return interceptor;
+ }
+}权限控制配置:
+@EnableWebSecurity
+@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
+@Configuration
+public class WaterSecurityConfiguration {
+
+ @Resource
+ private SecurityProperties securityProperties;
+
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity httpSecurity,
+ @Lazy TokenAuthenticationFilter tokenAuthenticationFilter) throws Exception {
+ return httpSecurity
+ // 设置 URL 安全权限
+ .authorizeHttpRequests(c -> c
+ // 1. 静态资源,可匿名访问
+ .requestMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
+ // 2. 设置 @PermitAll 无需认证
+ .requestMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
+ // 3. 兜底规则,必须认证
+ .anyRequest().authenticated()
+ )
+ // 设置处理器
+ .exceptionHandling(c -> c.authenticationEntryPoint(authenticationEntryPoint)
+ .accessDeniedHandler(accessDeniedHandler))
+ // 添加 Token Filter
+ .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
+ // 不创建 SecurityContext
+ .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ // 禁用 CSRF,因为使用 token 机制
+ .csrf(AbstractHttpConfigurer::disable)
+ // 禁用 cors
+ .cors(AbstractHttpConfigurer::disable)
+ .build();
+ }
+}package.json 依赖配置:
+{
+ "name": "water-biz-ui-admin",
+ "version": "1.0.0",
+ "description": "福建水务营收系统管理后台",
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.1.0",
+ "@vueuse/core": "^10.5.0",
+ "axios": "^1.6.0",
+ "echarts": "^5.4.3",
+ "element-plus": "^2.4.2",
+ "pinia": "^2.1.7",
+ "vue": "^3.3.8",
+ "vue-router": "^4.2.5",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-vue": "^5.1.12"
+ },
+ "devDependencies": {
+ "@types/node": "^20.8.7",
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
+ "@typescript-eslint/parser": "^6.9.1",
+ "@vitejs/plugin-vue": "^4.4.1",
+ "eslint": "^8.52.0",
+ "eslint-plugin-vue": "^9.17.0",
+ "prettier": "^3.0.3",
+ "typescript": "^5.2.2",
+ "vite": "^4.5.0",
+ "vue-tsc": "^1.8.22"
+ }
+}vite.config.ts 构建配置:
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import { resolve } from 'path'
+
+export default defineConfig({
+ plugins: [vue()],
+ resolve: {
+ alias: {
+ '@': resolve(__dirname, 'src'),
+ '~': resolve(__dirname, 'src'),
+ '#': resolve(__dirname, 'types')
+ }
+ },
+ server: {
+ host: '0.0.0.0',
+ port: 3000,
+ open: true,
+ proxy: {
+ '/admin-api': {
+ target: 'http://127.0.0.1:48080',
+ changeOrigin: true,
+ ws: true
+ }
+ }
+ },
+ build: {
+ target: 'es2015',
+ outDir: 'dist',
+ assetsDir: 'static',
+ sourcemap: false,
+ chunkSizeWarningLimit: 1500,
+ rollupOptions: {
+ output: {
+ chunkFileNames: 'static/js/[name]-[hash].js',
+ entryFileNames: 'static/js/[name]-[hash].js',
+ assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
+ }
+ }
+ }
+})src/stores/user.ts 用户状态管理:
+import { defineStore } from 'pinia'
+import { ref, computed } from 'vue'
+import { UserApi, UserVO } from '@/api/system/user'
+import { getAccessToken, removeToken } from '@/utils/auth'
+
+export const useUserStore = defineStore('user', () => {
+ const userInfo = ref<UserVO>()
+ const permissions = ref<string[]>([])
+ const roles = ref<string[]>([])
+
+ const nickname = computed(() => userInfo.value?.nickname ?? '')
+ const avatar = computed(() => userInfo.value?.avatar ?? '')
+ const email = computed(() => userInfo.value?.email ?? '')
+
+ // 获取用户信息
+ const getUserInfo = async () => {
+ const res = await UserApi.getUserProfile()
+ userInfo.value = res
+ permissions.value = res.permissions
+ roles.value = res.roles
+ }
+
+ // 用户登出
+ const logout = async () => {
+ try {
+ await UserApi.logout()
+ } finally {
+ await resetToken()
+ }
+ }
+
+ // 重置令牌
+ const resetToken = async () => {
+ userInfo.value = undefined
+ permissions.value = []
+ roles.value = []
+ removeToken()
+ }
+
+ // 检查权限
+ const hasPermission = (permission: string) => {
+ return permissions.value.includes(permission)
+ }
+
+ // 检查角色
+ const hasRole = (role: string) => {
+ return roles.value.includes(role)
+ }
+
+ return {
+ userInfo,
+ permissions,
+ roles,
+ nickname,
+ avatar,
+ email,
+ getUserInfo,
+ logout,
+ resetToken,
+ hasPermission,
+ hasRole
+ }
+})src/utils/request.ts HTTP请求封装:
+import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { getAccessToken, getRefreshToken, removeToken } from '@/utils/auth'
+import { useUserStore } from '@/stores/user'
+
+// 创建 axios 实例
+const service = axios.create({
+ baseURL: import.meta.env.VITE_BASE_URL,
+ timeout: 50000,
+ withCredentials: false
+})
+
+// 请求拦截器
+service.interceptors.request.use(
+ (config: InternalAxiosRequestConfig) => {
+ // 添加 token
+ const accessToken = getAccessToken()
+ if (accessToken && config.headers) {
+ config.headers.Authorization = `Bearer ${accessToken}`
+ }
+
+ // 添加租户ID
+ const tenantId = localStorage.getItem('tenantId')
+ if (tenantId && config.headers) {
+ config.headers['tenant-id'] = tenantId
+ }
+
+ return config
+ },
+ error => {
+ console.log(error)
+ return Promise.reject(error)
+ }
+)
+
+// 响应拦截器
+service.interceptors.response.use(
+ (response: AxiosResponse) => {
+ const { data } = response
+ const { code, msg } = data
+
+ // 业务请求成功
+ if (code === 0) {
+ return data
+ }
+
+ // token 过期,尝试刷新
+ if (code === 401) {
+ return handleTokenExpired()
+ }
+
+ // 业务请求失败
+ ElMessage.error(msg || '系统未知错误,请反馈给管理员')
+ return Promise.reject(new Error(msg || 'Error'))
+ },
+ error => {
+ console.log('err' + error)
+ let { message } = error
+ if (message === 'Network Error') {
+ message = '后端接口连接异常'
+ } else if (message.includes('timeout')) {
+ message = '系统接口请求超时'
+ } else if (message.includes('Request failed with status code')) {
+ message = '系统接口' + message.substr(message.length - 3) + '异常'
+ }
+ ElMessage.error(message)
+ return Promise.reject(error)
+ }
+)
+
+// 处理 token 过期
+const handleTokenExpired = async () => {
+ const userStore = useUserStore()
+ ElMessageBox.alert('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
+ confirmButtonText: '重新登录',
+ type: 'warning'
+ }).then(() => {
+ userStore.resetToken().then(() => {
+ location.reload()
+ })
+ })
+}
+
+export default service技术栈组成:
+graph TB
+ subgraph "开发框架"
+ A1[Vue 3.2.47 Composition API]
+ A2[TypeScript 4.9.4]
+ A3[Vite 4.0.0 构建工具]
+ end
+
+ subgraph "UI组件库"
+ B1[Element Plus 2.3.14]
+ B2[Element Plus Icons]
+ B3[自定义组件库]
+ end
+
+ subgraph "状态管理"
+ C1[Pinia 2.0.28]
+ C2[持久化插件]
+ C3[全局状态管理]
+ end
+
+ subgraph "路由系统"
+ D1[Vue Router 4.1.6]
+ D2[路由守卫]
+ D3[动态路由]
+ D4[权限控制]
+ end
+
+ subgraph "HTTP通信"
+ E1[Axios 1.2.2]
+ E2[请求拦截器]
+ E3[响应拦截器]
+ E4[错误处理]
+ end
+
+ subgraph "工具库"
+ F1[Lodash 工具函数]
+ F2[dayjs 时间处理]
+ F3[nprogress 进度条]
+ F4[js-cookie Cookie管理]
+ F5[crypto-js 加密解密]
+ end
+
+ A1 --> B1
+ A1 --> C1
+ A1 --> D1
+ A1 --> E1
+ B1 --> B3
+ C1 --> C2
+ D1 --> D2
+ E1 --> E2
+项目结构设计:
+yudao-ui-admin-vue3/
+├── public/ # 静态资源
+├── src/
+│ ├── api/ # API接口定义
+│ │ └── water/ # 水务业务API
+│ │ ├── customer/ # 客户管理API
+│ │ ├── meter/ # 抄表管理API
+│ │ ├── billing/ # 收费管理API
+│ │ └── workflow/ # 工单管理API
+│ ├── assets/ # 静态资源
+│ ├── components/ # 全局组件
+│ │ ├── Dialog/ # 弹窗组件
+│ │ ├── Form/ # 表单组件
+│ │ ├── Table/ # 表格组件
+│ │ └── Upload/ # 上传组件
+│ ├── layout/ # 布局组件
+│ ├── router/ # 路由配置
+│ ├── stores/ # Pinia状态管理
+│ ├── styles/ # 全局样式
+│ ├── utils/ # 工具函数
+│ ├── views/ # 页面组件
+│ │ └── water/ # 水务业务页面
+│ │ ├── customer/ # 客户管理
+│ │ ├── meter/ # 抄表管理
+│ │ ├── billing/ # 收费管理
+│ │ └── workflow/ # 工单管理
+│ └── App.vue
+├── types/ # TypeScript类型定义
+├── vite.config.ts # Vite配置
+├── tsconfig.json # TypeScript配置
+└── package.json # 项目依赖
+核心配置示例:
+// vite.config.ts - Vite构建配置
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import { resolve } from 'path'
+
+export default defineConfig({
+ plugins: [vue()],
+ resolve: {
+ alias: {
+ '@': resolve(__dirname, 'src'),
+ '@/api': resolve(__dirname, 'src/api'),
+ '@/components': resolve(__dirname, 'src/components'),
+ '@/utils': resolve(__dirname, 'src/utils')
+ }
+ },
+ server: {
+ port: 80,
+ proxy: {
+ '/admin-api': {
+ target: 'http://127.0.0.1:48080',
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/admin-api/, '/admin-api')
+ }
+ }
+ },
+ build: {
+ outDir: 'dist',
+ sourcemap: false,
+ rollupOptions: {
+ output: {
+ chunkFileNames: 'js/[name]-[hash].js',
+ entryFileNames: 'js/[name]-[hash].js',
+ assetFileNames: '[ext]/[name]-[hash].[ext]'
+ }
+ }
+ }
+})技术栈组成:
+graph TB
+ subgraph "跨平台框架"
+ M1[uni-app 3.x]
+ M2[Vue 3 Composition API]
+ M3[TypeScript支持]
+ end
+
+ subgraph "UI组件库"
+ N1[uView UI 2.0]
+ N2[uni-ui组件]
+ N3[自定义水务组件]
+ end
+
+ subgraph "状态管理"
+ O1[Vuex 4.x]
+ O2[uni-app存储]
+ O3[缓存管理]
+ end
+
+ subgraph "设备能力"
+ P1[相机API<br/>水表拍照]
+ P2[NFC读取<br/>水表标签]
+ P3[GPS定位<br/>抄表轨迹]
+ P4[扫码API<br/>二维码扫描]
+ end
+
+ subgraph "网络通信"
+ Q1[uni.request<br/>HTTP请求]
+ Q2[WebSocket<br/>实时通信]
+ Q3[文件上传<br/>图片处理]
+ end
+
+ M1 --> N1
+ M1 --> O1
+ M1 --> P1
+ M1 --> Q1
+ N1 --> N3
+ P1 --> P2
+ Q1 --> Q2
+移动端项目结构:
+water-mobile-app/
+├── pages/ # 页面目录
+│ ├── index/ # 首页
+│ ├── meter/ # 抄表功能
+│ │ ├── task/ # 抄表任务
+│ │ ├── read/ # 抄表录入
+│ │ └── history/ # 抄表历史
+│ ├── workflow/ # 工单管理
+│ └── personal/ # 个人中心
+├── components/ # 组件目录
+│ ├── meter-reader/ # 水表读数组件
+│ ├── map-trace/ # 地图轨迹组件
+│ └── camera-scan/ # 相机扫描组件
+├── static/ # 静态资源
+├── store/ # 状态管理
+├── utils/ # 工具函数
+├── api/ # 接口定义
+├── manifest.json # 应用配置
+└── pages.json # 页面配置
+微信小程序技术栈: - 开发框架:微信小程序原生框架 - +UI组件:WeUI + 自定义组件 - 状态管理:小程序全局数据管理 - +支付集成:微信支付API - 地图服务:腾讯地图API
+支付宝小程序技术栈: -
+开发框架:支付宝小程序原生框架
+- UI组件:mini-antui + 自定义组件 - 状态管理:小程序全局数据管理 -
+支付集成:支付宝支付API - 地图服务:高德地图API
代码规范:
+// .eslintrc.js - ESLint配置
+{
+ "extends": [
+ "@vue/typescript/recommended",
+ "@vue/prettier",
+ "@vue/prettier/@typescript-eslint"
+ ],
+ "rules": {
+ "@typescript-eslint/no-explicit-any": "warn",
+ "@typescript-eslint/no-unused-vars": "error",
+ "vue/multi-word-component-names": "off"
+ }
+}构建优化: - Vite热更新:开发环境快速构建 - +代码分割:按路由和组件懒加载 - 资源压缩:Gzip压缩和图片优化 - +CDN加速:静态资源CDN分发 - 缓存策略:浏览器缓存和Service Worker
+graph TB
+ subgraph "网关层"
+ GW[API网关<br/>Spring Cloud Gateway]
+ AUTH[认证服务<br/>OAuth2 + JWT]
+ end
+
+ subgraph "基础服务层"
+ subgraph "系统服务"
+ SYS[系统管理服务<br/>用户/角色/权限]
+ TENANT[租户管理服务<br/>多租户隔离]
+ FILE[文件管理服务<br/>附件存储]
+ MSG[消息服务<br/>短信/邮件/推送]
+ end
+
+ subgraph "工作流服务"
+ WF[工作流引擎<br/>Flowable]
+ TASK[任务调度服务<br/>Quartz]
+ end
+ end
+
+ subgraph "业务服务层"
+ subgraph "客户域服务"
+ CUST[客户管理服务<br/>Customer Service]
+ METER[水表管理服务<br/>Meter Service]
+ ADDR[地址管理服务<br/>Address Service]
+ end
+
+ subgraph "营收域服务"
+ READ[抄表服务<br/>Reading Service]
+ BILL[账单服务<br/>Billing Service]
+ PAY[收费服务<br/>Payment Service]
+ ACC[账务服务<br/>Accounting Service]
+ end
+
+ subgraph "运营域服务"
+ ORDER[工单服务<br/>Workflow Service]
+ RPT[报表服务<br/>Report Service]
+ STATS[统计分析服务<br/>Statistics Service]
+ end
+
+ subgraph "接口域服务"
+ BANK[银行接口服务<br/>Bank Service]
+ PAY_GW[支付网关服务<br/>Payment Gateway]
+ IOT[物联网服务<br/>IoT Service]
+ SMS[短信服务<br/>SMS Service]
+ end
+ end
+
+ subgraph "数据层"
+ subgraph "业务数据库"
+ DB_CUST[(客户库<br/>Customer DB)]
+ DB_BILL[(营收库<br/>Billing DB)]
+ DB_RPT[(报表库<br/>Report DB)]
+ end
+
+ subgraph "缓存与存储"
+ REDIS[(Redis集群<br/>缓存/会话)]
+ ES[(ElasticSearch<br/>搜索引擎)]
+ FILE_STORE[文件存储<br/>MinIO/OSS]
+ end
+ end
+
+ %% 网关层连接
+ GW --> AUTH
+ GW --> SYS
+ GW --> CUST
+ GW --> READ
+ GW --> ORDER
+
+ %% 服务间调用
+ CUST --> METER
+ CUST --> ADDR
+ READ --> METER
+ READ --> CUST
+ BILL --> READ
+ BILL --> CUST
+ PAY --> BILL
+ ACC --> PAY
+
+ ORDER --> WF
+ ORDER --> TASK
+ RPT --> STATS
+
+ %% 外部接口调用
+ PAY --> BANK
+ PAY --> PAY_GW
+ READ --> IOT
+ ORDER --> SMS
+
+ %% 数据层连接
+ CUST --> DB_CUST
+ METER --> DB_CUST
+ BILL --> DB_BILL
+ PAY --> DB_BILL
+ RPT --> DB_RPT
+
+ SYS --> REDIS
+ AUTH --> REDIS
+ CUST --> REDIS
+ BILL --> ES
+ FILE --> FILE_STORE
+graph TB
+ subgraph "服务发现与注册"
+ NACOS[Nacos注册中心<br/>服务注册/发现/配置]
+ end
+
+ subgraph "服务网格层"
+ subgraph "负载均衡"
+ LB[Ribbon负载均衡<br/>客户端负载均衡]
+ FEIGN[OpenFeign<br/>服务间调用]
+ end
+
+ subgraph "容错保护"
+ CB[Sentinel熔断器<br/>流量控制/熔断降级]
+ RETRY[重试机制<br/>失败重试]
+ end
+
+ subgraph "链路追踪"
+ TRACE[SkyWalking<br/>分布式链路追踪]
+ METRIC[Micrometer<br/>指标收集]
+ end
+ end
+
+ subgraph "配置管理"
+ CONFIG[Nacos Config<br/>配置中心]
+ SECRET[配置加密<br/>敏感信息保护]
+ end
+
+ subgraph "监控告警"
+ MONITOR[Spring Boot Admin<br/>应用监控]
+ ALERT[告警系统<br/>异常通知]
+ LOG[ELK日志系统<br/>日志聚合分析]
+ end
+
+ NACOS --> LB
+ NACOS --> FEIGN
+ LB --> CB
+ FEIGN --> TRACE
+ CB --> RETRY
+
+ CONFIG --> SECRET
+ MONITOR --> ALERT
+ TRACE --> LOG
系统应用架构基于业务域划分,主要包括以下核心应用模块:
graph TB
+ subgraph "OpenGauss高可用集群"
+ MASTER[("OpenGauss主库<br/>Primary Node<br/>读写操作")]
+ STANDBY[("OpenGauss备库<br/>Standby Node<br/>只读操作")]
+ CASCADE[("OpenGauss级联备库<br/>Cascade Standby<br/>负载分担")]
+ end
+
+ subgraph "应用层"
+ APP1[应用服务器1]
+ APP2[应用服务器2]
+ APP3[应用服务器3]
+ end
+
+ subgraph "连接池"
+ POOL[连接池<br/>HikariCP<br/>Druid]
+ end
+
+ subgraph "监控管理"
+ MON[OpenGauss Monitor<br/>性能监控]
+ BACKUP[定时备份<br/>gs_backup]
+ end
+
+ APP1 --> POOL
+ APP2 --> POOL
+ APP3 --> POOL
+ POOL --> MASTER
+ POOL --> STANDBY
+ POOL --> CASCADE
+
+ MASTER -.->|流复制| STANDBY
+ STANDBY -.->|级联复制| CASCADE
+
+ MON --> MASTER
+ MON --> STANDBY
+ BACKUP --> MASTER
+graph TB
+ subgraph "OpenGauss分布式架构"
+ subgraph "协调节点"
+ CN1[协调节点1<br/>Coordinator Node]
+ CN2[协调节点2<br/>Coordinator Node]
+ end
+
+ subgraph "数据节点组1"
+ DN1_1[数据节点1-主<br/>Datanode Primary]
+ DN1_2[数据节点1-备<br/>Datanode Standby]
+ end
+
+ subgraph "数据节点组2"
+ DN2_1[数据节点2-主<br/>Datanode Primary]
+ DN2_2[数据节点2-备<br/>Datanode Standby]
+ end
+
+ subgraph "GTM节点"
+ GTM[全局事务管理器<br/>GTM Master]
+ GTM_S[GTM备节点<br/>GTM Standby]
+ end
+ end
+
+ CN1 --> DN1_1
+ CN1 --> DN2_1
+ CN2 --> DN1_1
+ CN2 --> DN2_1
+
+ DN1_1 -.->|主备同步| DN1_2
+ DN2_1 -.->|主备同步| DN2_2
+
+ GTM -.->|备份| GTM_S
+ CN1 --> GTM
+ CN2 --> GTM
+graph TB
+ subgraph "安全防护层"
+ TDE[透明数据加密<br/>TDE]
+ RLS[行级安全<br/>Row Level Security]
+ MASK[动态数据脱敏<br/>Dynamic Data Masking]
+ AUDIT[三权分立审计<br/>Separated Audit]
+ end
+
+ subgraph "访问控制层"
+ RBAC[基于角色的访问控制<br/>RBAC]
+ LDAP[LDAP集成认证<br/>External Auth]
+ SSL[SSL/TLS加密传输<br/>Encrypted Transport]
+ end
+
+ subgraph "数据存储层"
+ ENCRYPT[存储层加密<br/>Storage Encryption]
+ COMPRESS[数据压缩<br/>Data Compression]
+ BACKUP_ENC[备份加密<br/>Backup Encryption]
+ end
+
+ TDE --> ENCRYPT
+ RLS --> RBAC
+ MASK --> ENCRYPT
+ AUDIT --> BACKUP_ENC
+ RBAC --> SSL
+ LDAP --> SSL
+系统安全架构满足等保三级要求,主要包括以下安全措施:
+系统安全架构基于OpenGauss数据库的企业级安全特性,满足等保三级要求和国产化安全标准:
graph TB
+ subgraph "加密层级"
+ L1[传输层加密<br/>SSL/TLS/国密SM]
+ L2[存储层加密<br/>TDE透明数据加密]
+ L3[字段级加密<br/>敏感字段加密]
+ L4[备份加密<br/>备份文件加密]
+ end
+
+ subgraph "密钥管理"
+ KMS[密钥管理系统<br/>Key Management]
+ HSM[硬件安全模块<br/>Hardware Security]
+ ROT[密钥轮换<br/>Key Rotation]
+ end
+
+ subgraph "国密算法"
+ SM2[SM2椭圆曲线<br/>非对称加密]
+ SM3[SM3哈希算法<br/>消息摘要]
+ SM4[SM4分组密码<br/>对称加密]
+ end
+
+ L1 --> KMS
+ L2 --> HSM
+ L3 --> ROT
+ L4 --> KMS
+
+ KMS --> SM2
+ HSM --> SM3
+ ROT --> SM4
+graph TB
+ subgraph "身份认证"
+ AUTH1[用户名密码认证]
+ AUTH2[LDAP集成认证]
+ AUTH3[Kerberos认证]
+ AUTH4[证书认证]
+ end
+
+ subgraph "权限控制"
+ RBAC[基于角色的权限控制<br/>Role-Based Access Control]
+ RLS[行级安全策略<br/>Row Level Security]
+ CLS[列级安全控制<br/>Column Level Security]
+ TENANT[多租户数据隔离<br/>Multi-Tenant Isolation]
+ end
+
+ subgraph "审计监控"
+ AUDIT[操作审计日志<br/>Audit Logging]
+ MONITOR[实时安全监控<br/>Security Monitoring]
+ ALERT[安全告警<br/>Security Alert]
+ REPORT[合规报告<br/>Compliance Report]
+ end
+
+ AUTH1 --> RBAC
+ AUTH2 --> RLS
+ AUTH3 --> CLS
+ AUTH4 --> TENANT
+
+ RBAC --> AUDIT
+ RLS --> MONITOR
+ CLS --> ALERT
+ TENANT --> REPORT
+系统采用集中部署的模式,基于集团私有云环境进行部署。
| 项目信息 | +详情 | +
|---|---|
| 项目名称 | +福建水务营收系统 | +
| 文档类型 | +概要设计文档 | +
| 技术框架 | +RuoYi-Vue-Pro + yudao-ui-admin-vue3 | +
| 文档版本 | +v1.0 | +
| 编写日期 | +2024-12-19 | +
| 文档状态 | +✅ 已完成 | +
福建水务营收系统采用现代化的分布式微服务架构,基于RuoYi-Vue-Pro后端框架和yudao-ui-admin-vue3前端框架构建,为水务企业提供完整的营收管理解决方案。
+graph TB
+ subgraph "用户层"
+ A1[管理员用户]
+ A2[抄表员]
+ A3[收费员]
+ A4[客户用户]
+ end
+
+ subgraph "接入层"
+ B1[PC端管理后台<br/>yudao-ui-admin-vue3]
+ B2[移动端抄表APP<br/>uni-app]
+ B3[微信小程序]
+ B4[支付宝小程序]
+ B5[Web客户端]
+ end
+
+ subgraph "网关层"
+ C1[API网关<br/>Spring Cloud Gateway]
+ C2[负载均衡<br/>Nginx]
+ end
+
+ subgraph "服务层"
+ D1[用户认证服务<br/>Spring Security + JWT]
+ D2[营收管理服务<br/>RuoYi-Vue-Pro]
+ D3[表务管理服务]
+ D4[报装管理服务]
+ D5[客户服务]
+ D6[系统管理服务]
+ end
+
+ subgraph "中间件层"
+ E1[(Redis缓存<br/>6.0+)]
+ E2[RabbitMQ消息队列]
+ E3[Elasticsearch搜索]
+ E4[MinIO文件存储]
+ end
+
+ subgraph "数据层"
+ F1[(主数据库<br/>OpenGauss 5.0+)]
+ F2[(从数据库<br/>OpenGauss 5.0+)]
+ F3[(历史数据库<br/>OpenGauss 5.0+)]
+ end
+
+ subgraph "外部系统"
+ G1[银行系统]
+ G2[支付宝/微信]
+ G3[短信平台]
+ G4[集抄系统]
+ G5[政务平台]
+ end
+
+ A1 --> B1
+ A2 --> B2
+ A3 --> B1
+ A4 --> B3
+ A4 --> B4
+ A4 --> B5
+
+ B1 --> C2
+ B2 --> C2
+ B3 --> C2
+ B4 --> C2
+ B5 --> C2
+
+ C2 --> C1
+ C1 --> D1
+ C1 --> D2
+ C1 --> D3
+ C1 --> D4
+ C1 --> D5
+ C1 --> D6
+
+ D1 --> E1
+ D2 --> E1
+ D2 --> E2
+ D3 --> E1
+ D4 --> E3
+ D5 --> E4
+ D6 --> E1
+
+ D2 --> F1
+ D3 --> F1
+ D4 --> F2
+ D5 --> F2
+ D6 --> F3
+
+ D2 --> G1
+ D2 --> G2
+ D5 --> G3
+ D3 --> G4
+ D4 --> G5
+graph TB
+ subgraph "前端技术栈"
+ FE1[Vue 3.x]
+ FE2[TypeScript 4.x]
+ FE3[Element Plus]
+ FE4[Vite 4.x]
+ FE5[Pinia状态管理]
+ end
+
+ subgraph "后端技术栈"
+ BE1[Spring Boot 3.x]
+ BE2[Spring Security 6.x]
+ BE3[MyBatis Plus 3.x]
+ BE4[Spring Cloud Gateway]
+ BE5[Hibernate Validator]
+ end
+
+ subgraph "数据库技术"
+ DB1[OpenGauss 5.0+]
+ DB2[Redis 6.0+]
+ DB3[HikariCP连接池]
+ DB4[MyBatis-Plus代码生成]
+ end
+
+ subgraph "中间件技术"
+ MW1[RabbitMQ 3.x]
+ MW2[Elasticsearch 8.x]
+ MW3[MinIO对象存储]
+ MW4[XXL-JOB定时任务]
+ end
+
+ subgraph "运维技术"
+ OPS1[Docker容器化]
+ OPS2[Jenkins CI/CD]
+ OPS3[Prometheus监控]
+ OPS4[ELK日志分析]
+ end
+
+ subgraph "安全技术"
+ SEC1[JWT Token认证]
+ SEC2[OAuth2.0授权]
+ SEC3[AES数据加密]
+ SEC4[RSA签名验证]
+ end
+
+ FE1 --> FE2
+ FE2 --> FE3
+ FE3 --> FE4
+ FE4 --> FE5
+
+ BE1 --> BE2
+ BE2 --> BE3
+ BE3 --> BE4
+ BE4 --> BE5
+
+ DB1 --> DB2
+ DB2 --> DB3
+ DB3 --> DB4
+
+ MW1 --> MW2
+ MW2 --> MW3
+ MW3 --> MW4
+
+ OPS1 --> OPS2
+ OPS2 --> OPS3
+ OPS3 --> OPS4
+
+ SEC1 --> SEC2
+ SEC2 --> SEC3
+ SEC3 --> SEC4
+graph TB
+ subgraph "统一平台层"
+ UP1[单点登录]
+ UP2[系统管理]
+ UP3[用户权限]
+ UP4[组织架构]
+ end
+
+ subgraph "核心业务层"
+ CB1[客户管理]
+ CB2[抄表管理]
+ CB3[收费管理]
+ CB4[账务管理]
+ CB5[表务管理]
+ CB6[报装管理]
+ end
+
+ subgraph "增值服务层"
+ VS1[客户服务]
+ VS2[移动应用]
+ VS3[微信服务]
+ VS4[电子发票]
+ VS5[在线支付]
+ end
+
+ subgraph "数据服务层"
+ DS1[统计分析]
+ DS2[报表查询]
+ DS3[数据导出]
+ DS4[决策支持]
+ end
+
+ subgraph "集成服务层"
+ IS1[银行接口]
+ IS2[支付接口]
+ IS3[短信接口]
+ IS4[集抄接口]
+ IS5[政务接口]
+ end
+
+ UP1 --> CB1
+ UP2 --> CB2
+ UP3 --> CB3
+ UP4 --> CB4
+
+ CB1 --> VS1
+ CB2 --> VS2
+ CB3 --> VS3
+ CB4 --> VS4
+ CB5 --> VS5
+ CB6 --> VS1
+
+ VS1 --> DS1
+ VS2 --> DS2
+ VS3 --> DS3
+ VS4 --> DS4
+ VS5 --> DS1
+
+ DS1 --> IS1
+ DS2 --> IS2
+ DS3 --> IS3
+ DS4 --> IS4
+ DS1 --> IS5
+统一平台是客户服务平台的综合展示平台,基于RuoYi-Vue-Pro和yudao-ui-admin-vue3框架构建,包含日常工作功能和客户全部的信息,是系统的基础功能模块。
-单点登录模块基于Spring Security和JWT实现用户一次登录即可访问系统中所有应用的功能,主要特点包括:
系统管理模块基于RuoYi-Vue-Pro框架的现成功能,提供对系统基础参数的配置管理功能,主要包括:
营收系统是水务业务系统的核心组成部分,负责抄表、收费、账务处理等关键业务功能。
-营收系统的基础管理功能,包括:
抄表开账模块负责水表读数的采集和账单生成,主要功能包括:
-收费管理模块负责水费的收取和管理,主要功能包括:
-账务处理模块负责处理各类特殊账务情况,主要功能包括:
-发票管理模块负责水费发票的管理,主要功能包括:
-抄表开账模块负责水表读数的采集和账单生成,是营收系统的核心业务模块。
+flowchart TD
+ Start([开始抄表周期]) --> BookPlan[制定抄表计划]
+ BookPlan --> CreateBook[生成抄表册本]
+ CreateBook --> AssignReader[分配抄表员]
+
+ AssignReader --> ReadingStart[开始抄表]
+ ReadingStart --> ReadingType{抄表方式}
+
+ ReadingType -->|人工抄表| ManualReading[现场抄表录入]
+ ReadingType -->|远程抄表| RemoteReading[远程采集数据]
+ ReadingType -->|客户自报| SelfReporting[客户自主上报]
+
+ ManualReading --> DataValidation[数据校验]
+ RemoteReading --> DataValidation
+ SelfReporting --> DataValidation
+
+ DataValidation --> ValidationResult{校验结果}
+ ValidationResult -->|异常| ExceptionHandle[异常处理]
+ ValidationResult -->|正常| DataReview[数据复核]
+
+ ExceptionHandle --> ReviewException[人工审核异常]
+ ReviewException --> DataReview
+
+ DataReview --> ReviewResult{复核结果}
+ ReviewResult -->|退回| ReadingStart
+ ReviewResult -->|通过| BillGeneration[生成账单]
+
+ BillGeneration --> CalcWaterFee[计算水费]
+ CalcWaterFee --> CalcSewageFee[计算污水费]
+ CalcSewageFee --> CalcOtherFee[计算其他费用]
+ CalcOtherFee --> BillReview[账单审核]
+
+ BillReview --> BillResult{审核结果}
+ BillResult -->|退回| BillGeneration
+ BillResult -->|通过| BillConfirm[账单确认]
+
+ BillConfirm --> SendNotification[发送缴费通知]
+ SendNotification --> End([完成开账])
+册本管理:册本基本信息的维护和管理 - 册本创建与配置 +- 抄表路线规划 - 抄表员分配 - 抄表周期设置
+抄表录入:支持多种抄表方式 - +手工抄表:现场抄表、批量录入 - 智能抄表:远程数据采集、自动同步 - +自报抄表:客户自主上报、在线提交
+抄表数据审核:确保数据质量 - +数据校验:读数合理性检查、用量异常检测 - +异常处理:异常数据标记、人工处理 - 开账处理:数据确认、账单生成
+追加抄表:支持非周期性特殊抄表 - +补抄管理:漏抄数据补录 - 特殊抄表:临时抄表需求 - +调整抄表:读数错误修正
+抄表管理主要接口:
+@RestController
+@RequestMapping("/admin-api/water/reading")
+@Tag(name = "管理后台 - 抄表管理")
+public class MeterReadingController {
+
+ @PostMapping("/create")
+ @Operation(summary = "创建抄表记录")
+ public CommonResult<Long> createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO);
+
+ @PostMapping("/batch-create")
+ @Operation(summary = "批量创建抄表记录")
+ public CommonResult<MeterReadingBatchRespVO> batchCreateReading(@Valid @RequestBody MeterReadingBatchReqVO batchReqVO);
+
+ @PostMapping("/review")
+ @Operation(summary = "抄表数据复核")
+ public CommonResult<Boolean> reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO);
+
+ @PostMapping("/generate-bill")
+ @Operation(summary = "生成账单")
+ public CommonResult<BillGenerateRespVO> generateBill(@Valid @RequestBody ReadingBillReqVO reqVO);
+}接口设计要点: - +遵循RESTful设计规范,统一的请求响应格式 - 支持批量操作提高处理效率 - +完整的数据校验和异常处理机制 - 集成RuoYi-Vue-Pro的权限控制和日志记录
+抄表管理页面结构:
+<template>
+ <ContentWrap>
+ <!-- 查询条件 -->
+ <el-form class="search-form" inline>
+ <el-form-item label="抄表日期">
+ <el-date-picker v-model="queryParams.readingDate" type="daterange" />
+ </el-form-item>
+ <el-form-item label="抄表状态">
+ <el-select v-model="queryParams.status">
+ <el-option label="待复核" value="pending" />
+ <el-option label="已通过" value="approved" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">查询</el-button>
+ <el-button @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 操作按钮 -->
+ <el-row class="mb-10px">
+ <el-button type="primary" @click="handleAdd">新增抄表</el-button>
+ <el-button type="success" @click="handleBatchAdd">批量抄表</el-button>
+ <el-button type="warning" @click="handleExport">导出数据</el-button>
+ </el-row>
+
+ <!-- 数据表格 -->
+ <el-table v-loading="loading" :data="readingList">
+ <el-table-column prop="readingCode" label="抄表编号" width="180" />
+ <el-table-column prop="customerName" label="客户名称" />
+ <el-table-column prop="meterCode" label="水表编号" />
+ <el-table-column prop="readingValue" label="本次读数" />
+ <el-table-column prop="waterUsage" label="用水量" />
+ <el-table-column prop="readingDate" label="抄表日期" />
+ <el-table-column prop="status" label="状态">
+ <template #default="{ row }">
+ <dict-tag :type="DICT_TYPE.READING_STATUS" :value="row.status" />
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" width="200" fixed="right">
+ <template #default="{ row }">
+ <el-button link @click="handleUpdate(row)">编辑</el-button>
+ <el-button link @click="handleReview(row)">复核</el-button>
+ <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </ContentWrap>
+</template>
+前端页面功能特性: - 响应式设计:基于Element +Plus的现代化UI组件 - 数据表格:支持分页、排序、筛选等功能 - +表单验证:前端数据校验和错误提示 - 批量操作:支持批量抄表录入和批量审核 +- 实时更新:页面数据实时刷新和状态同步
+收费管理模块负责水费的收取和管理,是营收系统的重要业务模块。
+flowchart TD
+ Start([客户缴费]) --> QueryCustomer[查询客户信息]
+ QueryCustomer --> CustomerExists{客户是否存在}
+ CustomerExists -->|否| ErrorReturn[返回错误信息]
+ CustomerExists -->|是| QueryBills[查询欠费账单]
+
+ QueryBills --> BillExists{是否有欠费}
+ BillExists -->|否| NoDebt[无欠费提示]
+ BillExists -->|是| ShowBills[显示账单列表]
+
+ ShowBills --> SelectBills[选择缴费账单]
+ SelectBills --> CalcAmount[计算缴费金额]
+ CalcAmount --> SelectPayMethod[选择支付方式]
+
+ SelectPayMethod --> PaymentType{支付方式}
+ PaymentType -->|现金| CashPayment[现金收费]
+ PaymentType -->|银行卡| BankCardPay[银行卡支付]
+ PaymentType -->|在线支付| OnlinePayment[在线支付]
+ PaymentType -->|预存款| PrepaidPayment[预存款支付]
+
+ CashPayment --> ValidatePayment[验证收费金额]
+ BankCardPay --> ValidatePayment
+ OnlinePayment --> ThirdPartyPay[第三方支付]
+ PrepaidPayment --> CheckBalance[检查预存余额]
+
+ ThirdPartyPay --> PaymentCallback[支付回调]
+ PaymentCallback --> ValidatePayment
+
+ CheckBalance --> BalanceOK{余额是否充足}
+ BalanceOK -->|否| InsufficientBalance[余额不足]
+ BalanceOK -->|是| ValidatePayment
+
+ ValidatePayment --> PaymentSuccess{支付成功}
+ PaymentSuccess -->|否| PaymentFailed[支付失败处理]
+ PaymentSuccess -->|是| UpdateAccount[更新账户状态]
+
+ UpdateAccount --> UpdateBills[更新账单状态]
+ UpdateBills --> GenerateReceipt[生成收费凭证]
+ GenerateReceipt --> PrintReceipt[打印收据]
+ PrintReceipt --> SendNotification[发送缴费通知]
+ SendNotification --> Complete([完成缴费])
+
+ PaymentFailed --> End([结束])
+ InsufficientBalance --> End
+ ErrorReturn --> End
+ NoDebt --> End
+柜台收费:现场收费服务 - +用户查询:客户信息查询、账单查询 - 收费处理:多种支付方式、找零计算 - +收费打印:收据打印、发票开具 - 预存预付:余额充值、预付费管理
+柜台结账:营业网点日常结账 - +日结处理:当日收费汇总、统计分析 - 交款管理:现金上缴、账务核对 - +结账查询:历史结账记录查询
+预付款管理:预付费业务处理 - +预付款充值:余额充值、充值记录 - 使用管理:自动扣款、余额提醒 - +退款处理:预付款退款、退款审核
+缴费记录查询:缴费历史管理 - +多条件查询:按时间、金额、渠道查询 - 统计分析:缴费趋势、渠道分析 - +导出功能:缴费记录导出
+缴费管理主要接口:
+@RestController
+@RequestMapping("/admin-api/water/payment")
+@Tag(name = "管理后台 - 缴费管理")
+public class PaymentController {
+
+ @PostMapping("/create")
+ @Operation(summary = "创建缴费记录")
+ public CommonResult<PaymentRespVO> createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO);
+
+ @PostMapping("/cash-payment")
+ @Operation(summary = "现金缴费")
+ public CommonResult<PaymentRespVO> cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO);
+
+ @PostMapping("/online-payment")
+ @Operation(summary = "在线支付")
+ public CommonResult<OnlinePaymentRespVO> onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO);
+
+ @PostMapping("/prepaid-payment")
+ @Operation(summary = "预存款缴费")
+ public CommonResult<PaymentRespVO> prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO);
+}接口设计特点: - +支持多种缴费方式:现金、银行卡、在线支付、预存款 - +事务控制:确保缴费操作的原子性和一致性 - +异步处理:第三方支付采用异步回调机制 - +安全验证:完整的权限控制和数据校验
+
+#### 3.3.4 前端界面设计
+
+**缴费管理页面结构**:
+```vue
+<template>
+ <ContentWrap>
+ <!-- 客户查询 -->
+ <el-form class="search-form" inline>
+ <el-form-item label="客户编号">
+ <el-input v-model="queryParams.customerCode" placeholder="请输入客户编号" />
+ </el-form-item>
+ <el-form-item label="客户姓名">
+ <el-input v-model="queryParams.customerName" placeholder="请输入客户姓名" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">查询</el-button>
+ <el-button @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 账单信息 -->
+ <el-table v-loading="loading" :data="billList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" />
+ <el-table-column prop="billCode" label="账单编号" />
+ <el-table-column prop="billDate" label="账期" />
+ <el-table-column prop="waterUsage" label="用水量" />
+ <el-table-column prop="totalAmount" label="应缴金额" />
+ <el-table-column prop="balanceAmount" label="欠费金额" />
+ </el-table>
+
+ <!-- 缴费操作 -->
+ <el-row class="payment-actions">
+ <el-col :span="12">
+ <el-statistic title="选中金额" :value="selectedAmount" prefix="¥" />
+ </el-col>
+ <el-col :span="12" class="text-right">
+ <el-button type="success" @click="handleCashPayment">现金缴费</el-button>
+ <el-button type="primary" @click="handleOnlinePayment">在线支付</el-button>
+ <el-button type="warning" @click="handlePrepaidPayment">预存扣费</el-button>
+ </el-col>
+ </el-row>
+ </ContentWrap>
+</template>
+账务处理模块负责处理各类特殊账务情况,确保账务数据的准确性和完整性。
+flowchart TD
+ Start([账务处理请求]) --> CheckAuth[权限验证]
+ CheckAuth --> AuthOK{权限验证}
+ AuthOK -->|失败| AuthError[权限错误]
+ AuthOK -->|成功| ProcessType{处理类型}
+
+ ProcessType -->|调账| AdjustAccount[账务调整]
+ ProcessType -->|退款| RefundProcess[退款处理]
+ ProcessType -->|销账| WriteOff[销账处理]
+ ProcessType -->|预存调整| PrepaidAdjust[预存调整]
+
+ AdjustAccount --> ValidateAdjust[验证调整数据]
+ RefundProcess --> ValidateRefund[验证退款数据]
+ WriteOff --> ValidateWriteOff[验证销账数据]
+ PrepaidAdjust --> ValidatePrepaid[验证预存数据]
+
+ ValidateAdjust --> AdjustApproval[调账审批]
+ ValidateRefund --> RefundApproval[退款审批]
+ ValidateWriteOff --> WriteOffApproval[销账审批]
+ ValidatePrepaid --> PrepaidApproval[预存审批]
+
+ AdjustApproval --> ApprovalResult{审批结果}
+ RefundApproval --> ApprovalResult
+ WriteOffApproval --> ApprovalResult
+ PrepaidApproval --> ApprovalResult
+
+ ApprovalResult -->|拒绝| ApprovalReject[审批拒绝]
+ ApprovalResult -->|通过| ExecuteProcess[执行处理]
+
+ ExecuteProcess --> UpdateAccount[更新账户]
+ UpdateAccount --> RecordLog[记录日志]
+ RecordLog --> Complete([处理完成])
+
+ AuthError --> End([结束])
+ ApprovalReject --> End
+未销调整:处理各类账务调整需求 - +水量调整:调整用水量和相关费用 - 金额调整:直接调整账单金额 - +违约金减免:减免或取消违约金 - 费用追加:补收相关费用
+特殊开账:处理特殊情况的账单生成 - +补抄开账:补录抄表数据并生成账单 - 估抄开账:估算用水量生成账单 - +平均开账:基于历史用量平均开账
+账务退款:处理各类退款业务 - +多缴退款:退还多缴的水费 - 预付款退款:退还预存余额 - +错误缴费退款:退还错误缴费
+@RestController
+@RequestMapping("/admin-api/water/account")
+@Tag(name = "管理后台 - 账务处理")
+@Validated
+public class AccountProcessController {
+
+ @PostMapping("/adjust")
+ @Operation(summary = "账务调整")
+ @PreAuthorize("@ss.hasPermission('water:account:adjust')")
+ public CommonResult<Boolean> adjustAccount(@Valid @RequestBody AccountAdjustReqVO adjustReqVO);
+
+ @PostMapping("/refund")
+ @Operation(summary = "退款处理")
+ @PreAuthorize("@ss.hasPermission('water:account:refund')")
+ public CommonResult<Boolean> processRefund(@Valid @RequestBody RefundProcessReqVO refundReqVO);
+
+ @PostMapping("/write-off")
+ @Operation(summary = "销账处理")
+ @PreAuthorize("@ss.hasPermission('water:account:write-off')")
+ public CommonResult<Boolean> writeOffAccount(@Valid @RequestBody WriteOffReqVO writeOffReqVO);
+}发票管理模块负责水费发票的全生命周期管理,支持纸质发票和电子发票。
+flowchart TD
+ Start([发票业务]) --> InvoiceType{发票类型}
+
+ InvoiceType -->|纸质发票| PaperInvoice[纸质发票管理]
+ InvoiceType -->|电子发票| EInvoice[电子发票管理]
+
+ PaperInvoice --> PaperStock[发票库存管理]
+ PaperStock --> PaperPrint[发票打印]
+ PaperPrint --> PaperRecord[打印记录]
+
+ EInvoice --> EInvoiceGenerate[电子发票生成]
+ EInvoiceGenerate --> EInvoiceSign[电子签章]
+ EInvoiceSign --> EInvoiceSend[发票推送]
+
+ PaperRecord --> InvoiceQuery[发票查询]
+ EInvoiceSend --> InvoiceQuery
+
+ InvoiceQuery --> InvoiceCancel{需要作废?}
+ InvoiceCancel -->|是| CancelInvoice[发票作废]
+ InvoiceCancel -->|否| Complete([完成])
+
+ CancelInvoice --> CancelRecord[作废记录]
+ CancelRecord --> Complete
+@RestController
+@RequestMapping("/admin-api/water/invoice")
+@Tag(name = "管理后台 - 发票管理")
+@Validated
+public class InvoiceController {
+
+ @PostMapping("/generate")
+ @Operation(summary = "生成发票")
+ public CommonResult<InvoiceRespVO> generateInvoice(@Valid @RequestBody InvoiceGenerateReqVO generateReqVO);
+
+ @PostMapping("/print")
+ @Operation(summary = "打印发票")
+ public CommonResult<Boolean> printInvoice(@Valid @RequestBody InvoicePrintReqVO printReqVO);
+
+ @PostMapping("/cancel")
+ @Operation(summary = "发票作废")
+ public CommonResult<Boolean> cancelInvoice(@Valid @RequestBody InvoiceCancelReqVO cancelReqVO);
+}代收业务模块负责处理各种渠道的水费代收业务,主要功能包括:
环卫系统模块负责管理与环卫相关的收费和计费业务,主要功能包括:
业务工单模块负责管理日常业务工单的流转和处理,主要功能包括:
表务系统负责水表的全生命周期管理,包括水表购置、安装、维修、更换等业务。
-表务工单模块负责处理各类表务作业,主要功能包括:
表务仓库模块负责水表的仓储管理,主要功能包括:
水表参数与基础信息模块负责维护水表相关的基础数据,主要功能包括:
物联网对接与数据同步模块负责水表数据的互联互通,主要功能包括:
报装系统负责新用户的报装立户管理,主要功能包括:
-报装流程模块负责新用户报装业务的全流程管理,主要功能包括:
一户一表管理模块负责实施”一户一表”改造,主要功能包括:
客户服务模块提供多渠道的客户服务功能,主要包括:
-系统配置模块提供各类系统参数的配置管理功能,主要包括:
-系统接口模块提供与外部系统的集成和数据交换功能,实现业务数据的互通互联。
-银行接口实现与银行系统的对接,支持代扣、托收等功能,主要包括:
支付宝和微信接口实现与第三方支付平台的对接,支持在线支付功能,主要包括:
短信接口提供短信通知和验证功能,主要包括:
集抄系统接口实现与智能水表集中抄表系统的对接,主要包括:
政务系统接口实现与地方政务平台和政务APP的对接,主要包括:
消火栓系统接口实现与消火栓系统的对接,主要功能包括:
其他系统对接模块负责与周边系统进行数据交换和业务协同,主要功能包括:
统计分析模块提供多维度的数据统计和分析功能,为管理决策提供数据支持。
-工程管理模块负责处理与供水工程相关的业务,包括工程申请、施工管理和工程验收等。
-抄表APP是针对移动端开发的抄表工具,支持外勤人员进行现场抄表、问题处理和工单管理等业务操作。
-接口服务模块提供系统对外的API接口管理和服务能力,实现与第三方系统的便捷集成。
-graph TB
+ subgraph "前端应用"
+ F1[管理后台<br/>yudao-ui-admin-vue3]
+ F2[移动端<br/>uni-app]
+ F3[客户端<br/>微信小程序]
+ end
+
+ subgraph "后端服务"
+ B1[认证服务<br/>Spring Security]
+ B2[业务服务<br/>RuoYi-Vue-Pro]
+ B3[网关服务<br/>Spring Cloud Gateway]
+ end
+
+ subgraph "数据存储"
+ D1[(OpenGauss 5.0+)]
+ D2[(Redis 6.0)]
+ D3[MinIO文件存储]
+ end
+
+ F1 --> B3
+ F2 --> B3
+ F3 --> B3
+
+ B3 --> B1
+ B3 --> B2
+
+ B1 --> D2
+ B2 --> D1
+ B2 --> D2
+ B2 --> D3
+后端技术整合: - Spring Boot 3.x作为核心框架 - +Spring Security 6.x提供安全认证 - MyBatis Plus 3.x简化数据访问 - +RuoYi-Vue-Pro提供基础功能框架
+前端技术整合: - Vue 3.x + TypeScript构建现代化前端 +- Element Plus提供UI组件库 - Vite作为构建工具 - Pinia进行状态管理
+数据库集成: - OpenGauss +5.0+作为主数据库,国产自主可控 - Redis 6.0提供缓存和会话管理 - +HikariCP连接池优化和读写分离支持
+中间件集成: - RabbitMQ提供消息队列 - +MinIO提供文件存储 - Elasticsearch提供全文搜索
+| 项目信息 | +详情 | +
|---|---|
| 项目名称 | +福建水务营收系统 | +
| 文档类型 | +概要设计文档 | +
| 技术框架 | +RuoYi-Vue-Pro + yudao-ui-admin-vue3 | +
| 文档版本 | +v1.0 | +
| 编写日期 | +2024-12-19 | +
| 文档状态 | +✅ 已完成 | +
福建水务业务系统的数据库设计基于MySQL/MariaDB数据库管理系统(同时支持国产OpenGauss数据库),采用关系型数据库模型,以支持业务系统的高并发、高可靠性需求。数据库设计遵循标准化、安全性、扩展性和性能优化的原则,为业务系统提供稳定、高效的数据存储和访问支持。
+福建水务营收系统采用华为OpenGauss +5.0+数据库,基于RuoYi-Vue-Pro框架规范设计。OpenGauss作为国产自主可控的企业级数据库,具有高性能、高可用、高安全的特点,完全满足水务行业对数据安全和国产化的要求。数据库架构支持多租户、高并发、高可用的业务需求,为水务营收业务提供稳定可靠的数据存储服务。
系统采用集中式数据库架构,主要包含以下组件:
+系统采用基于字段的方式实现多租户架构,主要包括:
-系统基于MyBatis Plus框架实现数据访问层,主要特点包括:
-系统中所有业务表都包含以下通用字段:
+graph TB
+ subgraph "应用层"
+ APP[Water Biz Application<br/>RuoYi-Vue-Pro]
+ end
+
+ subgraph "数据访问层"
+ MP[MyBatis Plus<br/>ORM框架]
+ CACHE[Redis缓存<br/>热点数据]
+ end
+
+ subgraph "数据存储层"
+ subgraph "OpenGauss主从集群"
+ MASTER[(OpenGauss主库<br/>读写)]
+ SLAVE[(OpenGauss从库<br/>只读)]
+ end
+
+ subgraph "业务数据库"
+ DB_CUSTOMER[(客户数据库<br/>Customer DB)]
+ DB_BILLING[(营收数据库<br/>Billing DB)]
+ DB_METER[(表务数据库<br/>Meter DB)]
+ DB_SYSTEM[(系统数据库<br/>System DB)]
+ end
+
+ subgraph "数据归档"
+ DB_HISTORY[(历史数据库<br/>Archive DB)]
+ BACKUP[(备份存储<br/>Backup Storage)]
+ end
+ end
+
+ APP --> MP
+ APP --> CACHE
+ MP --> MASTER
+ MASTER --> SLAVE
+ MASTER --> DB_CUSTOMER
+ MASTER --> DB_BILLING
+ MASTER --> DB_METER
+ MASTER --> DB_SYSTEM
+ SLAVE --> DB_HISTORY
+ MASTER --> BACKUP
+graph TB
+ subgraph "多租户数据隔离"
+ TENANT1[租户1: 福建水务集团]
+ TENANT2[租户2: 厦门分公司]
+ TENANT3[租户3: 泉州分公司]
+ end
+
+ subgraph "共享数据库"
+ subgraph "业务表结构"
+ TABLE1[water_customer<br/>+ tenant_id]
+ TABLE2[water_meter<br/>+ tenant_id]
+ TABLE3[water_bill<br/>+ tenant_id]
+ TABLE4[water_payment<br/>+ tenant_id]
+ end
+
+ subgraph "租户隔离机制"
+ INTERCEPTOR[MyBatis Plus<br/>多租户拦截器]
+ FILTER[数据权限过滤器]
+ end
+ end
+
+ TENANT1 --> INTERCEPTOR
+ TENANT2 --> INTERCEPTOR
+ TENANT3 --> INTERCEPTOR
+
+ INTERCEPTOR --> FILTER
+ FILTER --> TABLE1
+ FILTER --> TABLE2
+ FILTER --> TABLE3
+ FILTER --> TABLE4
+所有业务表统一包含以下基础字段:
| 字段名 | 数据类型 | 长度 | -是否为空 | +默认值 | 描述 | id | BIGINT | - | -否 | +AUTO_INCREMENT | 主键ID |
|---|---|---|---|---|---|---|
| tenant_id | +BIGINT | +- | +0 | +租户ID(多租户隔离) | +||
| creator | VARCHAR | 64 | -是 | +’’ | 创建者 | |
| create_time | DATETIME | - | -否 | +CURRENT_TIMESTAMP | 创建时间 | |
| updater | VARCHAR | 64 | -是 | +’’ | 更新者 | |
| update_time | DATETIME | - | -是 | +CURRENT_TIMESTAMP | 更新时间 | |
| deleted | -TINYINT | +BIT | 1 | -否 | -是否删除(0正常,1删除) | -|
| tenant_id | -BIGINT | -- | -否 | -租户ID | -||
| version | -INT | -- | -是 | -乐观锁版本号 | +0 | +逻辑删除标识 |
系统主要包含以下核心数据实体:
-erDiagram
+ WATER_CUSTOMER {
+ bigint id PK "主键ID"
+ varchar customer_code UK "客户编号"
+ varchar customer_name "客户名称"
+ varchar customer_type "客户类型"
+ varchar id_type "证件类型"
+ varchar id_number "证件号码"
+ varchar phone "联系电话"
+ varchar address "详细地址"
+ varchar area_code "行政区划代码"
+ tinyint status "状态"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_METER {
+ bigint id PK "主键ID"
+ varchar meter_code UK "水表编号"
+ varchar meter_no "水表表号"
+ varchar meter_type "水表类型"
+ varchar meter_model "水表型号"
+ varchar meter_caliber "水表口径"
+ date install_date "安装日期"
+ varchar install_position "安装位置"
+ decimal initial_reading "初始读数"
+ decimal current_reading "当前读数"
+ varchar reading_cycle "抄表周期"
+ varchar book_code "册本编号"
+ tinyint status "状态"
+ bigint customer_id FK "客户ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_CUSTOMER_ACCOUNT {
+ bigint id PK "主键ID"
+ decimal balance "账户余额"
+ decimal credit_amount "信用额度"
+ date last_payment_date "最近缴费日期"
+ tinyint status "账户状态"
+ bigint customer_id FK "客户ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_CUSTOMER ||--o{ WATER_METER : "拥有"
+ WATER_CUSTOMER ||--|| WATER_CUSTOMER_ACCOUNT : "对应"
+erDiagram
+ WATER_METER_READING {
+ bigint id PK "主键ID"
+ varchar reading_code UK "抄表记录编号"
+ date reading_date "抄表日期"
+ decimal reading_value "抄表读数"
+ decimal prev_reading_value "上次读数"
+ decimal water_usage "用水量"
+ varchar reading_type "抄表类型"
+ varchar reader_id "抄表员ID"
+ varchar remark "备注"
+ tinyint status "状态"
+ bigint meter_id FK "水表ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_BILL {
+ bigint id PK "主键ID"
+ varchar bill_code UK "账单编号"
+ varchar bill_month "账期"
+ decimal water_usage "用水量"
+ decimal water_fee "水费金额"
+ decimal sewage_fee "污水处理费"
+ decimal other_fee "其他费用"
+ decimal total_amount "总金额"
+ date due_date "缴费截止日期"
+ tinyint bill_status "账单状态"
+ bigint customer_id FK "客户ID"
+ bigint meter_id FK "水表ID"
+ bigint reading_id FK "抄表记录ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_PAYMENT {
+ bigint id PK "主键ID"
+ varchar payment_code UK "缴费记录编号"
+ varchar payment_type "缴费类型"
+ varchar payment_channel "缴费渠道"
+ decimal payment_amount "缴费金额"
+ datetime payment_time "缴费时间"
+ varchar transaction_no "交易流水号"
+ varchar operator_id "操作员ID"
+ varchar remark "备注"
+ tinyint payment_status "缴费状态"
+ bigint bill_id FK "账单ID"
+ bigint customer_id FK "客户ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_METER_READING ||--|| WATER_BILL : "生成"
+ WATER_BILL ||--o{ WATER_PAYMENT : "对应"
+erDiagram
+ WATER_METER_ARCHIVE {
+ bigint id PK "主键ID"
+ varchar archive_code UK "档案编号"
+ varchar manufacturer "生产厂家"
+ date production_date "生产日期"
+ int valid_period "有效期(月)"
+ date verification_date "检定日期"
+ date next_verification_date "下次检定日期"
+ varchar certificate_no "检定证书号"
+ tinyint archive_status "档案状态"
+ bigint meter_id FK "水表ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_METER_WORKORDER {
+ bigint id PK "主键ID"
+ varchar workorder_code UK "工单编号"
+ varchar workorder_type "工单类型"
+ varchar workorder_status "工单状态"
+ date apply_date "申请日期"
+ date plan_date "计划执行日期"
+ date execute_date "实际执行日期"
+ varchar applicant_id "申请人ID"
+ varchar executor_id "执行人ID"
+ varchar reason "申请原因"
+ varchar result "执行结果"
+ bigint meter_id FK "水表ID"
+ bigint customer_id FK "客户ID"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_METER_STOCK {
+ bigint id PK "主键ID"
+ varchar stock_code UK "库存编号"
+ varchar warehouse_code "仓库编码"
+ varchar warehouse_name "仓库名称"
+ int stock_quantity "库存数量"
+ int min_stock "最小库存"
+ int max_stock "最大库存"
+ varchar meter_model "水表型号"
+ varchar meter_caliber "水表口径"
+ tinyint stock_status "库存状态"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ WATER_METER ||--|| WATER_METER_ARCHIVE : "对应"
+ WATER_METER ||--o{ WATER_METER_WORKORDER : "产生"
+erDiagram
+ SYSTEM_TENANT {
+ bigint id PK "主键ID"
+ varchar tenant_name "租户名称"
+ varchar tenant_code UK "租户编码"
+ varchar contact_name "联系人"
+ varchar contact_phone "联系电话"
+ varchar contact_email "联系邮箱"
+ tinyint tenant_status "租户状态"
+ datetime expire_time "过期时间"
+ varchar domain "域名"
+ varchar package_name "套餐名称"
+ int user_count "用户数量"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ SYSTEM_USERS {
+ bigint id PK "主键ID"
+ varchar username UK "用户名"
+ varchar password "密码"
+ varchar nickname "昵称"
+ varchar remark "备注"
+ varchar dept_id "部门ID"
+ varchar post_ids "岗位ID列表"
+ varchar email "邮箱"
+ varchar mobile "手机号"
+ tinyint sex "性别"
+ varchar avatar "头像"
+ tinyint status "状态"
+ datetime login_date "最后登录时间"
+ varchar login_ip "最后登录IP"
+ bigint tenant_id "租户ID"
+ varchar creator "创建者"
+ datetime create_time "创建时间"
+ varchar updater "更新者"
+ datetime update_time "更新时间"
+ tinyint deleted "是否删除"
+ }
+
+ SYSTEM_TENANT ||--o{ SYSTEM_USERS : "包含"
+erDiagram
+ WATER_METER_WORKORDER {
+ bigint id PK "主键ID"
+ varchar workorder_code UK "工单编号"
+ varchar workorder_type "工单类型"
+ varchar workorder_status "工单状态"
+ date apply_date "申请日期"
+ date plan_date "计划执行日期"
+ date execute_date "实际执行日期"
+ varchar applicant_id "申请人ID"
+ varchar executor_id "执行人ID"
+ varchar reason "申请原因"
+ varchar result "执行结果"
+ bigint meter_id FK "水表ID"
+ bigint customer_id FK "客户ID"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_METER_STOCK {
+ bigint id PK "主键ID"
+ varchar stock_code UK "库存编号"
+ varchar meter_brand "水表品牌"
+ varchar meter_model "水表型号"
+ varchar meter_caliber "水表口径"
+ int stock_quantity "库存数量"
+ int min_stock "最小库存"
+ decimal unit_price "单价"
+ varchar warehouse_location "仓库位置"
+ tinyint stock_status "库存状态"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_METER_INVENTORY {
+ bigint id PK "主键ID"
+ varchar inventory_code UK "出入库编号"
+ varchar inventory_type "出入库类型"
+ int quantity "数量"
+ decimal unit_price "单价"
+ decimal total_amount "总金额"
+ varchar operator_id "操作员ID"
+ datetime operation_time "操作时间"
+ varchar remark "备注"
+ bigint stock_id FK "库存ID"
+ bigint workorder_id FK "工单ID"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_METER ||--o{ WATER_METER_WORKORDER : "生成"
+ WATER_METER_STOCK ||--o{ WATER_METER_INVENTORY : "出入库"
+ WATER_METER_WORKORDER ||--o{ WATER_METER_INVENTORY : "关联"
+erDiagram
+ WATER_DICT_TYPE {
+ bigint id PK "主键ID"
+ varchar dict_name "字典名称"
+ varchar dict_type UK "字典类型"
+ varchar remark "备注"
+ tinyint status "状态"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_DICT_DATA {
+ bigint id PK "主键ID"
+ varchar dict_type "字典类型"
+ varchar dict_label "字典标签"
+ varchar dict_value "字典键值"
+ int dict_sort "字典排序"
+ varchar color_type "颜色类型"
+ varchar css_class "CSS类名"
+ varchar remark "备注"
+ tinyint status "状态"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_CONFIG {
+ bigint id PK "主键ID"
+ varchar config_name "参数名称"
+ varchar config_key UK "参数键名"
+ varchar config_value "参数键值"
+ varchar config_type "系统内置"
+ varchar remark "备注"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_PRICE_CONFIG {
+ bigint id PK "主键ID"
+ varchar price_name "水价名称"
+ varchar customer_type "客户类型"
+ varchar price_type "价格类型"
+ decimal base_price "基础价格"
+ decimal sewage_price "污水处理费"
+ decimal garbage_price "垃圾处理费"
+ date effective_date "生效日期"
+ date expire_date "失效日期"
+ tinyint status "状态"
+ bigint tenant_id "租户ID"
+ }
+
+ WATER_DICT_TYPE ||--o{ WATER_DICT_DATA : "包含"
+CREATE TABLE `water_customer` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `customer_code` varchar(32) NOT NULL COMMENT '客户编号',
+ `customer_name` varchar(100) NOT NULL COMMENT '客户名称',
+ `customer_type` varchar(20) NOT NULL COMMENT '客户类型(居民:RESIDENT,非居民:NON_RESIDENT,工业:INDUSTRIAL,行政:ADMINISTRATIVE)',
+ `id_type` varchar(20) DEFAULT NULL COMMENT '证件类型(身份证:ID_CARD,营业执照:BUSINESS_LICENSE)',
+ `id_number` varchar(30) DEFAULT NULL COMMENT '证件号码',
+ `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
+ `mobile` varchar(20) DEFAULT NULL COMMENT '手机号码',
+ `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
+ `address` varchar(500) DEFAULT NULL COMMENT '详细地址',
+ `area_code` varchar(20) DEFAULT NULL COMMENT '行政区划代码',
+ `postal_code` varchar(10) DEFAULT NULL COMMENT '邮政编码',
+ `contact_person` varchar(50) DEFAULT NULL COMMENT '联系人',
+ `bank_account` varchar(50) DEFAULT NULL COMMENT '银行账户',
+ `bank_name` varchar(100) DEFAULT NULL COMMENT '开户银行',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注信息',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态(0:停用,1:正常,2:欠费,3:销户)',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_customer_code` (`customer_code`, `tenant_id`),
+ KEY `idx_customer_name` (`customer_name`),
+ KEY `idx_phone` (`phone`),
+ KEY `idx_id_number` (`id_number`),
+ KEY `idx_tenant_customer_type` (`tenant_id`, `customer_type`),
+ KEY `idx_status` (`status`),
+ KEY `idx_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户基本信息表';CREATE TABLE `water_meter` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `meter_code` varchar(32) NOT NULL COMMENT '水表编号',
+ `meter_no` varchar(30) DEFAULT NULL COMMENT '水表表号',
+ `meter_type` varchar(20) NOT NULL COMMENT '水表类型(机械:MECHANICAL,智能:SMART,远传:REMOTE)',
+ `meter_model` varchar(50) DEFAULT NULL COMMENT '水表型号',
+ `meter_caliber` varchar(10) DEFAULT NULL COMMENT '水表口径(15mm,20mm,25mm等)',
+ `manufacturer` varchar(100) DEFAULT NULL COMMENT '生产厂家',
+ `production_date` date DEFAULT NULL COMMENT '生产日期',
+ `install_date` date DEFAULT NULL COMMENT '安装日期',
+ `install_position` varchar(500) DEFAULT NULL COMMENT '安装位置',
+ `longitude` decimal(10,7) DEFAULT NULL COMMENT '经度',
+ `latitude` decimal(10,7) DEFAULT NULL COMMENT '纬度',
+ `initial_reading` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '初始读数',
+ `current_reading` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '当前读数',
+ `reading_cycle` varchar(20) NOT NULL DEFAULT 'MONTHLY' COMMENT '抄表周期(月度:MONTHLY,双月:BIMONTHLY,季度:QUARTERLY)',
+ `book_code` varchar(32) DEFAULT NULL COMMENT '册本编号',
+ `reading_route` varchar(100) DEFAULT NULL COMMENT '抄表路线',
+ `meter_status` tinyint NOT NULL DEFAULT '1' COMMENT '水表状态(0:停用,1:正常,2:故障,3:拆除)',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_meter_code` (`meter_code`, `tenant_id`),
+ KEY `idx_meter_no` (`meter_no`),
+ KEY `idx_customer_id` (`customer_id`),
+ KEY `idx_book_code` (`book_code`),
+ KEY `idx_meter_type` (`meter_type`),
+ KEY `idx_meter_status` (`meter_status`),
+ KEY `idx_tenant_status` (`tenant_id`, `meter_status`),
+ CONSTRAINT `fk_meter_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水表信息表';CREATE TABLE `water_meter_workorder` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `workorder_code` varchar(32) NOT NULL COMMENT '工单编号',
+ `workorder_type` varchar(20) NOT NULL COMMENT '工单类型(换表:CHANGE,移表:MOVE,拆表:REMOVE,装表:INSTALL,维修:REPAIR)',
+ `workorder_status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT '工单状态(待处理:PENDING,执行中:PROCESSING,已完成:COMPLETED,已取消:CANCELLED)',
+ `apply_date` date NOT NULL COMMENT '申请日期',
+ `plan_date` date DEFAULT NULL COMMENT '计划执行日期',
+ `execute_date` date DEFAULT NULL COMMENT '实际执行日期',
+ `applicant_id` varchar(20) DEFAULT NULL COMMENT '申请人ID',
+ `applicant_name` varchar(50) DEFAULT NULL COMMENT '申请人姓名',
+ `executor_id` varchar(20) DEFAULT NULL COMMENT '执行人ID',
+ `executor_name` varchar(50) DEFAULT NULL COMMENT '执行人姓名',
+ `reason` varchar(500) DEFAULT NULL COMMENT '申请原因',
+ `result` varchar(500) DEFAULT NULL COMMENT '执行结果',
+ `old_meter_no` varchar(30) DEFAULT NULL COMMENT '旧水表表号',
+ `new_meter_no` varchar(30) DEFAULT NULL COMMENT '新水表表号',
+ `old_reading` decimal(10,2) DEFAULT NULL COMMENT '旧表读数',
+ `new_reading` decimal(10,2) DEFAULT NULL COMMENT '新表读数',
+ `cost_amount` decimal(10,2) DEFAULT NULL COMMENT '费用金额',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `meter_id` bigint NOT NULL COMMENT '水表ID',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_workorder_code` (`workorder_code`, `tenant_id`),
+ KEY `idx_workorder_type` (`workorder_type`),
+ KEY `idx_workorder_status` (`workorder_status`),
+ KEY `idx_apply_date` (`apply_date`),
+ KEY `idx_meter_id` (`meter_id`),
+ KEY `idx_customer_id` (`customer_id`),
+ KEY `idx_tenant_type_status` (`tenant_id`, `workorder_type`, `workorder_status`),
+ CONSTRAINT `fk_workorder_meter` FOREIGN KEY (`meter_id`) REFERENCES `water_meter` (`id`),
+ CONSTRAINT `fk_workorder_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='表务工单表';CREATE TABLE `water_meter_stock` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `stock_code` varchar(32) NOT NULL COMMENT '库存编号',
+ `meter_brand` varchar(50) NOT NULL COMMENT '水表品牌',
+ `meter_model` varchar(50) NOT NULL COMMENT '水表型号',
+ `meter_caliber` varchar(10) NOT NULL COMMENT '水表口径',
+ `meter_type` varchar(20) NOT NULL COMMENT '水表类型',
+ `stock_quantity` int NOT NULL DEFAULT '0' COMMENT '库存数量',
+ `min_stock` int NOT NULL DEFAULT '0' COMMENT '最小库存',
+ `max_stock` int DEFAULT NULL COMMENT '最大库存',
+ `unit_price` decimal(10,2) DEFAULT NULL COMMENT '单价',
+ `warehouse_location` varchar(100) DEFAULT NULL COMMENT '仓库位置',
+ `supplier` varchar(100) DEFAULT NULL COMMENT '供应商',
+ `purchase_date` date DEFAULT NULL COMMENT '进货日期',
+ `warranty_period` int DEFAULT '24' COMMENT '质保期(月)',
+ `stock_status` tinyint NOT NULL DEFAULT '1' COMMENT '库存状态(0:停用,1:正常,2:缺货,3:超储)',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_stock_code` (`stock_code`, `tenant_id`),
+ KEY `idx_meter_brand` (`meter_brand`),
+ KEY `idx_meter_model` (`meter_model`),
+ KEY `idx_meter_caliber` (`meter_caliber`),
+ KEY `idx_stock_status` (`stock_status`),
+ KEY `idx_tenant_brand_model` (`tenant_id`, `meter_brand`, `meter_model`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水表库存管理表';CREATE TABLE `water_dict_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `dict_name` varchar(100) NOT NULL COMMENT '字典名称',
+ `dict_type` varchar(100) NOT NULL COMMENT '字典类型',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态(0:停用,1:正常)',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_dict_type` (`dict_type`, `tenant_id`),
+ KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据字典类型表';-- OpenGauss数据库DDL语句
+CREATE TABLE water_customer (
+ id SERIAL PRIMARY KEY,
+ customer_code VARCHAR(32) NOT NULL,
+ customer_name VARCHAR(100) NOT NULL,
+ customer_type VARCHAR(20) NOT NULL CHECK (customer_type IN ('RESIDENT','NON_RESIDENT','INDUSTRIAL','ADMINISTRATIVE')),
+ id_type VARCHAR(20) DEFAULT NULL CHECK (id_type IN ('ID_CARD','BUSINESS_LICENSE') OR id_type IS NULL),
+ id_number VARCHAR(30) DEFAULT NULL,
+ phone VARCHAR(20) DEFAULT NULL,
+ mobile VARCHAR(20) DEFAULT NULL,
+ email VARCHAR(100) DEFAULT NULL,
+ address VARCHAR(500) DEFAULT NULL,
+ area_code VARCHAR(20) DEFAULT NULL,
+ postal_code VARCHAR(10) DEFAULT NULL,
+ contact_person VARCHAR(50) DEFAULT NULL,
+ bank_account VARCHAR(50) DEFAULT NULL,
+ bank_name VARCHAR(100) DEFAULT NULL,
+ remark VARCHAR(500) DEFAULT NULL,
+ status SMALLINT NOT NULL DEFAULT 1 CHECK (status IN (0,1,2,3)),
+ tenant_id BIGINT NOT NULL DEFAULT 0,
+ creator VARCHAR(64) DEFAULT '',
+ create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater VARCHAR(64) DEFAULT '',
+ update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted BOOLEAN NOT NULL DEFAULT FALSE
+);
+
+-- 创建注释
+COMMENT ON TABLE water_customer IS '客户基本信息表';
+COMMENT ON COLUMN water_customer.id IS '主键ID';
+COMMENT ON COLUMN water_customer.customer_code IS '客户编号';
+COMMENT ON COLUMN water_customer.customer_name IS '客户名称';
+COMMENT ON COLUMN water_customer.customer_type IS '客户类型(居民:RESIDENT,非居民:NON_RESIDENT,工业:INDUSTRIAL,行政:ADMINISTRATIVE)';
+COMMENT ON COLUMN water_customer.id_type IS '证件类型(身份证:ID_CARD,营业执照:BUSINESS_LICENSE)';
+COMMENT ON COLUMN water_customer.id_number IS '证件号码';
+COMMENT ON COLUMN water_customer.phone IS '联系电话';
+COMMENT ON COLUMN water_customer.mobile IS '手机号码';
+COMMENT ON COLUMN water_customer.email IS '邮箱';
+COMMENT ON COLUMN water_customer.address IS '详细地址';
+COMMENT ON COLUMN water_customer.area_code IS '行政区划代码';
+COMMENT ON COLUMN water_customer.postal_code IS '邮政编码';
+COMMENT ON COLUMN water_customer.contact_person IS '联系人';
+COMMENT ON COLUMN water_customer.bank_account IS '银行账户';
+COMMENT ON COLUMN water_customer.bank_name IS '开户银行';
+COMMENT ON COLUMN water_customer.remark IS '备注信息';
+COMMENT ON COLUMN water_customer.status IS '状态(0:停用,1:正常,2:欠费,3:销户)';
+COMMENT ON COLUMN water_customer.tenant_id IS '租户ID';
+COMMENT ON COLUMN water_customer.creator IS '创建者';
+COMMENT ON COLUMN water_customer.create_time IS '创建时间';
+COMMENT ON COLUMN water_customer.updater IS '更新者';
+COMMENT ON COLUMN water_customer.update_time IS '更新时间';
+COMMENT ON COLUMN water_customer.deleted IS '是否删除';
+
+-- 创建索引
+CREATE UNIQUE INDEX uk_customer_code ON water_customer (customer_code, tenant_id);
+CREATE INDEX idx_customer_name ON water_customer (customer_name);
+CREATE INDEX idx_phone ON water_customer (phone);
+CREATE INDEX idx_id_number ON water_customer (id_number);
+CREATE INDEX idx_tenant_customer_type ON water_customer (tenant_id, customer_type);
+CREATE INDEX idx_status ON water_customer (status);
+CREATE INDEX idx_create_time ON water_customer (create_time);
+
+-- 创建更新时间触发器
+CREATE OR REPLACE FUNCTION update_timestamp()
+RETURNS TRIGGER AS $$
+BEGIN
+ NEW.update_time = CURRENT_TIMESTAMP;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER water_customer_update_timestamp
+ BEFORE UPDATE ON water_customer
+ FOR EACH ROW
+ EXECUTE FUNCTION update_timestamp();CREATE TABLE `water_meter` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `meter_code` varchar(32) NOT NULL COMMENT '水表编号',
+ `meter_no` varchar(30) DEFAULT NULL COMMENT '水表表号',
+ `meter_type` varchar(20) NOT NULL COMMENT '水表类型(机械:MECHANICAL,智能:SMART,远传:REMOTE)',
+ `meter_model` varchar(50) DEFAULT NULL COMMENT '水表型号',
+ `meter_caliber` varchar(10) DEFAULT NULL COMMENT '水表口径(15mm,20mm,25mm等)',
+ `manufacturer` varchar(100) DEFAULT NULL COMMENT '生产厂家',
+ `production_date` date DEFAULT NULL COMMENT '生产日期',
+ `install_date` date DEFAULT NULL COMMENT '安装日期',
+ `install_position` varchar(500) DEFAULT NULL COMMENT '安装位置',
+ `longitude` decimal(10,7) DEFAULT NULL COMMENT '经度',
+ `latitude` decimal(10,7) DEFAULT NULL COMMENT '纬度',
+ `initial_reading` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '初始读数',
+ `current_reading` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '当前读数',
+ `reading_cycle` varchar(20) NOT NULL DEFAULT 'MONTHLY' COMMENT '抄表周期(月度:MONTHLY,双月:BIMONTHLY,季度:QUARTERLY)',
+ `book_code` varchar(32) DEFAULT NULL COMMENT '册本编号',
+ `reading_route` varchar(100) DEFAULT NULL COMMENT '抄表路线',
+ `meter_status` tinyint NOT NULL DEFAULT '1' COMMENT '水表状态(0:停用,1:正常,2:故障,3:拆除)',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_meter_code` (`meter_code`, `tenant_id`),
+ KEY `idx_meter_no` (`meter_no`),
+ KEY `idx_customer_id` (`customer_id`),
+ KEY `idx_book_code` (`book_code`),
+ KEY `idx_meter_type` (`meter_type`),
+ KEY `idx_meter_status` (`meter_status`),
+ KEY `idx_tenant_status` (`tenant_id`, `meter_status`),
+ CONSTRAINT `fk_meter_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水表信息表';CREATE TABLE `water_customer_account` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `account_code` varchar(32) NOT NULL COMMENT '账户编号',
+ `balance` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '账户余额',
+ `credit_amount` decimal(12,2) DEFAULT '0.00' COMMENT '信用额度',
+ `deposit_amount` decimal(12,2) DEFAULT '0.00' COMMENT '保证金',
+ `frozen_amount` decimal(12,2) DEFAULT '0.00' COMMENT '冻结金额',
+ `last_payment_date` date DEFAULT NULL COMMENT '最近缴费日期',
+ `last_payment_amount` decimal(12,2) DEFAULT NULL COMMENT '最近缴费金额',
+ `arrears_amount` decimal(12,2) DEFAULT '0.00' COMMENT '欠费金额',
+ `arrears_months` int DEFAULT '0' COMMENT '欠费月数',
+ `account_status` tinyint NOT NULL DEFAULT '1' COMMENT '账户状态(0:停用,1:正常,2:欠费,3:冻结)',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_account_code` (`account_code`, `tenant_id`),
+ UNIQUE KEY `uk_customer_account` (`customer_id`, `tenant_id`),
+ KEY `idx_account_status` (`account_status`),
+ KEY `idx_balance` (`balance`),
+ KEY `idx_arrears` (`arrears_amount`),
+ CONSTRAINT `fk_account_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户账户信息表';CREATE TABLE `water_meter_reading` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `reading_code` varchar(32) NOT NULL COMMENT '抄表记录编号',
+ `reading_date` date NOT NULL COMMENT '抄表日期',
+ `reading_time` datetime DEFAULT NULL COMMENT '抄表时间',
+ `reading_value` decimal(10,2) NOT NULL COMMENT '抄表读数',
+ `prev_reading_value` decimal(10,2) DEFAULT NULL COMMENT '上次读数',
+ `water_usage` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '用水量',
+ `reading_type` varchar(20) NOT NULL COMMENT '抄表类型(手工:MANUAL,远传:REMOTE,自报:SELF_REPORT,估算:ESTIMATE)',
+ `reading_method` varchar(20) DEFAULT NULL COMMENT '抄表方式(现场:FIELD,拍照:PHOTO,NFC:NFC,扫码:SCAN)',
+ `reader_id` varchar(20) DEFAULT NULL COMMENT '抄表员ID',
+ `reader_name` varchar(50) DEFAULT NULL COMMENT '抄表员姓名',
+ `photo_url` varchar(255) DEFAULT NULL COMMENT '抄表照片URL',
+ `reading_location` varchar(200) DEFAULT NULL COMMENT '抄表位置',
+ `abnormal_flag` tinyint DEFAULT '0' COMMENT '异常标识(0:正常,1:异常)',
+ `abnormal_reason` varchar(200) DEFAULT NULL COMMENT '异常原因',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `reading_status` tinyint NOT NULL DEFAULT '0' COMMENT '状态(0:未复核,1:已复核,2:已开账,3:作废)',
+ `meter_id` bigint NOT NULL COMMENT '水表ID',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_reading_code` (`reading_code`, `tenant_id`),
+ KEY `idx_meter_reading_date` (`meter_id`, `reading_date`),
+ KEY `idx_reading_date` (`reading_date`),
+ KEY `idx_reader_id` (`reader_id`),
+ KEY `idx_reading_status` (`reading_status`),
+ KEY `idx_customer_id` (`customer_id`),
+ KEY `idx_tenant_meter_date` (`tenant_id`, `meter_id`, `reading_date`),
+ CONSTRAINT `fk_reading_meter` FOREIGN KEY (`meter_id`) REFERENCES `water_meter` (`id`),
+ CONSTRAINT `fk_reading_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='抄表记录表';CREATE TABLE `water_bill` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `bill_code` varchar(32) NOT NULL COMMENT '账单编号',
+ `bill_month` varchar(7) NOT NULL COMMENT '账期(格式:YYYY-MM)',
+ `bill_date` date NOT NULL COMMENT '开账日期',
+ `water_usage` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '用水量',
+ `prev_reading` decimal(10,2) DEFAULT NULL COMMENT '上期读数',
+ `current_reading` decimal(10,2) DEFAULT NULL COMMENT '本期读数',
+ `reading_days` int DEFAULT NULL COMMENT '抄表间隔天数',
+ `water_price` decimal(8,4) DEFAULT NULL COMMENT '水价单价',
+ `water_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '水费金额',
+ `sewage_fee` decimal(10,2) DEFAULT '0.00' COMMENT '污水处理费',
+ `garbage_fee` decimal(10,2) DEFAULT '0.00' COMMENT '垃圾处理费',
+ `other_fee` decimal(10,2) DEFAULT '0.00' COMMENT '其他费用',
+ `adjustment_fee` decimal(10,2) DEFAULT '0.00' COMMENT '调整费用',
+ `late_fee` decimal(10,2) DEFAULT '0.00' COMMENT '滞纳金',
+ `total_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '总金额',
+ `paid_amount` decimal(10,2) DEFAULT '0.00' COMMENT '已缴金额',
+ `balance_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '余额',
+ `due_date` date NOT NULL COMMENT '缴费截止日期',
+ `billing_type` varchar(20) DEFAULT 'NORMAL' COMMENT '开账类型(正常:NORMAL,追补:SUPPLEMENT,调整:ADJUSTMENT)',
+ `bill_status` tinyint NOT NULL DEFAULT '0' COMMENT '账单状态(0:未缴费,1:已缴费,2:部分缴费,3:作废)',
+ `payment_status` tinyint DEFAULT '0' COMMENT '缴费状态(0:未缴,1:已缴,2:部分缴费)',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `meter_id` bigint NOT NULL COMMENT '水表ID',
+ `reading_id` bigint DEFAULT NULL COMMENT '抄表记录ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_bill_code` (`bill_code`, `tenant_id`),
+ KEY `idx_customer_bill_month` (`customer_id`, `bill_month`),
+ KEY `idx_meter_bill_month` (`meter_id`, `bill_month`),
+ KEY `idx_bill_status` (`bill_status`),
+ KEY `idx_due_date` (`due_date`),
+ KEY `idx_tenant_customer_month` (`tenant_id`, `customer_id`, `bill_month`),
+ CONSTRAINT `fk_bill_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`),
+ CONSTRAINT `fk_bill_meter` FOREIGN KEY (`meter_id`) REFERENCES `water_meter` (`id`),
+ CONSTRAINT `fk_bill_reading` FOREIGN KEY (`reading_id`) REFERENCES `water_meter_reading` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水费账单表';CREATE TABLE `water_payment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `payment_code` varchar(32) NOT NULL COMMENT '缴费记录编号',
+ `payment_type` varchar(20) NOT NULL COMMENT '缴费类型(正常缴费:NORMAL,预存:PREPAID,退费:REFUND)',
+ `payment_channel` varchar(20) NOT NULL COMMENT '缴费渠道(现金:CASH,银行卡:BANK_CARD,微信:WECHAT,支付宝:ALIPAY,银行代扣:BANK_DEDUCT)',
+ `payment_amount` decimal(10,2) NOT NULL COMMENT '缴费金额',
+ `actual_amount` decimal(10,2) DEFAULT NULL COMMENT '实收金额',
+ `change_amount` decimal(10,2) DEFAULT '0.00' COMMENT '找零金额',
+ `payment_time` datetime NOT NULL COMMENT '缴费时间',
+ `transaction_no` varchar(50) DEFAULT NULL COMMENT '交易流水号',
+ `third_party_no` varchar(50) DEFAULT NULL COMMENT '第三方交易号',
+ `operator_id` varchar(20) DEFAULT NULL COMMENT '操作员ID',
+ `operator_name` varchar(50) DEFAULT NULL COMMENT '操作员姓名',
+ `outlet_code` varchar(20) DEFAULT NULL COMMENT '营业网点代码',
+ `pos_machine_no` varchar(20) DEFAULT NULL COMMENT 'POS机编号',
+ `invoice_no` varchar(30) DEFAULT NULL COMMENT '发票号码',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `payment_status` tinyint NOT NULL DEFAULT '1' COMMENT '缴费状态(0:待确认,1:成功,2:失败,3:退费)',
+ `bill_id` bigint DEFAULT NULL COMMENT '账单ID',
+ `customer_id` bigint NOT NULL COMMENT '客户ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_payment_code` (`payment_code`, `tenant_id`),
+ KEY `idx_customer_payment_time` (`customer_id`, `payment_time`),
+ KEY `idx_payment_time` (`payment_time`),
+ KEY `idx_transaction_no` (`transaction_no`),
+ KEY `idx_operator_id` (`operator_id`),
+ KEY `idx_payment_status` (`payment_status`),
+ KEY `idx_bill_id` (`bill_id`),
+ CONSTRAINT `fk_payment_customer` FOREIGN KEY (`customer_id`) REFERENCES `water_customer` (`id`),
+ CONSTRAINT `fk_payment_bill` FOREIGN KEY (`bill_id`) REFERENCES `water_bill` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='缴费记录表';CREATE TABLE `water_meter_archive` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `archive_code` varchar(32) NOT NULL COMMENT '档案编号',
+ `manufacturer` varchar(100) DEFAULT NULL COMMENT '生产厂家',
+ `production_date` date DEFAULT NULL COMMENT '生产日期',
+ `valid_period` int DEFAULT '72' COMMENT '有效期(月)',
+ `verification_date` date DEFAULT NULL COMMENT '检定日期',
+ `next_verification_date` date DEFAULT NULL COMMENT '下次检定日期',
+ `certificate_no` varchar(50) DEFAULT NULL COMMENT '检定证书号',
+ `verification_agency` varchar(100) DEFAULT NULL COMMENT '检定机构',
+ `accuracy_level` varchar(10) DEFAULT NULL COMMENT '精度等级',
+ `max_flow` decimal(8,2) DEFAULT NULL COMMENT '最大流量',
+ `nominal_flow` decimal(8,2) DEFAULT NULL COMMENT '常用流量',
+ `min_flow` decimal(8,2) DEFAULT NULL COMMENT '最小流量',
+ `working_pressure` decimal(8,2) DEFAULT NULL COMMENT '工作压力',
+ `purchase_date` date DEFAULT NULL COMMENT '采购日期',
+ `purchase_price` decimal(10,2) DEFAULT NULL COMMENT '采购价格',
+ `supplier` varchar(100) DEFAULT NULL COMMENT '供应商',
+ `warranty_period` int DEFAULT '24' COMMENT '质保期(月)',
+ `installation_cost` decimal(10,2) DEFAULT NULL COMMENT '安装费用',
+ `archive_status` tinyint NOT NULL DEFAULT '1' COMMENT '档案状态(0:停用,1:正常,2:报废)',
+ `meter_id` bigint NOT NULL COMMENT '水表ID',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_archive_code` (`archive_code`, `tenant_id`),
+ UNIQUE KEY `uk_meter_archive` (`meter_id`, `tenant_id`),
+ KEY `idx_manufacturer` (`manufacturer`),
+ KEY `idx_verification_date` (`verification_date`),
+ KEY `idx_next_verification_date` (`next_verification_date`),
+ KEY `idx_archive_status` (`archive_status`),
+ CONSTRAINT `fk_archive_meter` FOREIGN KEY (`meter_id`) REFERENCES `water_meter` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水表档案表';CREATE TABLE `water_dict_data` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `dict_type` varchar(100) NOT NULL COMMENT '字典类型',
+ `dict_label` varchar(100) NOT NULL COMMENT '字典标签',
+ `dict_value` varchar(100) NOT NULL COMMENT '字典键值',
+ `dict_sort` int NOT NULL DEFAULT '0' COMMENT '字典排序',
+ `color_type` varchar(100) DEFAULT '' COMMENT '颜色类型',
+ `css_class` varchar(100) DEFAULT '' COMMENT 'CSS类名',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态(0:停用,1:正常)',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户ID',
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ KEY `idx_dict_type` (`dict_type`),
+ KEY `idx_dict_value` (`dict_value`),
+ KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据字典表';-- 插入基础字典数据
+INSERT INTO `water_dict_data` (`dict_type`, `dict_label`, `dict_value`, `dict_sort`, `status`, `remark`) VALUES
+('customer_type', '居民用户', 'RESIDENT', 1, 1, '居民生活用水'),
+('customer_type', '非居民用户', 'NON_RESIDENT', 2, 1, '非居民用水'),
+('customer_type', '工业用户', 'INDUSTRIAL', 3, 1, '工业生产用水'),
+('customer_type', '行政用户', 'ADMINISTRATIVE', 4, 1, '行政事业单位用水'),
+
+('meter_type', '机械水表', 'MECHANICAL', 1, 1, '传统机械式水表'),
+('meter_type', '智能水表', 'SMART', 2, 1, '智能电子水表'),
+('meter_type', '远传水表', 'REMOTE', 3, 1, '远程传输水表'),
+
+('reading_type', '人工抄表', 'MANUAL', 1, 1, '抄表员现场抄表'),
+('reading_type', '远程抄表', 'REMOTE', 2, 1, '远程自动抄表'),
+('reading_type', '客户自报', 'SELF_REPORT', 3, 1, '客户自主上报'),
+('reading_type', '估算抄表', 'ESTIMATE', 4, 1, '估算用水量'),
+
+('payment_channel', '现金', 'CASH', 1, 1, '现金缴费'),
+('payment_channel', '银行卡', 'BANK_CARD', 2, 1, '银行卡刷卡'),
+('payment_channel', '微信支付', 'WECHAT', 3, 1, '微信在线支付'),
+('payment_channel', '支付宝', 'ALIPAY', 4, 1, '支付宝在线支付'),
+('payment_channel', '银行代扣', 'BANK_DEDUCT', 5, 1, '银行自动代扣');-- 按月份分区的账单表
+CREATE TABLE water_bill (
+ -- 字段定义...
+) PARTITION BY RANGE (bill_month) (
+ PARTITION p202401 VALUES LESS THAN ('2024-02'),
+ PARTITION p202402 VALUES LESS THAN ('2024-03'),
+ PARTITION p202403 VALUES LESS THAN ('2024-04')
+ -- 继续按月创建分区...
+);-- 统计分析用的列存储表
+CREATE TABLE water_bill_stats (
+ -- 字段定义...
+) WITH (ORIENTATION = COLUMN);-- 配置参数缓存表
+CREATE TABLE water_config_cache (
+ -- 字段定义...
+) WITH (ORIENTATION = ROW, STORAGE_TYPE = USTORE);-- OpenGauss连接池参数
+ALTER SYSTEM SET max_connections = 200;
+ALTER SYSTEM SET shared_buffers = '256MB';
+ALTER SYSTEM SET effective_cache_size = '1GB';
+ALTER SYSTEM SET work_mem = '4MB';-- 启用并行查询
+ALTER SYSTEM SET max_parallel_workers = 8;
+ALTER SYSTEM SET max_parallel_workers_per_gather = 4;-- 客户编号唯一索引
+CREATE UNIQUE INDEX uk_customer_code ON water_customer (customer_code, tenant_id);
+-- 水表编号唯一索引
+CREATE UNIQUE INDEX uk_meter_code ON water_meter (meter_code, tenant_id);-- 多租户查询优化
+CREATE INDEX idx_tenant_customer_type ON water_customer (tenant_id, customer_type);
+-- 账单查询优化
+CREATE INDEX idx_tenant_customer_month ON water_bill (tenant_id, customer_id, bill_month);
+-- 抄表查询优化
+CREATE INDEX idx_tenant_meter_date ON water_meter_reading (tenant_id, meter_id, reading_date);-- 等值查询优化
+CREATE INDEX CONCURRENTLY idx_customer_phone_hash ON water_customer USING HASH (phone);-- 全文检索索引
+CREATE INDEX idx_customer_name_gin ON water_customer USING GIN (to_tsvector('simple', customer_name));-- 只对有效数据建索引
+CREATE INDEX idx_active_customers ON water_customer (customer_code) WHERE deleted = FALSE AND status = 1;-- 启用表级加密
+CREATE TABLE water_customer_encrypted (
+ -- 字段定义...
+) WITH (ENCRYPTION_TYPE = 'AES_128_CTR');
+
+-- 敏感字段加密
+ALTER TABLE water_customer
+ADD COLUMN id_number_encrypted BYTEA
+GENERATED ALWAYS AS (gs_encrypt_aes128(id_number, '密钥')) STORED;-- 创建多租户行级安全
+ALTER TABLE water_customer ENABLE ROW LEVEL SECURITY;
+
+-- 创建策略
+CREATE POLICY tenant_isolation_policy ON water_customer
+ FOR ALL TO PUBLIC
+ USING (tenant_id = current_setting('app.current_tenant_id')::bigint);-- 创建脱敏函数
+CREATE OR REPLACE FUNCTION mask_phone(phone_no TEXT)
+RETURNS TEXT AS $$
+BEGIN
+ RETURN SUBSTRING(phone_no, 1, 3) || '****' || SUBSTRING(phone_no, 8);
+END;
+$$ LANGUAGE plpgsql;
+
+-- 创建脱敏视图
+CREATE VIEW water_customer_masked AS
+SELECT
+ id, customer_code, customer_name,
+ mask_phone(phone) as phone_masked,
+ -- 其他字段...
+FROM water_customer;-- 创建业务角色
+CREATE ROLE water_admin;
+CREATE ROLE water_operator;
+CREATE ROLE water_viewer;
+
+-- 分配权限
+GRANT ALL ON water_customer TO water_admin;
+GRANT SELECT, INSERT, UPDATE ON water_customer TO water_operator;
+GRANT SELECT ON water_customer_masked TO water_viewer;-- 敏感字段权限控制
+REVOKE ALL ON water_customer FROM PUBLIC;
+GRANT SELECT (id, customer_name, phone) ON water_customer TO water_viewer;
+GRANT SELECT ON water_customer TO water_admin;-- 启用审计
+ALTER SYSTEM SET audit_enabled = on;
+ALTER SYSTEM SET audit_directory = '/data/audit';
+ALTER SYSTEM SET audit_file_remain_threshold = 1024;
+
+-- 配置审计策略
+SELECT pg_audit_set_policy('DDL_LOGIN_LOGOUT', 'DDL, LOGIN, LOGOUT');
+SELECT pg_audit_set_policy('DML_DCL', 'DML, DCL');-- 创建敏感操作触发器
+CREATE OR REPLACE FUNCTION audit_sensitive_data()
+RETURNS TRIGGER AS $$
+BEGIN
+ INSERT INTO audit_log (
+ table_name, operation, old_values, new_values,
+ user_name, operation_time
+ ) VALUES (
+ TG_TABLE_NAME, TG_OP,
+ row_to_json(OLD), row_to_json(NEW),
+ current_user, current_timestamp
+ );
+ RETURN COALESCE(NEW, OLD);
+END;
+$$ LANGUAGE plpgsql;
+
+-- 应用到敏感表
+CREATE TRIGGER audit_customer_changes
+ AFTER INSERT OR UPDATE OR DELETE ON water_customer
+ FOR EACH ROW EXECUTE FUNCTION audit_sensitive_data();-- 全量备份
+gs_backup -D /data/backup -h localhost -p 5432 -U backup_user
+
+-- 增量备份
+gs_backup -D /data/backup -h localhost -p 5432 -U backup_user --incremental
+
+-- 归档日志备份
+ALTER SYSTEM SET archive_mode = on;
+ALTER SYSTEM SET archive_command = 'cp %p /data/archive/%f';-- 主库配置
+ALTER SYSTEM SET synchronous_standby_names = 'standby1';
+ALTER SYSTEM SET synchronous_commit = on;
+
+-- 备库配置
+ALTER SYSTEM SET hot_standby = on;
+ALTER SYSTEM SET max_standby_streaming_delay = 30s;以下是系统主要表结构设计,按业务模块划分:
--- 使用国产SM4算法加密
+CREATE TABLE water_customer_sm4 (
+ -- 字段定义...
+) WITH (ENCRYPTION_TYPE = 'SM4_CTR');| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | +项目信息 | +详情 |
|---|---|---|---|---|---|---|---|
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -是 | -客户编号,主键 | +项目名称 | +福建水务营收系统 |
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | +文档类型 | +概要设计文档 |
| CUSTOMER_NAME | -VARCHAR | -100 | -否 | -否 | -客户名称 | +技术框架 | +RuoYi-Vue-Pro + yudao-ui-admin-vue3 |
| CUSTOMER_TYPE | -VARCHAR | -10 | -否 | -否 | -客户类型 | +文档版本 | +v1.0 |
| ID_TYPE | -VARCHAR | -10 | -是 | -否 | -证件类型 | +编写日期 | +2024-12-19 |
| ID_NUMBER | -VARCHAR | -30 | -是 | -否 | -证件号码 | -||
| PHONE | -VARCHAR | -20 | -是 | -否 | -联系电话 | -||
| ADDRESS | -VARCHAR | -200 | -是 | -否 | -地址 | -||
| AREA_CODE | -VARCHAR | -20 | -是 | -否 | -行政区划代码 | -||
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -||
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -||
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | +文档状态 | +🟡 进行中 |
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| METER_ID | -VARCHAR | -20 | -否 | -是 | -水表编号,主键 | -
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -否 | -客户编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| METER_NO | -VARCHAR | -30 | -否 | -否 | -水表号 | -
| METER_TYPE | -VARCHAR | -10 | -否 | -否 | -水表类型 | -
| METER_MODEL | -VARCHAR | -20 | -是 | -否 | -水表型号 | -
| METER_CALIBER | -VARCHAR | -10 | -是 | -否 | -水表口径 | -
| INSTALL_DATE | -DATE | -- | -是 | -否 | -安装日期 | -
| INSTALL_POSITION | -VARCHAR | -200 | -是 | -否 | -安装位置 | -
| INITIAL_READING | -DECIMAL | -10,2 | -否 | -否 | -初始读数 | -
| CURRENT_READING | -DECIMAL | -10,2 | -否 | -否 | -当前读数 | -
| READING_CYCLE | -VARCHAR | -10 | -否 | -否 | -抄表周期 | -
| BOOK_ID | -VARCHAR | -20 | -是 | -否 | -册本编号 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| ACCOUNT_ID | -VARCHAR | -20 | -否 | -是 | -账户编号,主键 | -
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -否 | -客户编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| BALANCE | -DECIMAL | -12,2 | -否 | -否 | -账户余额 | -
| CREDIT_AMOUNT | -DECIMAL | -12,2 | -是 | -否 | -信用额度 | -
| LAST_PAYMENT_DATE | -DATE | -- | -是 | -否 | -最近缴费日期 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| READING_ID | -VARCHAR | -20 | -否 | -是 | -抄表记录编号,主键 | -
| METER_ID | -VARCHAR | -20 | -否 | -否 | -水表编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| READING_DATE | -DATE | -- | -否 | -否 | -抄表日期 | -
| READING_VALUE | -DECIMAL | -10,2 | -否 | -否 | -抄表读数 | -
| PREV_READING_VALUE | -DECIMAL | -10,2 | -是 | -否 | -上次读数 | -
| WATER_USAGE | -DECIMAL | -10,2 | -否 | -否 | -用水量 | -
| READING_TYPE | -VARCHAR | -10 | -否 | -否 | -抄表类型(人工/远传/自报) | -
| READER_ID | -VARCHAR | -20 | -是 | -否 | -抄表员编号 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| REMARK | -VARCHAR | -200 | -是 | -否 | -备注 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| BILL_ID | -VARCHAR | -20 | -否 | -是 | -账单编号,主键 | -
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -否 | -客户编号,外键 | -
| METER_ID | -VARCHAR | -20 | -否 | -否 | -水表编号,外键 | -
| READING_ID | -VARCHAR | -20 | -是 | -否 | -抄表记录编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| BILL_MONTH | -VARCHAR | -7 | -否 | -否 | -账期(格式:YYYY-MM) | -
| WATER_USAGE | -DECIMAL | -10,2 | -否 | -否 | -用水量 | -
| WATER_FEE | -DECIMAL | -10,2 | -否 | -否 | -水费金额 | -
| OTHER_FEE | -DECIMAL | -10,2 | -是 | -否 | -其他费用 | -
| TOTAL_AMOUNT | -DECIMAL | -10,2 | -否 | -否 | -总金额 | -
| DUE_DATE | -DATE | -- | -否 | -否 | -缴费截止日期 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| PAYMENT_ID | -VARCHAR | -20 | -否 | -是 | -缴费记录编号,主键 | -
| BILL_ID | -VARCHAR | -20 | -是 | -否 | -账单编号,外键 | -
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -否 | -客户编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| PAYMENT_TYPE | -VARCHAR | -10 | -否 | -否 | -缴费类型 | -
| PAYMENT_CHANNEL | -VARCHAR | -10 | -否 | -否 | -缴费渠道 | -
| PAYMENT_AMOUNT | -DECIMAL | -10,2 | -否 | -否 | -缴费金额 | -
| PAYMENT_DATE | -DATETIME | -- | -否 | -否 | -缴费时间 | -
| TRANSACTION_NO | -VARCHAR | -30 | -是 | -否 | -交易流水号 | -
| OPERATOR_ID | -VARCHAR | -20 | -是 | -否 | -操作员编号 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| REMARK | -VARCHAR | -200 | -是 | -否 | -备注 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| METER_ARCHIVE_ID | -VARCHAR | -20 | -否 | -是 | -水表档案编号,主键 | -
| METER_ID | -VARCHAR | -20 | -否 | -否 | -水表编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| FACTORY | -VARCHAR | -50 | -是 | -否 | -生产厂家 | -
| PRODUCTION_DATE | -DATE | -- | -是 | -否 | -生产日期 | -
| VALID_PERIOD | -INT | -- | -是 | -否 | -有效期(月) | -
| VERIFICATION_DATE | -DATE | -- | -是 | -否 | -检定日期 | -
| NEXT_VERIFICATION_DATE | -DATE | -- | -是 | -否 | -下次检定日期 | -
| STATUS | -VARCHAR | -10 | -否 | -否 | -状态 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
| 字段名 | -数据类型 | -长度 | -是否为空 | -主键 | -描述 | -
|---|---|---|---|---|---|
| WORKORDER_ID | -VARCHAR | -20 | -否 | -是 | -工单编号,主键 | -
| METER_ID | -VARCHAR | -20 | -否 | -否 | -水表编号,外键 | -
| CUSTOMER_ID | -VARCHAR | -20 | -否 | -否 | -客户编号,外键 | -
| TENANT_ID | -VARCHAR | -20 | -否 | -否 | -租户标识 | -
| WORKORDER_TYPE | -VARCHAR | -10 | -否 | -否 | -工单类型 | -
| WORKORDER_STATUS | -VARCHAR | -10 | -否 | -否 | -工单状态 | -
| APPLY_DATE | -DATE | -- | -否 | -否 | -申请日期 | -
| PLAN_DATE | -DATE | -- | -是 | -否 | -计划执行日期 | -
| EXECUTE_DATE | -DATE | -- | -是 | -否 | -实际执行日期 | -
| APPLICANT_ID | -VARCHAR | -20 | -是 | -否 | -申请人编号 | -
| EXECUTOR_ID | -VARCHAR | -20 | -是 | -否 | -执行人编号 | -
| REASON | -VARCHAR | -200 | -是 | -否 | -原因 | -
| RESULT | -VARCHAR | -200 | -是 | -否 | -结果 | -
| CREATE_TIME | -DATETIME | -- | -否 | -否 | -创建时间 | -
| UPDATE_TIME | -DATETIME | -- | -是 | -否 | -更新时间 | -
为提高系统性能,针对主要查询场景设计了以下索引:
-系统统一采用以下JSON格式响应:
-{
- "code": 0, // 业务状态码,0表示成功,非0表示失败
- "data": {}, // 响应数据
- "msg": "success" // 响应消息
-}{
+ "code": 0, // 业务状态码,0表示成功,非0表示失败
+ "data": {}, // 响应数据
+ "msg": "success" // 响应消息
+}分页查询响应格式:
-{
- "code": 0,
- "data": {
- "list": [], // 数据列表
- "total": 100, // 总记录数
- "pageNum": 1, // 当前页码
- "pageSize": 10 // 每页记录数
- },
- "msg": "success"
-}{
+ "code": 0,
+ "data": {
+ "list": [], // 数据列表
+ "total": 100, // 总记录数
+ "pageNum": 1, // 当前页码
+ "pageSize": 10 // 每页记录数
+ },
+ "msg": "success"
+}系统使用Knife4j(基于Swagger)自动生成API文档,文档地址为:http://{系统地址}/doc.html。
主要特点: - 在线接口文档:支持在线查看接口定义 - 接口调试:支持在线调试接口 - 文档导出:支持导出OpenAPI规范文档 - 权限控制:支持对接口文档的访问控制
功能描述:通过银行系统自动从用户账户中扣除水费。
-接口规范: - 接口方式:文件交换或WebService - -数据格式:文本文件或XML - 交换频率:每日或实时
+接口详情: - +接口方式:文件交换(FTP/SFTP) - +数据格式:定长文本文件 - +交换频率:每日凌晨2:00 - +文件编码:GBK
+代扣文件格式:
+记录类型(1位) + 客户号(12位) + 户名(30位) + 银行账号(20位) + 扣款金额(12位,含2位小数) + 账期(6位) + 保留字段(19位)
+代扣文件示例:
+1C00000000001张三 62172511001234567890000009180202412
+1C00000000002李四 62172511001234567891000015460202412
+回盘文件格式:
+记录类型(1位) + 客户号(12位) + 银行账号(20位) + 扣款金额(12位) + 处理状态(1位) + 银行流水号(20位) + 处理时间(14位) + 失败原因(20位)
+Java实现示例:
+@Service
+public class BankDeductServiceImpl implements BankDeductService {
+
+ @Resource
+ private SftpTemplate sftpTemplate;
+ @Resource
+ private BillService billService;
+
+ @Scheduled(cron = "0 0 2 * * ?")
+ public void generateDeductFile() {
+ LocalDate deductDate = LocalDate.now();
+
+ // 获取待代扣账单
+ List<BillDO> deductBills = billService.getDeductBills(deductDate);
+
+ // 生成代扣文件
+ String fileName = "DEDUCT_" + deductDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".txt";
+ String fileContent = buildDeductFileContent(deductBills);
+
+ // 上传至银行SFTP
+ sftpTemplate.put(fileName, fileContent.getBytes(StandardCharsets.UTF_8), "/upload/");
+
+ // 记录代扣文件日志
+ DeductFileLogDO log = new DeductFileLogDO();
+ log.setFileName(fileName);
+ log.setFileStatus("UPLOADED");
+ log.setRecordCount(deductBills.size());
+ deductFileLogMapper.insert(log);
+ }
+
+ private String buildDeductFileContent(List<BillDO> bills) {
+ StringBuilder content = new StringBuilder();
+ for (BillDO bill : bills) {
+ content.append("1") // 记录类型
+ .append(StringUtils.rightPad(bill.getCustomerCode(), 12)) // 客户号
+ .append(StringUtils.rightPad(bill.getCustomerName(), 30)) // 户名
+ .append(StringUtils.rightPad(bill.getBankAccount(), 20)) // 银行账号
+ .append(String.format("%012d", bill.getTotalAmount().multiply(new BigDecimal(100)).intValue())) // 金额(分)
+ .append(bill.getBillMonth().replace("-", "")) // 账期
+ .append(StringUtils.repeat(" ", 19)) // 保留字段
+ .append("\n");
+ }
+ return content.toString();
+ }
+}功能描述:用户在银行柜台、网上银行或手机银行实时缴纳水费。
-接口规范: - 接口方式:WebService或HTTP接口 - -数据格式:XML或JSON - 交换频率:实时
-功能描述:用户通过支付宝缴纳水费。
-接口规范: - 接口方式:HTTP接口 - 数据格式:JSON - -交换频率:实时
-功能描述:用户通过微信支付缴纳水费。
-接口规范: - 接口方式:HTTP接口 - -数据格式:XML或JSON - 交换频率:实时
+接口详情: - 接口方式:HTTP POST -
+请求URL:https://bank.api.com/payment/water-fee
+- 数据格式:JSON - 认证方式:API Key +
+签名
请求参数:
+{
+ "merchantId": "WATER001",
+ "customerCode": "C001",
+ "billCodes": ["B202412190001"],
+ "totalAmount": 91.80,
+ "bankAccount": "6217251100123456789",
+ "customerName": "张三",
+ "timestamp": "20241219103000",
+ "signature": "ABC123DEF456..."
+}响应参数:
+{
+ "resultCode": "0000",
+ "resultMsg": "交易成功",
+ "data": {
+ "transactionId": "TXN20241219001",
+ "paymentTime": "20241219103001",
+ "bankSerial": "BNK20241219001234"
+ }
+}功能描述:用户通过支付宝缴纳水费,支持扫码支付和H5支付。
+接口详情: - 接口方式:HTTP POST - +支付方式:统一收单交易预创建(alipay.trade.precreate) +- 数据格式:JSON - +认证方式:RSA2签名
+预创建支付请求参数:
+{
+ "app_id": "2021001234567890",
+ "method": "alipay.trade.precreate",
+ "charset": "UTF-8",
+ "sign_type": "RSA2",
+ "timestamp": "2024-12-19 10:30:00",
+ "version": "1.0",
+ "notify_url": "https://water.example.com/api/payment/alipay/notify",
+ "biz_content": {
+ "out_trade_no": "P202412190002",
+ "total_amount": "91.80",
+ "subject": "水费缴费",
+ "body": "2024年12月水费-客户编号:C001",
+ "store_id": "WATER_STORE_001",
+ "timeout_express": "30m"
+ }
+}支付宝响应参数:
+{
+ "alipay_trade_precreate_response": {
+ "code": "10000",
+ "msg": "Success",
+ "out_trade_no": "P202412190002",
+ "qr_code": "https://qr.alipay.com/bax08945xtdnfwgqmwi200b4"
+ },
+ "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
+}Java实现示例:
+@Service
+public class AlipayServiceImpl implements AlipayService {
+
+ @Resource
+ private AlipayClient alipayClient;
+
+ @Override
+ public AlipayPaymentRespVO createPayment(AlipayPaymentReqVO request) {
+ AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();
+ alipayRequest.setNotifyUrl("https://water.example.com/api/payment/alipay/notify");
+
+ AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
+ model.setOutTradeNo(request.getPaymentCode());
+ model.setTotalAmount(request.getTotalAmount().toString());
+ model.setSubject("水费缴费");
+ model.setBody("账单号:" + String.join(",", request.getBillCodes()));
+ model.setTimeoutExpress("30m");
+
+ alipayRequest.setBizModel(model);
+
+ try {
+ AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);
+ if (response.isSuccess()) {
+ return AlipayPaymentRespVO.builder()
+ .paymentCode(request.getPaymentCode())
+ .qrCode(response.getQrCode())
+ .outTradeNo(response.getOutTradeNo())
+ .build();
+ } else {
+ throw new BizException(ALIPAY_PAY_FAILED, response.getSubMsg());
+ }
+ } catch (AlipayApiException e) {
+ throw new BizException(ALIPAY_PAY_ERROR, e.getErrMsg());
+ }
+ }
+}功能描述:用户通过微信支付缴纳水费,支持扫码支付和小程序支付。
+接口详情: - 接口方式:HTTP POST -
+支付方式:Native支付(扫码)/ JSAPI支付(小程序) -
+请求URL:https://api.mch.weixin.qq.com/v3/pay/transactions/native
+- 数据格式:JSON -
+认证方式:微信支付V3签名
统一下单请求参数:
+{
+ "appid": "wx8888888888888888",
+ "mchid": "1900000109",
+ "description": "水费缴费-2024年12月",
+ "out_trade_no": "P202412190003",
+ "notify_url": "https://water.example.com/api/payment/wechat/notify",
+ "amount": {
+ "total": 9180,
+ "currency": "CNY"
+ },
+ "attach": "客户编号:C001,账单号:B202412190001",
+ "goods_tag": "WATER_FEE",
+ "time_expire": "2024-12-19T11:00:00+08:00"
+}微信支付响应参数:
+{
+ "code_url": "weixin://wxpay/bizpayurl?pr=HuaLcAKwa"
+}支付结果通知参数:
+{
+ "id": "EV-2018022511223320873",
+ "create_time": "2024-12-19T10:30:00+08:00",
+ "resource_type": "encrypt-resource",
+ "event_type": "TRANSACTION.SUCCESS",
+ "summary": "支付成功",
+ "resource": {
+ "original_type": "transaction",
+ "algorithm": "AEAD_AES_256_GCM",
+ "ciphertext": "...",
+ "associated_data": "transaction",
+ "nonce": "..."
+ }
+}功能描述:向用户发送各类业务通知短信。
接口规范: - 接口方式:HTTP接口 - 数据格式:JSON - @@ -2775,33 +4580,427 @@ Plus的分页插件,实现高性能分页
接口规范: - 接口方式:HTTP接口或WebService - 数据格式:JSON或XML - 交换频率:定时或实时
功能描述:查询用户基本信息。
-接口规范: - 请求方式:GET - -请求路径:/api/users/{userId} - 返回格式:JSON
-功能描述:更新用户基本信息。
-接口规范: - 请求方式:PUT - -请求路径:/api/users/{userId} - 请求/返回格式:JSON
-功能描述:根据客户ID查询客户详细信息。
+接口详情: - 请求方式:GET -
+请求路径:/admin-api/water/customer/{id} -
+请求头:Authorization: Bearer {token}
请求参数: | 参数名 | 类型 | 必填 | 说明 | 示例 | +|——-|——|——|——|——| | id | Long | 是 | 客户ID | 1 |
+响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "id": 1,
+ "customerCode": "C001",
+ "customerName": "张三",
+ "customerType": "RESIDENT",
+ "phone": "13800138000",
+ "address": "福建省福州市台江区XX街道XX号",
+ "status": 1,
+ "createTime": "2024-12-19 10:00:00"
+ }
+}RuoYi-Vue-Pro代码示例:
+@RestController
+@RequestMapping("/admin-api/water/customer")
+@Tag(name = "管理后台 - 客户管理")
+@Validated
+public class CustomerController {
+
+ @Resource
+ private CustomerService customerService;
+
+ @GetMapping("/{id}")
+ @Operation(summary = "获得客户")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('water:customer:query')")
+ public CommonResult<CustomerRespVO> getCustomer(@PathVariable("id") Long id) {
+ CustomerDO customer = customerService.getCustomer(id);
+ return success(BeanUtils.toBean(customer, CustomerRespVO.class));
+ }
+}功能描述:分页查询客户列表信息。
+接口详情: - 请求方式:GET -
+请求路径:/admin-api/water/customer/page
请求参数: | 参数名 | 类型 | 必填 | 说明 | 示例 | +|——-|——|——|——|——| | pageNo | Integer | 否 | 页码,默认1 | 1 | | pageSize +| Integer | 否 | 每页条数,默认10 | 10 | | customerName | String | 否 | +客户名称 | 张三 | | customerCode | String | 否 | 客户编号 | C001 | | +customerType | String | 否 | 客户类型 | RESIDENT | | phone | String | 否 +| 联系电话 | 138 |
+响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "list": [
+ {
+ "id": 1,
+ "customerCode": "C001",
+ "customerName": "张三",
+ "customerType": "RESIDENT",
+ "phone": "13800138000",
+ "address": "福建省福州市台江区XX街道XX号",
+ "status": 1,
+ "createTime": "2024-12-19 10:00:00"
+ }
+ ],
+ "total": 1
+ }
+}功能描述:创建新客户记录。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/customer/create
请求参数:
+{
+ "customerCode": "C002",
+ "customerName": "李四",
+ "customerType": "RESIDENT",
+ "idType": "ID_CARD",
+ "idNumber": "350103199001011234",
+ "phone": "13900139000",
+ "address": "福建省福州市鼓楼区XX街道XX号"
+}响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": 2
+}Service层代码示例:
+@Service
+@Validated
+public class CustomerServiceImpl implements CustomerService {
+
+ @Resource
+ private CustomerMapper customerMapper;
+
+ @Override
+ public Long createCustomer(CustomerSaveReqVO createReqVO) {
+ // 校验客户编号唯一性
+ validateCustomerCodeUnique(createReqVO.getCustomerCode());
+
+ // 创建客户
+ CustomerDO customer = BeanUtils.toBean(createReqVO, CustomerDO.class);
+ customerMapper.insert(customer);
+ return customer.getId();
+ }
+
+ private void validateCustomerCodeUnique(String customerCode) {
+ CustomerDO existCustomer = customerMapper.selectByCustomerCode(customerCode);
+ if (existCustomer != null) {
+ throw exception(CUSTOMER_CODE_DUPLICATE);
+ }
+ }
+}功能描述:查询水表基本信息。
-接口规范: - 请求方式:GET - -请求路径:/api/meters/{meterId} - 返回格式:JSON
-功能描述:上传水表读数。
-接口规范: - 请求方式:POST - -请求路径:/api/meters/{meterId}/readings - 请求/返回格式:JSON
-功能描述:根据水表ID查询水表详细信息。
+接口详情: - 请求方式:GET -
+请求路径:/admin-api/water/meter/{id} -
+请求头:Authorization: Bearer {token}
请求参数: | 参数名 | 类型 | 必填 | 说明 | 示例 | +|——-|——|——|——|——| | id | Long | 是 | 水表ID | 1 |
+响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "id": 1,
+ "meterCode": "M001",
+ "meterNo": "20241219001",
+ "meterType": "SMART",
+ "meterModel": "LXSY-15E",
+ "meterCaliber": "15mm",
+ "installDate": "2024-01-15",
+ "installPosition": "1层水表井",
+ "initialReading": 0.00,
+ "currentReading": 156.32,
+ "readingCycle": "MONTHLY",
+ "meterStatus": 1,
+ "customerId": 1,
+ "customerName": "张三"
+ }
+}Controller代码示例:
+@RestController
+@RequestMapping("/admin-api/water/meter")
+@Tag(name = "管理后台 - 水表管理")
+@Validated
+public class MeterController {
+
+ @Resource
+ private MeterService meterService;
+
+ @GetMapping("/{id}")
+ @Operation(summary = "获得水表")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('water:meter:query')")
+ public CommonResult<MeterRespVO> getMeter(@PathVariable("id") Long id) {
+ MeterDO meter = meterService.getMeter(id);
+ return success(BeanUtils.toBean(meter, MeterRespVO.class));
+ }
+}功能描述:创建新的抄表记录。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/reading/create
请求参数:
+{
+ "meterId": 1,
+ "readingDate": "2024-12-19",
+ "readingValue": 156.32,
+ "readingType": "MANUAL",
+ "readerId": "R001",
+ "photoUrl": "https://example.com/photos/reading001.jpg",
+ "remark": "正常抄表"
+}响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": 1
+}Service层实现示例:
+@Service
+@Validated
+public class MeterReadingServiceImpl implements MeterReadingService {
+
+ @Resource
+ private MeterReadingMapper readingMapper;
+ @Resource
+ private MeterService meterService;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createReading(MeterReadingSaveReqVO createReqVO) {
+ // 校验水表存在性
+ MeterDO meter = meterService.validateMeterExists(createReqVO.getMeterId());
+
+ // 校验读数合理性
+ validateReadingValue(createReqVO.getMeterId(), createReqVO.getReadingValue());
+
+ // 创建抄表记录
+ MeterReadingDO reading = BeanUtils.toBean(createReqVO, MeterReadingDO.class);
+ reading.setReadingCode(generateReadingCode());
+ reading.setCustomerId(meter.getCustomerId());
+
+ // 计算用水量
+ BigDecimal waterUsage = calculateWaterUsage(meter.getCurrentReading(),
+ createReqVO.getReadingValue());
+ reading.setWaterUsage(waterUsage);
+
+ readingMapper.insert(reading);
+
+ // 更新水表当前读数
+ meterService.updateCurrentReading(createReqVO.getMeterId(),
+ createReqVO.getReadingValue());
+
+ return reading.getId();
+ }
+}功能描述:批量导入抄表数据,支持Excel文件上传。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/reading/import
+- Content-Type:multipart/form-data
请求参数: | 参数名 | 类型 | 必填 | 说明 | 示例 | +|——-|——|——|——|——| | file | MultipartFile | 是 | Excel文件 | +reading_data.xlsx | | updateSupport | Boolean | 否 | 是否更新已有数据 | +false |
+响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "successCount": 95,
+ "failureCount": 5,
+ "failureList": [
+ {
+ "lineNumber": 3,
+ "meterCode": "M003",
+ "errorMsg": "水表不存在"
+ }
+ ]
+ }
+}功能描述:查询用户账单信息。
-接口规范: - 请求方式:GET - -请求路径:/api/users/{userId}/bills - 返回格式:JSON
-功能描述:处理用户缴费。
-接口规范: - 请求方式:POST - -请求路径:/api/bills/{billId}/payments - 请求/返回格式:JSON
+功能描述:根据客户ID和查询条件查询账单信息。
+接口详情: - 请求方式:GET -
+请求路径:/admin-api/water/bill/page
请求参数: | 参数名 | 类型 | 必填 | 说明 | 示例 | +|——-|——|——|——|——| | pageNo | Integer | 否 | 页码,默认1 | 1 | | pageSize +| Integer | 否 | 每页条数,默认10 | 10 | | customerId | Long | 否 | +客户ID | 1 | | billMonth | String | 否 | 账期 | 2024-12 | | billStatus | +Integer | 否 | 账单状态 | 0 |
+响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "list": [
+ {
+ "id": 1,
+ "billCode": "B202412190001",
+ "billMonth": "2024-12",
+ "billDate": "2024-12-19",
+ "waterUsage": 25.50,
+ "waterFee": 76.50,
+ "sewageFee": 15.30,
+ "totalAmount": 91.80,
+ "paidAmount": 0.00,
+ "balanceAmount": 91.80,
+ "dueDate": "2025-01-19",
+ "billStatus": 0,
+ "customerName": "张三",
+ "meterCode": "M001"
+ }
+ ],
+ "total": 1
+ }
+}功能描述:根据抄表记录生成水费账单。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/bill/generate
请求参数:
+{
+ "billMonth": "2024-12",
+ "customerIds": [1, 2, 3],
+ "readingIds": [1, 2, 3],
+ "dueDate": "2025-01-19"
+}响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "generateCount": 3,
+ "successList": [
+ {
+ "customerId": 1,
+ "billId": 1,
+ "totalAmount": 91.80
+ }
+ ],
+ "failureList": []
+ }
+}Service层代码示例:
+@Service
+@Validated
+public class BillServiceImpl implements BillService {
+
+ @Resource
+ private BillMapper billMapper;
+ @Resource
+ private MeterReadingService readingService;
+ @Resource
+ private WaterPriceService priceService;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public BillGenerateRespVO generateBills(BillGenerateReqVO generateReqVO) {
+ BillGenerateRespVO result = new BillGenerateRespVO();
+ List<BillGenerateDetailVO> successList = new ArrayList<>();
+ List<BillGenerateDetailVO> failureList = new ArrayList<>();
+
+ for (Long readingId : generateReqVO.getReadingIds()) {
+ try {
+ // 获取抄表记录
+ MeterReadingDO reading = readingService.getReading(readingId);
+
+ // 计算水费
+ WaterFeeCalculateDTO feeResult = priceService.calculateWaterFee(
+ reading.getCustomerId(), reading.getWaterUsage());
+
+ // 创建账单
+ BillDO bill = new BillDO();
+ bill.setBillCode(generateBillCode());
+ bill.setBillMonth(generateReqVO.getBillMonth());
+ bill.setCustomerId(reading.getCustomerId());
+ bill.setMeterId(reading.getMeterId());
+ bill.setReadingId(readingId);
+ bill.setWaterUsage(reading.getWaterUsage());
+ bill.setWaterFee(feeResult.getWaterFee());
+ bill.setSewageFee(feeResult.getSewageFee());
+ bill.setTotalAmount(feeResult.getTotalAmount());
+ bill.setDueDate(generateReqVO.getDueDate());
+
+ billMapper.insert(bill);
+
+ successList.add(buildSuccessDetail(reading.getCustomerId(),
+ bill.getId(), feeResult.getTotalAmount()));
+
+ } catch (Exception e) {
+ failureList.add(buildFailureDetail(readingId, e.getMessage()));
+ }
+ }
+
+ result.setGenerateCount(successList.size());
+ result.setSuccessList(successList);
+ result.setFailureList(failureList);
+ return result;
+ }
+}功能描述:处理客户缴费操作。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/payment/create
请求参数:
+{
+ "customerId": 1,
+ "billIds": [1, 2],
+ "paymentType": "NORMAL",
+ "paymentChannel": "CASH",
+ "paymentAmount": 183.60,
+ "actualAmount": 200.00,
+ "operatorId": "OP001",
+ "outletCode": "OUT001",
+ "remark": "现金缴费"
+}响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "paymentId": 1,
+ "paymentCode": "P202412190001",
+ "changeAmount": 16.40,
+ "invoiceNo": "INV20241219001"
+ }
+}功能描述:处理在线支付(微信、支付宝等)。
+接口详情: - 请求方式:POST -
+请求路径:/admin-api/water/payment/online-pay
请求参数:
+{
+ "customerId": 1,
+ "billIds": [1],
+ "paymentChannel": "WECHAT",
+ "paymentAmount": 91.80,
+ "returnUrl": "https://water.example.com/payment/callback",
+ "notifyUrl": "https://water.example.com/api/payment/notify"
+}响应参数:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "paymentCode": "P202412190002",
+ "prepayId": "wx20241219001234567890",
+ "payUrl": "weixin://wxpay/bizpayurl?pr=abc123",
+ "qrCode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
+ }
+}功能描述:创建业务工单。
@@ -2828,18 +5027,386 @@ API接口,结构简单清晰,适合Web应用接口安全采用以下机制:
-接口安全采用多层防护机制:
+JWT令牌认证:
+@RestController
+public class AuthController {
+
+ @Resource
+ private AuthService authService;
+
+ @PostMapping("/admin-api/system/auth/login")
+ public CommonResult<AuthLoginRespVO> login(@Valid @RequestBody AuthLoginReqVO reqVO) {
+ // 验证用户名密码
+ AdminUserDO user = authService.authenticate(reqVO.getUsername(), reqVO.getPassword());
+
+ // 生成JWT Token
+ String token = authService.createToken(user.getId(), user.getTenantId());
+
+ return success(AuthLoginRespVO.builder()
+ .userId(user.getId())
+ .accessToken(token)
+ .refreshToken(authService.createRefreshToken(user.getId()))
+ .expiresTime(LocalDateTime.now().plusHours(2))
+ .build());
+ }
+}API Key认证(外部系统):
+@Component
+public class ApiKeyAuthenticationFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+ String apiKey = request.getHeader("X-API-KEY");
+ String timestamp = request.getHeader("X-TIMESTAMP");
+ String signature = request.getHeader("X-SIGNATURE");
+
+ // 验证API Key
+ if (!apiKeyService.validateApiKey(apiKey)) {
+ writeErrorResponse(response, "Invalid API Key");
+ return;
+ }
+
+ // 验证时间戳(防重放攻击)
+ if (!validateTimestamp(timestamp)) {
+ writeErrorResponse(response, "Request expired");
+ return;
+ }
+
+ // 验证签名
+ if (!validateSignature(request, signature)) {
+ writeErrorResponse(response, "Invalid signature");
+ return;
+ }
+
+ filterChain.doFilter(request, response);
+ }
+}敏感数据加密:
+@Component
+public class DataEncryptionService {
+
+ private final AESUtil aesUtil;
+
+ public String encryptPersonalInfo(String plainText) {
+ if (StrUtil.isBlank(plainText)) {
+ return plainText;
+ }
+ return aesUtil.encrypt(plainText);
+ }
+
+ public String decryptPersonalInfo(String cipherText) {
+ if (StrUtil.isBlank(cipherText)) {
+ return cipherText;
+ }
+ return aesUtil.decrypt(cipherText);
+ }
+}IP白名单控制:
+@Component
+public class IpWhitelistFilter extends OncePerRequestFilter {
+
+ @Value("${water.security.ip-whitelist}")
+ private List<String> ipWhitelist;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+ String clientIp = getClientIpAddress(request);
+
+ if (!isIpAllowed(clientIp)) {
+ response.setStatus(HttpStatus.FORBIDDEN.value());
+ response.getWriter().write("{\"code\":403,\"msg\":\"IP access denied\"}");
+ return;
+ }
+
+ filterChain.doFilter(request, response);
+ }
+}基于Redis的令牌桶限流:
+@Component
+public class RateLimitService {
+
+ @Resource
+ private StringRedisTemplate redisTemplate;
+
+ public boolean allowRequest(String key, int maxRequests, Duration window) {
+ String redisKey = "rate_limit:" + key;
+ String script = """
+ local key = KEYS[1]
+ local window = tonumber(ARGV[1])
+ local limit = tonumber(ARGV[2])
+ local current = redis.call('get', key)
+ if current == false then
+ redis.call('setex', key, window, 1)
+ return 1
+ end
+ if tonumber(current) < limit then
+ return redis.call('incr', key)
+ else
+ return 0
+ end
+ """;
+
+ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
+ Long result = redisTemplate.execute(redisScript,
+ Collections.singletonList(redisKey),
+ String.valueOf(window.getSeconds()),
+ String.valueOf(maxRequests));
+
+ return result != null && result > 0;
+ }
+}@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ServiceException.class)
+ public CommonResult<?> serviceExceptionHandler(ServiceException ex) {
+ log.info("[serviceExceptionHandler]", ex);
+ return CommonResult.error(ex.getCode(), ex.getMessage());
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public CommonResult<?> constraintViolationExceptionHandler(ConstraintViolationException ex) {
+ log.info("[constraintViolationExceptionHandler]", ex);
+ return CommonResult.error(BAD_REQUEST.getCode(), "请求参数不正确:" + ex.getMessage());
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public CommonResult<?> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
+ log.info("[methodArgumentNotValidExceptionHandler]", ex);
+ FieldError fieldError = ex.getBindingResult().getFieldError();
+ assert fieldError != null;
+ return CommonResult.error(BAD_REQUEST.getCode(), "请求参数不正确:" + fieldError.getDefaultMessage());
+ }
+}public interface ErrorCodeConstants {
+
+ // ========== 通用错误码 1-000-000-000 ==========
+ ErrorCode SUCCESS = new ErrorCode(0, "成功");
+ ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
+ ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
+ ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
+ ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
+ ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
+ ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
+
+ // ========== 客户管理错误码 1-001-000-000 ==========
+ ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_001_000_001, "客户不存在");
+ ErrorCode CUSTOMER_CODE_DUPLICATE = new ErrorCode(1_001_000_002, "客户编号已存在");
+ ErrorCode CUSTOMER_STATUS_INVALID = new ErrorCode(1_001_000_003, "客户状态不正确");
+
+ // ========== 水表管理错误码 1-002-000-000 ==========
+ ErrorCode METER_NOT_EXISTS = new ErrorCode(1_002_000_001, "水表不存在");
+ ErrorCode METER_CODE_DUPLICATE = new ErrorCode(1_002_000_002, "水表编号已存在");
+ ErrorCode METER_READING_INVALID = new ErrorCode(1_002_000_003, "水表读数不正确");
+
+ // ========== 账单管理错误码 1-003-000-000 ==========
+ ErrorCode BILL_NOT_EXISTS = new ErrorCode(1_003_000_001, "账单不存在");
+ ErrorCode BILL_ALREADY_PAID = new ErrorCode(1_003_000_002, "账单已缴费");
+ ErrorCode BILL_AMOUNT_INVALID = new ErrorCode(1_003_000_003, "账单金额不正确");
+
+ // ========== 缴费管理错误码 1-004-000-000 ==========
+ ErrorCode PAYMENT_FAILED = new ErrorCode(1_004_000_001, "缴费失败");
+ ErrorCode PAYMENT_AMOUNT_INSUFFICIENT = new ErrorCode(1_004_000_002, "缴费金额不足");
+ ErrorCode PAYMENT_CHANNEL_UNAVAILABLE = new ErrorCode(1_004_000_003, "缴费渠道不可用");
+}成功响应示例:
+{
+ "code": 0,
+ "msg": "操作成功",
+ "data": {
+ "id": 1,
+ "customerName": "张三"
+ }
+}失败响应示例:
+{
+ "code": 1001000001,
+ "msg": "客户不存在",
+ "data": null
+}// api/water/customer.ts
+import { request } from '@/utils/request'
+
+export interface CustomerVO {
+ id: number
+ customerCode: string
+ customerName: string
+ customerType: string
+ phone: string
+ address: string
+ status: number
+ createTime: string
+}
+
+export interface CustomerPageReqVO extends PageParam {
+ customerName?: string
+ customerCode?: string
+ customerType?: string
+ phone?: string
+}
+
+export const CustomerApi = {
+ // 获取客户分页
+ getCustomerPage: (params: CustomerPageReqVO) => {
+ return request.get<PageResult<CustomerVO>>({ url: '/water/customer/page', params })
+ },
+
+ // 获取客户详情
+ getCustomer: (id: number) => {
+ return request.get<CustomerVO>({ url: `/water/customer/${id}` })
+ },
+
+ // 创建客户
+ createCustomer: (data: CustomerSaveReqVO) => {
+ return request.post<number>({ url: '/water/customer/create', data })
+ },
+
+ // 更新客户
+ updateCustomer: (data: CustomerSaveReqVO) => {
+ return request.put<void>({ url: '/water/customer/update', data })
+ },
+
+ // 删除客户
+ deleteCustomer: (id: number) => {
+ return request.delete<void>({ url: `/water/customer/delete?id=${id}` })
+ }
+}<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">
+ <!-- 查询表单 -->
+ <el-form :model="queryParams" ref="queryFormRef" inline>
+ <el-form-item label="客户名称" prop="customerName">
+ <el-input v-model="queryParams.customerName" placeholder="请输入客户名称" />
+ </el-form-item>
+ <el-form-item label="客户编号" prop="customerCode">
+ <el-input v-model="queryParams.customerCode" placeholder="请输入客户编号" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">搜索</el-button>
+ <el-button @click="handleReset">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <!-- 数据表格 -->
+ <el-table v-loading="loading" :data="customerList">
+ <el-table-column label="客户编号" prop="customerCode" />
+ <el-table-column label="客户名称" prop="customerName" />
+ <el-table-column label="联系电话" prop="phone" />
+ <el-table-column label="创建时间" prop="createTime" :formatter="formatDate" />
+ </el-table>
+
+ <!-- 分页组件 -->
+ <Pagination
+ :total="total"
+ v-model:page="queryParams.pageNo"
+ v-model:limit="queryParams.pageSize"
+ @pagination="getCustomerList"
+ />
+ </div>
+</template>
+| 项目信息 | +详情 | +
|---|---|
| 项目名称 | +福建水务营收系统 | +
| 文档类型 | +概要设计文档 | +
| 技术框架 | +RuoYi-Vue-Pro + yudao-ui-admin-vue3 | +
| 文档版本 | +v1.0 | +
| 编写日期 | +2024-12-19 | +
| 文档状态 | +✅ 已完成 | +
# docker-compose.yml
+version: '3.8'
+
+services:
+ # OpenGauss 数据库
+ water-opengauss:
+ image: enmotech/opengauss:5.0.0
+ container_name: water-opengauss
+ restart: always
+ environment:
+ GS_PASSWORD: "Water@2024"
+ GS_DB: "ruoyi_water"
+ GS_USERNAME: "water_user"
+ TZ: "Asia/Shanghai"
+ volumes:
+ - ./data/opengauss:/var/lib/opengauss
+ - ./sql:/docker-entrypoint-initdb.d
+ - ./config/opengauss:/opt/opengauss/config
+ ports:
+ - "5432:5432"
+ networks:
+ - water-network
+ healthcheck:
+ test: ["CMD-SHELL", "gs_ctl status -D /var/lib/opengauss/data"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+ # Redis 缓存
+ water-redis:
+ image: redis:7.0-alpine
+ container_name: water-redis
+ restart: always
+ volumes:
+ - ./data/redis:/data
+ - ./config/redis/redis.conf:/etc/redis/redis.conf
+ ports:
+ - "6379:6379"
+ command: redis-server /etc/redis/redis.conf
+ networks:
+ - water-network
+
+ # 后端应用
+ water-server:
+ build:
+ context: ./water-server
+ dockerfile: Dockerfile
+ container_name: water-server
+ restart: always
+ depends_on:
+ - water-opengauss
+ - water-redis
+ environment:
+ - SPRING_PROFILES_ACTIVE=prod
+ - SPRING_DATASOURCE_URL=jdbc:opengauss://water-opengauss:5432/ruoyi_water?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+ - SPRING_DATASOURCE_USERNAME=water_user
+ - SPRING_DATASOURCE_PASSWORD=Water@2024
+ - SPRING_REDIS_HOST=water-redis
+ - SPRING_REDIS_PORT=6379
+ - SERVER_PORT=8080
+ volumes:
+ - ./logs:/app/logs
+ - ./upload:/app/upload
+ ports:
+ - "8080:8080"
+ networks:
+ - water-network
+
+ # 前端应用
+ water-ui:
+ build:
+ context: ./water-ui
+ dockerfile: Dockerfile
+ container_name: water-ui
+ restart: always
+ depends_on:
+ - water-server
+ volumes:
+ - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
+ - ./config/nginx/conf.d:/etc/nginx/conf.d
+ ports:
+ - "80:80"
+ - "443:443"
+ networks:
+ - water-network
+
+ # Nginx 反向代理
+ water-nginx:
+ image: nginx:1.24-alpine
+ container_name: water-nginx
+ restart: always
+ depends_on:
+ - water-server
+ - water-ui
+ volumes:
+ - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
+ - ./config/nginx/conf.d:/etc/nginx/conf.d
+ - ./ssl:/etc/nginx/ssl
+ - ./logs/nginx:/var/log/nginx
+ ports:
+ - "80:80"
+ - "443:443"
+ networks:
+ - water-network
+
+ # MinIO 文件存储
+ water-minio:
+ image: minio/minio:latest
+ container_name: water-minio
+ restart: always
+ environment:
+ MINIO_ACCESS_KEY: "admin"
+ MINIO_SECRET_KEY: "admin123456"
+ volumes:
+ - ./data/minio:/data
+ ports:
+ - "9000:9000"
+ - "9001:9001"
+ command: server /data --console-address ":9001"
+ networks:
+ - water-network
+
+networks:
+ water-network:
+ driver: bridge
+
+volumes:
+ opengauss-data:
+ redis-data:
+ minio-data:# water-server/Dockerfile
+FROM openjdk:17-jdk-slim
+
+LABEL maintainer="fujian-water-dev-team"
+
+# 设置工作目录
+WORKDIR /app
+
+# 设置时区
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+# 添加应用jar包
+COPY target/water-server.jar app.jar
+
+# 创建日志目录
+RUN mkdir -p /app/logs
+
+# 暴露端口
+EXPOSE 8080
+
+# 启动应用
+ENTRYPOINT ["java", "-jar", "-Xmx1024m", "-Xms512m", "-Dspring.profiles.active=prod", "/app/app.jar"]# water-ui/Dockerfile
+# 构建阶段
+FROM node:18-alpine AS builder
+
+WORKDIR /app
+
+# 复制包管理文件
+COPY package*.json ./
+
+# 安装依赖
+RUN npm ci --only=production
+
+# 复制源代码
+COPY . .
+
+# 构建应用
+RUN npm run build:prod
+
+# 生产阶段
+FROM nginx:1.24-alpine
+
+# 复制构建产物
+COPY --from=builder /app/dist /usr/share/nginx/html
+
+# 复制nginx配置
+COPY nginx.conf /etc/nginx/nginx.conf
+
+# 暴露端口
+EXPOSE 80
+
+# 启动nginx
+CMD ["nginx", "-g", "daemon off;"]Docker Compose生产环境配置文件:
+# docker-compose.prod.yml
+version: '3.8'
+
+services:
+ water-opengauss:
+ image: enmotech/opengauss:5.0.0
+ container_name: water-opengauss-prod
+ restart: unless-stopped
+ environment:
+ GS_PASSWORD: "${DB_PASSWORD:-Water@2024!}"
+ GS_DB: "ruoyi_water"
+ GS_USERNAME: "water_user"
+ TZ: "Asia/Shanghai"
+ volumes:
+ - opengauss-prod-data:/var/lib/opengauss
+ - ./config/opengauss/prod:/opt/opengauss/config
+ - ./backups:/backups
+ ports:
+ - "5432:5432"
+ networks:
+ - water-prod-network
+ deploy:
+ resources:
+ limits:
+ memory: 2G
+ cpus: '2.0'
+ healthcheck:
+ test: ["CMD-SHELL", "gs_ctl status -D /var/lib/opengauss/data"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+ start_period: 60s
+
+ water-redis:
+ image: redis:7.0-alpine
+ container_name: water-redis-prod
+ restart: unless-stopped
+ command: redis-server /etc/redis/redis.conf --requirepass ${REDIS_PASSWORD:-water_redis_2024}
+ volumes:
+ - redis-prod-data:/data
+ - ./config/redis/prod.conf:/etc/redis/redis.conf
+ ports:
+ - "6379:6379"
+ networks:
+ - water-prod-network
+ deploy:
+ resources:
+ limits:
+ memory: 512M
+ cpus: '1.0'
+
+ water-server:
+ image: water-server:${VERSION:-latest}
+ container_name: water-server-prod
+ restart: unless-stopped
+ depends_on:
+ water-opengauss:
+ condition: service_healthy
+ water-redis:
+ condition: service_started
+ environment:
+ - SPRING_PROFILES_ACTIVE=prod
+ - SPRING_DATASOURCE_URL=jdbc:opengauss://water-opengauss:5432/ruoyi_water
+ - SPRING_DATASOURCE_USERNAME=water_user
+ - SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD:-Water@2024!}
+ - SPRING_REDIS_HOST=water-redis
+ - SPRING_REDIS_PASSWORD=${REDIS_PASSWORD:-water_redis_2024}
+ - SERVER_PORT=8080
+ - JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC
+ volumes:
+ - ./logs/prod:/app/logs
+ - ./upload/prod:/app/upload
+ - ./config/app:/app/config
+ networks:
+ - water-prod-network
+ deploy:
+ resources:
+ limits:
+ memory: 3G
+ cpus: '2.0'
+ replicas: 2
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+ water-nginx:
+ image: nginx:1.24-alpine
+ container_name: water-nginx-prod
+ restart: unless-stopped
+ depends_on:
+ - water-server
+ volumes:
+ - ./config/nginx/prod.conf:/etc/nginx/nginx.conf
+ - ./config/nginx/conf.d:/etc/nginx/conf.d
+ - ./ssl:/etc/nginx/ssl
+ - ./logs/nginx:/var/log/nginx
+ - ./static:/usr/share/nginx/html
+ ports:
+ - "80:80"
+ - "443:443"
+ networks:
+ - water-prod-network
+ deploy:
+ resources:
+ limits:
+ memory: 256M
+ cpus: '0.5'
+
+networks:
+ water-prod-network:
+ driver: bridge
+ ipam:
+ config:
+ - subnet: 172.20.0.0/16
+
+volumes:
+ opengauss-prod-data:
+ driver: local
+ redis-prod-data:
+ driver: local# .env.prod
+# 数据库配置
+DB_PASSWORD=Water@2024!Production
+DB_HOST=water-opengauss
+DB_PORT=5432
+DB_NAME=ruoyi_water
+
+# Redis配置
+REDIS_PASSWORD=WaterRedis@2024!Production
+REDIS_HOST=water-redis
+REDIS_PORT=6379
+
+# 应用配置
+APP_VERSION=1.0.0
+JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError
+
+# 网络配置
+NGINX_PORT=80
+NGINX_SSL_PORT=443
+
+# 日志级别
+LOG_LEVEL=INFO
+LOG_ROOT_LEVEL=WARN# docker-compose.monitoring.yml
+version: '3.8'
+
+services:
+ prometheus:
+ image: prom/prometheus:latest
+ container_name: water-prometheus
+ restart: unless-stopped
+ volumes:
+ - ./config/prometheus:/etc/prometheus
+ - prometheus-data:/prometheus
+ ports:
+ - "9090:9090"
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--storage.tsdb.path=/prometheus'
+ - '--web.console.libraries=/etc/prometheus/console_libraries'
+ - '--web.console.templates=/etc/prometheus/consoles'
+ networks:
+ - water-network
+
+ grafana:
+ image: grafana/grafana:latest
+ container_name: water-grafana
+ restart: unless-stopped
+ environment:
+ - GF_SECURITY_ADMIN_PASSWORD=admin123
+ volumes:
+ - grafana-data:/var/lib/grafana
+ - ./config/grafana:/etc/grafana/provisioning
+ ports:
+ - "3000:3000"
+ networks:
+ - water-network
+
+volumes:
+ prometheus-data:
+ grafana-data:#!/bin/bash
+# deploy-docker.sh
+
+set -e
+
+echo "=== 福建水务营收系统 Docker 部署脚本 ==="
+
+# 检查Docker环境
+if ! command -v docker &> /dev/null; then
+ echo "错误: Docker未安装,请先安装Docker"
+ exit 1
+fi
+
+if ! command -v docker-compose &> /dev/null; then
+ echo "错误: Docker Compose未安装,请先安装Docker Compose"
+ exit 1
+fi
+
+# 创建必要目录
+echo "创建数据目录..."
+mkdir -p data/{opengauss,redis,minio}
+mkdir -p logs/{app,nginx}
+mkdir -p config/{opengauss,redis,nginx/conf.d}
+mkdir -p upload
+mkdir -p ssl
+mkdir -p backups
+
+# 设置OpenGauss配置
+echo "配置OpenGauss..."
+cat > config/opengauss/postgresql.conf << EOF
+# 数据库连接配置
+max_connections = 1000
+port = 5432
+listen_addresses = '*'
+
+# 内存配置
+shared_buffers = 512MB
+work_mem = 4MB
+maintenance_work_mem = 128MB
+
+# WAL配置
+wal_level = replica
+max_wal_size = 2GB
+min_wal_size = 128MB
+
+# 日志配置
+log_destination = 'stderr'
+logging_collector = on
+log_directory = 'pg_log'
+log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
+log_min_duration_statement = 3000
+
+# 性能优化
+effective_cache_size = 1GB
+random_page_cost = 1.1
+seq_page_cost = 1.0
+EOF
+
+cat > config/opengauss/pg_hba.conf << EOF
+# TYPE DATABASE USER ADDRESS METHOD
+local all all trust
+host all all 127.0.0.1/32 md5
+host all all ::1/128 md5
+host all all 0.0.0.0/0 md5
+EOF
+
+# 设置Redis配置
+echo "配置Redis..."
+cat > config/redis/redis.conf << EOF
+port 6379
+requirepass water_redis_2024
+timeout 300
+tcp-keepalive 300
+maxmemory 256mb
+maxmemory-policy allkeys-lru
+save 900 1
+save 300 10
+save 60 10000
+EOF
+
+# 设置Nginx配置
+echo "配置Nginx..."
+cat > config/nginx/nginx.conf << EOF
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+ worker_connections 1024;
+ use epoll;
+ multi_accept on;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
+ '\$status \$body_bytes_sent "\$http_referer" '
+ '"\$http_user_agent" "\$http_x_forwarded_for"';
+
+ access_log /var/log/nginx/access.log main;
+
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ client_max_body_size 50M;
+
+ gzip on;
+ gzip_vary on;
+ gzip_min_length 1024;
+ gzip_types text/plain text/css text/xml text/javascript
+ application/javascript application/xml+rss
+ application/json;
+
+ include /etc/nginx/conf.d/*.conf;
+}
+EOF
+
+cat > config/nginx/conf.d/water.conf << EOF
+upstream water_backend {
+ server water-server:8080 max_fails=3 fail_timeout=30s;
+ keepalive 32;
+}
+
+server {
+ listen 80;
+ server_name localhost;
+
+ location /admin-api/ {
+ proxy_pass http://water_backend;
+ proxy_set_header Host \$host;
+ proxy_set_header X-Real-IP \$remote_addr;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ proxy_connect_timeout 600;
+ proxy_send_timeout 600;
+ proxy_read_timeout 600;
+ }
+
+ location / {
+ proxy_pass http://water-ui;
+ proxy_set_header Host \$host;
+ proxy_set_header X-Real-IP \$remote_addr;
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto \$scheme;
+ }
+}
+EOF
+
+# 构建和启动服务
+echo "构建和启动Docker服务..."
+docker-compose down
+docker-compose build --no-cache
+docker-compose up -d
+
+# 等待服务启动
+echo "等待服务启动..."
+sleep 30
+
+# 检查服务状态
+echo "检查服务状态..."
+docker-compose ps
+
+echo "=== 部署完成 ==="
+echo "系统访问地址: http://localhost"
+echo "API接口地址: http://localhost/admin-api"
+echo "MinIO控制台: http://localhost:9001 (admin/admin123456)"
+echo ""
+echo "查看日志: docker-compose logs -f [服务名]"
+echo "停止服务: docker-compose down"
+echo "重启服务: docker-compose restart"#!/bin/bash
+# deploy-prod.sh
+
+set -e
+
+echo "=== 福建水务营收系统 生产环境部署脚本 ==="
+
+# 检查环境
+if ! command -v docker &> /dev/null; then
+ echo "错误: Docker未安装,请先安装Docker"
+ exit 1
+fi
+
+if ! command -v docker-compose &> /dev/null; then
+ echo "错误: Docker Compose未安装,请先安装Docker Compose"
+ exit 1
+fi
+
+# 设置环境变量
+export COMPOSE_PROJECT_NAME=water-system-prod
+export VERSION=${1:-latest}
+
+# 创建生产环境目录
+echo "创建生产环境目录..."
+mkdir -p {data,logs,config,upload,ssl,backups}/{prod,test}
+mkdir -p config/{opengauss,redis,nginx,app,prometheus,grafana}
+
+# 生成强密码
+DB_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
+REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
+
+# 创建环境变量文件
+echo "创建环境变量文件..."
+cat > .env.prod << EOF
+# 数据库配置
+DB_PASSWORD=${DB_PASSWORD}
+DB_HOST=water-opengauss
+DB_PORT=5432
+DB_NAME=ruoyi_water
+
+# Redis配置
+REDIS_PASSWORD=${REDIS_PASSWORD}
+REDIS_HOST=water-redis
+REDIS_PORT=6379
+
+# 应用配置
+VERSION=${VERSION}
+JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError
+
+# 网络配置
+NGINX_PORT=80
+NGINX_SSL_PORT=443
+
+# 日志级别
+LOG_LEVEL=INFO
+LOG_ROOT_LEVEL=WARN
+EOF
+
+echo "数据库密码: ${DB_PASSWORD}"
+echo "Redis密码: ${REDIS_PASSWORD}"
+echo "请妥善保存以上密码信息!"
+
+# 创建SSL证书(自签名,生产环境应使用正式证书)
+echo "创建SSL证书..."
+if [ ! -f ssl/water-system.crt ]; then
+ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
+ -keyout ssl/water-system.key \
+ -out ssl/water-system.crt \
+ -subj "/C=CN/ST=Fujian/L=Fuzhou/O=Water/CN=water.local"
+fi
+
+# 构建应用镜像
+echo "构建应用镜像..."
+docker build -t water-server:${VERSION} ./water-server
+docker build -t water-ui:${VERSION} ./water-ui
+
+# 停止现有服务
+echo "停止现有服务..."
+docker-compose --env-file .env.prod -f docker-compose.prod.yml down
+
+# 启动生产服务
+echo "启动生产服务..."
+docker-compose --env-file .env.prod -f docker-compose.prod.yml up -d
+
+# 等待服务启动
+echo "等待服务启动..."
+sleep 60
+
+# 检查服务状态
+echo "检查服务状态..."
+docker-compose --env-file .env.prod -f docker-compose.prod.yml ps
+
+# 健康检查
+echo "执行健康检查..."
+for i in {1..10}; do
+ if curl -f http://localhost/actuator/health >/dev/null 2>&1; then
+ echo "应用服务健康检查通过"
+ break
+ else
+ echo "等待应用服务启动... ($i/10)"
+ sleep 30
+ fi
+
+ if [ $i -eq 10 ]; then
+ echo "警告: 应用服务健康检查失败"
+ docker-compose --env-file .env.prod -f docker-compose.prod.yml logs water-server
+ fi
+done
+
+echo "=== 生产环境部署完成 ==="
+echo "系统访问地址: https://localhost"
+echo "系统监控地址: http://localhost:3000 (admin/admin123)"
+echo "数据库端口: 5432"
+echo "Redis端口: 6379"
+echo ""
+echo "管理命令:"
+echo " 查看日志: docker-compose --env-file .env.prod -f docker-compose.prod.yml logs -f [服务名]"
+echo " 停止服务: docker-compose --env-file .env.prod -f docker-compose.prod.yml down"
+echo " 重启服务: docker-compose --env-file .env.prod -f docker-compose.prod.yml restart [服务名]"
+echo " 备份数据: docker exec water-opengauss-prod gs_dump -h localhost -U water_user ruoyi_water > ./backups/backup-\$(date +%Y%m%d_%H%M%S).sql"# .github/workflows/deploy.yml
+name: Build and Deploy Water System
+
+on:
+ push:
+ branches: [ main, develop ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ REGISTRY: docker.io
+ IMAGE_NAME: water-system
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Cache Maven dependencies
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+
+ - name: Run tests
+ run: mvn clean test
+
+ - name: Generate test report
+ uses: dorny/test-reporter@v1
+ if: success() || failure()
+ with:
+ name: Maven Tests
+ path: target/surefire-reports/*.xml
+ reporter: java-junit
+
+ build:
+ needs: test
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Build with Maven
+ run: mvn clean package -DskipTests
+
+ - name: Build Docker image
+ run: |
+ docker build -t $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA ./water-server
+ docker build -t $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA ./water-ui
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Push Docker images
+ run: |
+ docker push $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA
+ docker push $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA
+ docker tag $REGISTRY/$IMAGE_NAME-server:$GITHUB_SHA $REGISTRY/$IMAGE_NAME-server:latest
+ docker tag $REGISTRY/$IMAGE_NAME-ui:$GITHUB_SHA $REGISTRY/$IMAGE_NAME-ui:latest
+ docker push $REGISTRY/$IMAGE_NAME-server:latest
+ docker push $REGISTRY/$IMAGE_NAME-ui:latest
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main'
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Deploy to Production
+ env:
+ DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
+ DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
+ run: |
+ # 设置SSH密钥
+ echo "$DEPLOY_KEY" > deploy_key
+ chmod 600 deploy_key
+
+ # 部署到生产服务器
+ ssh -i deploy_key -o StrictHostKeyChecking=no $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
+ cd /opt/water-system
+
+ # 拉取最新代码
+ git pull origin main
+
+ # 更新镜像版本
+ export VERSION=$GITHUB_SHA
+
+ # 重新部署
+ ./deploy-prod.sh $VERSION
+
+ # 验证部署
+ sleep 30
+ curl -f http://localhost/actuator/health || exit 1
+
+ echo "生产环境部署完成!"
+ EOF
+
+ rm -f deploy_key
+ echo "部署完成!"这样,我已经为福建水务营收系统的部署设计文档补充了完整的现代化部署方案,包括:
+这些配置都基于RuoYi-Vue-Pro框架的要求,提供了生产就绪的部署方案。