2024年12月19日
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 文档版本 | v1.0 |
| 编写日期 | 2024-12-19 |
| 文档状态 | ✅ 已完成 |
ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 技术框架 | RuoYi-Vue-Pro + yudao-ui-admin-vue3 |
| 文档版本 | v1.0 |
| 编写日期 | 2024-12-19 |
| 文档状态 | ✅ 基本完成 |
福建水务营收系统采用多层架构设计,旨在支持集团化的集中管理、统一资源管理的业务需求。系统架构的设计目标是实现”一个业务平台、一网通平台”的建设目标,为集团及下属各分公司提供统一的营业收费系统。
系统架构主要包括以下核心特点: - 多租户架构:支持集团、分公司、营业站点的多层级租户管理模式 - 统一资源服务:统一的数字水务系统运行资源环境 - 统一平台应用:统一业务流程,集中汇集数据 - 统一对外接口:提供标准的接口和能力
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
系统采用集中部署的模式,基于集团私有云环境进行部署。
系统提供标准化的接口,实现与外部系统的集成和数据交换。
ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 技术框架 | 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提供全文搜索
ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 技术框架 | RuoYi-Vue-Pro + yudao-ui-admin-vue3 |
| 文档版本 | v1.0 |
| 编写日期 | 2024-12-19 |
| 文档状态 | ✅ 已完成 |
福建水务营收系统采用华为OpenGauss 5.0+数据库,基于RuoYi-Vue-Pro框架规范设计。OpenGauss作为国产自主可控的企业级数据库,具有高性能、高可用、高安全的特点,完全满足水务行业对数据安全和国产化的要求。数据库架构支持多租户、高并发、高可用的业务需求,为水务营收业务提供稳定可靠的数据存储服务。
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 | BIT | 1 | 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');ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 技术框架 | RuoYi-Vue-Pro + yudao-ui-admin-vue3 |
| 文档版本 | v1.0 |
| 编写日期 | 2024-12-19 |
| 文档状态 | 🟡 进行中 |
福建水务业务系统提供丰富的接口,用于与外部系统集成以及系统内部各模块间的数据交换。接口设计遵循标准化、安全性、可扩展性的原则,基于RuoYi-Vue-Pro框架采用RESTful风格设计,支持JSON数据格式。
系统API接口采用RESTful风格设计,主要规范如下:
/users、/meters/users/1、/meters/123/users/1/meters系统统一采用以下JSON格式响应:
{
"code": 0, // 业务状态码,0表示成功,非0表示失败
"data": {}, // 响应数据
"msg": "success" // 响应消息
}分页查询响应格式:
{
"code": 0,
"data": {
"list": [], // 数据列表
"total": 100, // 总记录数
"pageNum": 1, // 当前页码
"pageSize": 10 // 每页记录数
},
"msg": "success"
}系统使用Knife4j(基于Swagger)自动生成API文档,文档地址为:http://{系统地址}/doc.html。
主要特点: - 在线接口文档:支持在线查看接口定义 - 接口调试:支持在线调试接口 - 文档导出:支持导出OpenAPI规范文档 - 权限控制:支持对接口文档的访问控制
功能描述:通过银行系统自动从用户账户中扣除水费。
接口详情: - 接口方式:文件交换(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();
}
}功能描述:用户在银行柜台、网上银行或手机银行实时缴纳水费。
接口详情: - 接口方式: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 - 交换频率:实时
功能描述:与物联网集抄平台交互,获取智能水表数据。
接口规范: - 接口方式:HTTP接口或WebService - 数据格式:JSON或XML - 交换频率:定时或实时
功能描述:根据客户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);
}
}
}功能描述:根据水表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": "水表不存在"
}
]
}
}功能描述:根据客户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..."
}
}功能描述:创建业务工单。
接口规范: - 请求方式:POST - 请求路径:/api/workorders - 请求/返回格式:JSON
功能描述:更新工单处理状态。
接口规范: - 请求方式:PUT - 请求路径:/api/workorders/{workorderId}/status - 请求/返回格式:JSON
系统接口主要采用以下协议:
接口数据主要采用以下格式:
接口安全采用多层防护机制:
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>
ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 概要设计文档 |
| 技术框架 | 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 "部署完成!"这样,我已经为福建水务营收系统的部署设计文档补充了完整的现代化部署方案,包括:
ewpage
| 项目信息 | 详情 |
|---|---|
| 项目名称 | 福建水务营收系统 |
| 文档类型 | 安全设计文档 |
| 技术框架 | RuoYi-Vue-Pro + OpenGauss |
| 文档版本 | v1.0 |
| 编写日期 | 2024-12-19 |
| 文档状态 | ✅ 已完成 |
福建水务营收系统安全设计严格按照《网络安全等级保护基本要求》第三级标准,结合水务行业特点和国产化要求,构建全方位、多层次的安全防护体系。
graph TB
subgraph "外部威胁"
THREAT1[网络攻击]
THREAT2[恶意软件]
THREAT3[数据泄露]
THREAT4[内部威胁]
end
subgraph "安全防护层"
subgraph "边界安全"
WAF[Web应用防火墙]
FW[网络防火墙]
IPS[入侵防护系统]
VPN[VPN网关]
end
subgraph "应用安全"
AUTH[身份认证]
AUTHZ[访问控制]
AUDIT[操作审计]
ENCRYPT[数据加密]
end
subgraph "数据安全"
TDE[透明数据加密]
RLS[行级安全]
MASK[数据脱敏]
BACKUP[安全备份]
end
subgraph "运维安全"
MONITOR[安全监控]
LOG[日志分析]
ALERT[告警响应]
PATCH[安全更新]
end
end
subgraph "核心资产"
APP[水务营收系统]
DB[OpenGauss数据库]
FILE[文件存储]
API[接口服务]
end
THREAT1 --> WAF
THREAT2 --> FW
THREAT3 --> IPS
THREAT4 --> VPN
WAF --> AUTH
FW --> AUTHZ
IPS --> AUDIT
VPN --> ENCRYPT
AUTH --> TDE
AUTHZ --> RLS
AUDIT --> MASK
ENCRYPT --> BACKUP
TDE --> MONITOR
RLS --> LOG
MASK --> ALERT
BACKUP --> PATCH
MONITOR --> APP
LOG --> DB
ALERT --> FILE
PATCH --> API
网络架构安全
graph TB
subgraph "安全区域划分"
DMZ[DMZ区<br/>Web服务器]
APP_ZONE[应用区<br/>应用服务器]
DB_ZONE[数据区<br/>数据库服务器]
MGT_ZONE[管理区<br/>运维管理]
end
subgraph "边界防护"
INTERNET[互联网]
FW1[边界防火墙]
FW2[内部防火墙]
IDS[入侵检测系统]
end
subgraph "访问控制"
VPN[VPN接入]
JUMP[跳板机]
BASTION[堡垒机]
end
INTERNET --> FW1
FW1 --> DMZ
DMZ --> FW2
FW2 --> APP_ZONE
APP_ZONE --> DB_ZONE
VPN --> JUMP
JUMP --> BASTION
BASTION --> MGT_ZONE
IDS --> DMZ
IDS --> APP_ZONE
网络安全措施 - 网络边界部署防火墙,实现网络访问控制 - 重要网络设备和服务器前端部署网络入侵检测设备 - 网络分段部署,DMZ区、应用区、数据区物理隔离 - 关键网络设备提供双机热备功能 - 网络设备登录实现身份标识和鉴别
区域边界防护 - 在网络边界部署防火墙设备,设置访问控制策略 - 在网络边界部署入侵检测设备,监控网络攻击行为 - 在应用层部署Web应用防火墙,防护Web应用攻击 - 对进出网络的数据流进行过滤和监控 - 建立网络访问控制策略,限制不必要的网络连接
身份鉴别
graph LR
subgraph "多因素认证"
USER[用户] --> AUTH1[用户名密码]
AUTH1 --> AUTH2[短信验证码]
AUTH2 --> AUTH3[邮箱验证]
AUTH3 --> TOKEN[JWT Token]
end
subgraph "认证集成"
LDAP[LDAP认证]
SSO[单点登录]
OAUTH[OAuth2.0]
SAML[SAML认证]
end
TOKEN --> LDAP
TOKEN --> SSO
TOKEN --> OAUTH
TOKEN --> SAML
访问控制设计 - 实现基于角色的访问控制(RBAC) - 支持基于属性的访问控制(ABAC) - 实现最小权限原则 - 支持权限的动态调整和审批流程
graph TB
subgraph "OpenGauss安全特性"
subgraph "身份认证"
PWD[密码认证]
CERT[证书认证]
LDAP_AUTH[LDAP认证]
KERBEROS[Kerberos认证]
end
subgraph "访问控制"
RBAC_DB[基于角色的访问控制]
RLS_DB[行级安全策略]
CLS_DB[列级访问控制]
SCHEMA[模式权限控制]
end
subgraph "数据加密"
TDE_SM4[TDE透明加密<br/>SM4国密算法]
SSL_SM[SSL传输加密<br/>SM2/SM3/SM4]
FIELD_ENC[字段级加密]
BACKUP_ENC[备份加密]
end
subgraph "审计监控"
AUDIT_LOG[操作审计日志]
LOGIN_LOG[登录审计]
DDL_LOG[DDL操作记录]
SECURITY_LOG[安全事件日志]
end
end
PWD --> RBAC_DB
CERT --> RLS_DB
LDAP_AUTH --> CLS_DB
KERBEROS --> SCHEMA
RBAC_DB --> TDE_SM4
RLS_DB --> SSL_SM
CLS_DB --> FIELD_ENC
SCHEMA --> BACKUP_ENC
TDE_SM4 --> AUDIT_LOG
SSL_SM --> LOGIN_LOG
FIELD_ENC --> DDL_LOG
BACKUP_ENC --> SECURITY_LOG
-- 配置国密SSL连接
ALTER SYSTEM SET ssl = on;
ALTER SYSTEM SET ssl_ciphers = 'SM4-GCM-SM3:SM4-CCM-SM3';
ALTER SYSTEM SET ssl_cert_file = 'server-sm2.crt';
ALTER SYSTEM SET ssl_key_file = 'server-sm2.key';-- 启用TDE透明数据加密,使用SM4算法
CREATE KEY ENCRYPTION KEY water_biz_kek
WITH ALGORITHM = 'SM4-CTR', KEY_STORE = 'localkms';
-- 为敏感表启用加密
CREATE TABLE water_customer (
id SERIAL PRIMARY KEY,
customer_name VARCHAR(100) ENCRYPTED WITH (
COLUMN_ENCRYPTION_KEY = water_biz_kek,
ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'SM4-CTR'
),
id_card VARCHAR(18) ENCRYPTED WITH (
COLUMN_ENCRYPTION_KEY = water_biz_kek,
ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'SM4-CTR'
)
);-- 创建多租户行级安全策略
CREATE ROW LEVEL SECURITY POLICY tenant_isolation_policy
ON water_customer
USING (tenant_id = current_setting('app.current_tenant_id')::bigint);
-- 启用行级安全
ALTER TABLE water_customer ENABLE ROW LEVEL SECURITY;
-- 创建数据访问角色
CREATE ROLE water_data_reader;
CREATE ROLE water_data_writer;
-- 配置列级权限
GRANT SELECT (id, customer_name, phone) ON water_customer TO water_data_reader;
GRANT ALL ON water_customer TO water_data_writer;-- 创建数据脱敏函数
CREATE OR REPLACE FUNCTION mask_phone(phone_num TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN SUBSTRING(phone_num, 1, 3) || '****' || SUBSTRING(phone_num, 8, 4);
END;
$$ LANGUAGE plpgsql;
-- 创建脱敏视图
CREATE VIEW water_customer_masked AS
SELECT
id,
customer_name,
mask_phone(phone) as phone,
LEFT(id_card, 6) || '********' || RIGHT(id_card, 4) as id_card_masked
FROM water_customer;
-- 授权普通用户只能访问脱敏视图
GRANT SELECT ON water_customer_masked TO water_normal_user;@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// 使用国密SM3哈希算法
return new SM3PasswordEncoder();
}
@Bean
public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
// CSRF防护
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
// 请求授权
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/login", "/api/register").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
// JWT过滤器
.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
// 会话管理
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
}@Service
public class MFAService {
@Autowired
private SmsService smsService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean sendSmsCode(String phone) {
String code = generateRandomCode();
String key = "mfa:sms:" + phone;
// 存储验证码,5分钟过期
redisTemplate.opsForValue().set(key, code, Duration.ofMinutes(5));
// 发送短信
return smsService.send(phone, "您的验证码是:" + code + ",5分钟内有效。");
}
public boolean verifySmsCode(String phone, String code) {
String key = "mfa:sms:" + phone;
String storedCode = redisTemplate.opsForValue().get(key);
if (storedCode != null && storedCode.equals(code)) {
redisTemplate.delete(key);
return true;
}
return false;
}
}server:
port: 8443
ssl:
enabled: true
key-store: classpath:keystore/server.p12
key-store-password: ${SSL_KEYSTORE_PASSWORD}
key-store-type: PKCS12
# 支持国密算法
ciphers: SM4-GCM-SM3,SM4-CCM-SM3,ECDHE-SM2-WITH-SM4-SM3
protocols: TLSv1.2,TLSv1.3@Component
public class DataEncryptionService {
private final SM4Cipher sm4Cipher = new SM4Cipher();
public String encryptSensitiveData(String plaintext) {
try {
return sm4Cipher.encrypt(plaintext);
} catch (Exception e) {
throw new SecurityException("数据加密失败", e);
}
}
public String decryptSensitiveData(String ciphertext) {
try {
return sm4Cipher.decrypt(ciphertext);
} catch (Exception e) {
throw new SecurityException("数据解密失败", e);
}
}
}@Component
public class ApiSignatureValidator {
public boolean validateSignature(HttpServletRequest request) {
String timestamp = request.getHeader("X-Timestamp");
String nonce = request.getHeader("X-Nonce");
String signature = request.getHeader("X-Signature");
String body = getRequestBody(request);
// 检查时间戳,防止重放攻击
if (isTimestampExpired(timestamp)) {
return false;
}
// 生成签名
String expectedSignature = generateSignature(timestamp, nonce, body);
// 验证签名
return signature.equals(expectedSignature);
}
private String generateSignature(String timestamp, String nonce, String body) {
String message = timestamp + nonce + body;
return SM3Utils.hash(message);
}
}@Component
public class RateLimitService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean isAllowed(String key, int limit, Duration window) {
String redisKey = "rate_limit:" + key;
String current = redisTemplate.opsForValue().get(redisKey);
if (current == null) {
redisTemplate.opsForValue().set(redisKey, "1", window);
return true;
}
int count = Integer.parseInt(current);
if (count < limit) {
redisTemplate.opsForValue().increment(redisKey);
return true;
}
return false;
}
}graph TB
subgraph "外网区域"
INTERNET[互联网]
CDN[CDN加速]
DNS[DNS服务]
end
subgraph "边界防护"
WAF[Web应用防火墙<br/>国产WAF产品]
FW_BORDER[边界防火墙<br/>安全审计]
IPS[入侵防护系统<br/>威胁检测]
DPI[深度包检测<br/>流量分析]
end
subgraph "DMZ区域"
LB[负载均衡器<br/>SSL卸载]
WEB1[Web服务器1]
WEB2[Web服务器2]
PROXY[反向代理]
end
subgraph "内网安全"
FW_INTERNAL[内部防火墙]
VLAN_APP[应用VLAN]
VLAN_DB[数据库VLAN]
VLAN_MGT[管理VLAN]
end
subgraph "应用层"
APP1[应用服务器1]
APP2[应用服务器2]
APP3[应用服务器3]
end
subgraph "数据层"
DB_MASTER[OpenGauss主库]
DB_SLAVE[OpenGauss从库]
REDIS[Redis集群]
end
subgraph "管理层"
JUMP[跳板机]
MONITOR[监控服务器]
LOG[日志服务器]
end
INTERNET --> CDN
CDN --> DNS
DNS --> WAF
WAF --> FW_BORDER
FW_BORDER --> IPS
IPS --> DPI
DPI --> LB
LB --> WEB1
LB --> WEB2
WEB1 --> PROXY
WEB2 --> PROXY
PROXY --> FW_INTERNAL
FW_INTERNAL --> VLAN_APP
FW_INTERNAL --> VLAN_DB
FW_INTERNAL --> VLAN_MGT
VLAN_APP --> APP1
VLAN_APP --> APP2
VLAN_APP --> APP3
VLAN_DB --> DB_MASTER
VLAN_DB --> DB_SLAVE
VLAN_DB --> REDIS
VLAN_MGT --> JUMP
VLAN_MGT --> MONITOR
VLAN_MGT --> LOG
##### 允许HTTPS访问
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
##### 允许HTTP重定向到HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
##### 禁止直接数据库访问
iptables -A INPUT -p tcp --dport 5432 -s ! 192.168.1.0/24 -j DROP
##### 允许内网SSH管理
iptables -A INPUT -p tcp --dport 22 -s 192.168.100.0/24 -j ACCEPT
##### 拒绝其他所有入站连接
iptables -A INPUT -j DROP##### 只允许来自DMZ区的连接
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
##### 允许访问数据库
iptables -A OUTPUT -d 192.168.2.0/24 -p tcp --dport 5432 -j ACCEPT
##### 允许访问Redis
iptables -A OUTPUT -d 192.168.2.0/24 -p tcp --dport 6379 -j ACCEPT
##### 允许DNS查询
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
##### 拒绝其他出站连接
iptables -A OUTPUT -j DROP##### Suricata规则示例
alert tcp any any -> $HOME_NET 443 (msg:"Suspicious HTTPS traffic"; \
content:"POST"; http_method; content:"/api/admin"; http_uri; \
threshold:type limit, track by_src, count 10, seconds 60; \
sid:10001; rev:1;)
alert tcp any any -> $HOME_NET 5432 (msg:"Direct database access attempt"; \
content:"SELECT"; content:"FROM"; distance:0; \
sid:10002; rev:1;)
alert tcp any any -> $HOME_NET any (msg:"Brute force attack detected"; \
flags:S; threshold:type threshold, track by_src, count 100, seconds 60; \
sid:10003; rev:1;)graph TB
subgraph "数据分类"
TOP_SECRET[绝密级<br/>核心商业机密]
SECRET[机密级<br/>重要业务数据]
INTERNAL[内部级<br/>一般业务数据]
PUBLIC[公开级<br/>公开业务数据]
end
subgraph "水务业务数据"
CUSTOMER[客户身份信息<br/>机密级]
METER[水表计量数据<br/>内部级]
BILLING[收费账务数据<br/>机密级]
REPORT[统计报表数据<br/>内部级]
CONFIG[系统配置数据<br/>内部级]
LOG[日志审计数据<br/>内部级]
end
subgraph "保护措施"
ENC_HIGH[强加密<br/>SM4+数字签名]
ENC_MID[加密存储<br/>SM4算法]
ENC_LOW[访问控制<br/>权限管理]
ENC_NONE[公开访问<br/>无特殊保护]
end
TOP_SECRET --> ENC_HIGH
SECRET --> ENC_MID
INTERNAL --> ENC_LOW
PUBLIC --> ENC_NONE
CUSTOMER --> SECRET
BILLING --> SECRET
METER --> INTERNAL
REPORT --> INTERNAL
CONFIG --> INTERNAL
LOG --> INTERNAL
-- 客户敏感信息表(机密级)
CREATE TABLE water_customer_sensitive (
id SERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL,
-- 身份证号:强加密存储
id_card_encrypted VARCHAR(200) ENCRYPTED WITH (
COLUMN_ENCRYPTION_KEY = customer_sensitive_key,
ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'SM4-CTR'
),
-- 银行卡号:强加密存储
bank_account_encrypted VARCHAR(200) ENCRYPTED WITH (
COLUMN_ENCRYPTION_KEY = customer_sensitive_key,
ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'SM4-CTR'
),
-- 手机号:确定性加密,支持查询
phone_encrypted VARCHAR(200) ENCRYPTED WITH (
COLUMN_ENCRYPTION_KEY = customer_sensitive_key,
ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'SM4-CTR'
),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 创建行级安全策略
CREATE POLICY customer_sensitive_policy ON water_customer_sensitive
FOR ALL TO water_customer_service_role
USING (
customer_id IN (
SELECT customer_id FROM water_customer
WHERE tenant_id = current_setting('app.current_tenant_id')::bigint
)
);#!/bin/bash
##### OpenGauss安全备份脚本
##### 设置备份参数
BACKUP_DIR="/backup/opengauss"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="water_biz_backup_${DATE}.tar.gz"
ENCRYPT_KEY="/etc/opengauss/backup_key.key"
##### 创建加密备份
gs_backup -D $GAUSSDATA -U gaussdb \
--encrypt --encrypt-key-file=$ENCRYPT_KEY \
--backup-format=tar \
--backup-path=$BACKUP_DIR/$BACKUP_FILE
##### 验证备份完整性
openssl dgst -sm3 $BACKUP_DIR/$BACKUP_FILE > $BACKUP_DIR/$BACKUP_FILE.sm3
##### 安全传输到异地备份中心
rsync -avz --delete $BACKUP_DIR/ backup-server:/backup/remote/-- 恢复前验证备份完整性
-- 1. 验证SM3摘要
-- 2. 解密备份文件
-- 3. 验证数据库结构
-- 4. 执行恢复操作
-- 创建恢复测试环境
CREATE DATABASE water_biz_recovery_test;
-- 恢复数据到测试环境
\c water_biz_recovery_test;
-- 执行恢复SQL脚本
\i /backup/water_biz_recovery.sql;
-- 验证数据完整性
SELECT COUNT(*) FROM water_customer;
SELECT COUNT(*) FROM water_meter_reading;
SELECT COUNT(*) FROM water_billing;
-- 验证加密数据
SELECT id,
pgp_sym_decrypt(id_card_encrypted, 'encryption_key') as id_card
FROM water_customer_sensitive LIMIT 1;-- 创建安全数据销毁函数
CREATE OR REPLACE FUNCTION secure_data_destroy(table_name TEXT, where_clause TEXT)
RETURNS BOOLEAN AS $$
DECLARE
sql_cmd TEXT;
affected_rows INTEGER;
BEGIN
-- 构建删除SQL
sql_cmd := 'DELETE FROM ' || table_name || ' WHERE ' || where_clause;
-- 执行删除
EXECUTE sql_cmd;
GET DIAGNOSTICS affected_rows = ROW_COUNT;
-- 记录审计日志
INSERT INTO data_destroy_audit (
table_name, where_clause, affected_rows,
operator, operation_time
) VALUES (
table_name, where_clause, affected_rows,
current_user, current_timestamp
);
-- 执行VACUUM清理物理空间
EXECUTE 'VACUUM FULL ' || table_name;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION '数据销毁失败: %', SQLERRM;
RETURN FALSE;
END;
$$ LANGUAGE plpgsql;
-- 示例:销毁3年前的历史数据
SELECT secure_data_destroy(
'water_meter_reading_history',
'reading_date < CURRENT_DATE - INTERVAL ''3 years'''
);graph TB
subgraph "数据采集层"
AGENT1[系统日志采集]
AGENT2[应用日志采集]
AGENT3[数据库日志采集]
AGENT4[网络流量采集]
end
subgraph "数据处理层"
KAFKA[消息队列<br/>Kafka集群]
STREAM[流处理<br/>Flink/Storm]
ETL[数据清洗<br/>Logstash]
end
subgraph "存储分析层"
ES[Elasticsearch<br/>日志存储]
SIEM[安全信息事件管理<br/>SIEM平台]
AI[智能分析<br/>机器学习]
end
subgraph "可视化层"
DASHBOARD[监控仪表盘<br/>Grafana]
ALERT[告警系统<br/>AlertManager]
REPORT[安全报告<br/>自动生成]
end
AGENT1 --> KAFKA
AGENT2 --> KAFKA
AGENT3 --> KAFKA
AGENT4 --> KAFKA
KAFKA --> STREAM
STREAM --> ETL
ETL --> ES
ES --> SIEM
SIEM --> AI
AI --> DASHBOARD
DASHBOARD --> ALERT
ALERT --> REPORT
##### 安全事件检测规则配置
security_rules:
- name: "暴力破解检测"
type: "authentication"
condition: "failed_login_count > 5 in 5 minutes"
severity: "high"
action: ["block_ip", "send_alert"]
- name: "异常数据访问"
type: "data_access"
condition: "query_count > 1000 in 1 minute"
severity: "medium"
action: ["rate_limit", "send_alert"]
- name: "权限提升检测"
type: "privilege_escalation"
condition: "role_change to admin"
severity: "critical"
action: ["block_user", "send_alert", "create_incident"]
- name: "异常时间访问"
type: "abnormal_access"
condition: "access_time between 22:00 and 06:00"
severity: "medium"
action: ["log_event", "send_alert"]#!/bin/bash
##### 系统漏洞扫描脚本
##### 扫描操作系统漏洞
nmap -sV --script vulners localhost
##### 扫描Web应用漏洞
nikto -h https://water.example.com -ssl
##### 扫描数据库漏洞
nmap -p 5432 --script pgsql-brute,pgsql-databases localhost
##### 生成漏洞报告
cat > vulnerability_report.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>安全漏洞扫描报告</title>
</head>
<body>
<h1>福建水务营收系统漏洞扫描报告</h1>
<p>扫描时间:$(date)</p>
<h2>高危漏洞</h2>
<pre>$(grep -i "high\|critical" scan_results.txt)</pre>
<h2>中危漏洞</h2>
<pre>$(grep -i "medium" scan_results.txt)</pre>
</body>
</html>
EOFgraph LR
DISCOVER[漏洞发现] --> ASSESS[风险评估]
ASSESS --> PLAN[补丁计划]
PLAN --> TEST[测试验证]
TEST --> DEPLOY[生产部署]
DEPLOY --> VERIFY[部署验证]
VERIFY --> DOCUMENT[文档记录]
subgraph "评估标准"
HIGH[高危<br/>24小时内]
MEDIUM[中危<br/>7天内]
LOW[低危<br/>30天内]
end
ASSESS --> HIGH
ASSESS --> MEDIUM
ASSESS --> LOW
| 级别 | 描述 | 响应时间 | 处理措施 |
|---|---|---|---|
| P0 | 系统完全不可用,数据泄露 | 15分钟 | 立即启动应急预案,通知管理层 |
| P1 | 核心功能受影响,安全风险高 | 30分钟 | 启动应急预案,组建应急小组 |
| P2 | 部分功能受影响,安全风险中等 | 2小时 | 安排专人处理,定期汇报 |
| P3 | 轻微影响,安全风险较低 | 8小时 | 正常工作时间处理 |
graph TB
INCIDENT[安全事件发生] --> DETECT[事件检测]
DETECT --> REPORT[事件上报]
REPORT --> ASSESS[影响评估]
ASSESS --> RESPONSE[应急响应]
subgraph "应急响应措施"
ISOLATE[系统隔离]
PRESERVE[证据保全]
RECOVER[系统恢复]
INVESTIGATE[调查分析]
end
subgraph "后续处理"
LESSON[经验总结]
IMPROVE[流程改进]
TRAIN[培训加强]
DOC[文档更新]
end
RESPONSE --> ISOLATE
RESPONSE --> PRESERVE
RESPONSE --> RECOVER
RESPONSE --> INVESTIGATE
INVESTIGATE --> LESSON
LESSON --> IMPROVE
IMPROVE --> TRAIN
TRAIN --> DOC
graph TB
CEO[总经理<br/>安全最高责任人]
CISO[信息安全负责人<br/>CISO]
subgraph "安全管理委员会"
IT_DIR[IT总监]
SECURITY_DIR[安全总监]
COMPLIANCE[合规负责人]
LEGAL[法务负责人]
end
subgraph "安全执行团队"
SEC_ADMIN[安全管理员]
SYS_ADMIN[系统管理员]
DBA[数据库管理员]
NET_ADMIN[网络管理员]
end
subgraph "业务安全责任人"
BUS_OWNER[业务负责人]
DATA_OWNER[数据负责人]
USER_ADMIN[用户管理员]
end
CEO --> CISO
CISO --> IT_DIR
CISO --> SECURITY_DIR
CISO --> COMPLIANCE
CISO --> LEGAL
IT_DIR --> SEC_ADMIN
IT_DIR --> SYS_ADMIN
IT_DIR --> DBA
IT_DIR --> NET_ADMIN
SECURITY_DIR --> BUS_OWNER
SECURITY_DIR --> DATA_OWNER
SECURITY_DIR --> USER_ADMIN
福建水务营收系统安全设计严格按照等级保护三级要求,结合OpenGauss数据库的安全特性,建立了全方位、多层次的安全防护体系。通过技术防护、管理制度、人员培训等多重措施,确保系统安全稳定运行,满足水务行业的安全合规要求。
本安全设计方案的核心特点: 1. 国产化安全:采用OpenGauss数据库和国密算法 2. 纵深防御:网络、应用、数据多层安全防护 3. 合规导向:严格按照等保三级标准设计 4. 持续改进:建立安全监控和应急响应机制 5. 管理规范:完善的安全管理制度和流程 —