Compare commits
12 Commits
ee6dd64f98
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 68c91b4ba3 | |||
| 133209691e | |||
| a8233ceb72 | |||
| ab8be1a832 | |||
| 917e9a517a | |||
| 9a3547b70b | |||
| b3200f8858 | |||
| 9cb4844be4 | |||
| 90ddcf7af3 | |||
| 28787e5b29 | |||
| 2a9e624ba9 | |||
| 94718edd6b |
116
Makefile
Normal file
116
Makefile
Normal file
@@ -0,0 +1,116 @@
|
||||
# Urban Lifeline 开发环境快捷命令
|
||||
|
||||
.PHONY: help up down logs restart clean build ps
|
||||
|
||||
# 默认目标
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# 帮助信息
|
||||
help:
|
||||
@echo "========================================="
|
||||
@echo " 泰豪电源 Urban Lifeline 开发环境"
|
||||
@echo "========================================="
|
||||
@echo ""
|
||||
@echo "可用命令:"
|
||||
@echo " make up - 启动所有服务"
|
||||
@echo " make down - 停止所有服务"
|
||||
@echo " make restart - 重启所有服务"
|
||||
@echo " make logs - 查看所有服务日志"
|
||||
@echo " make ps - 查看服务状态"
|
||||
@echo " make build - 重新构建镜像"
|
||||
@echo " make clean - 清理所有数据(慎用)"
|
||||
@echo ""
|
||||
@echo "单独服务操作:"
|
||||
@echo " make logs-portal - 查看主应用日志"
|
||||
@echo " make logs-gateway - 查看网关日志"
|
||||
@echo " make restart-portal - 重启主应用"
|
||||
@echo " make shell-portal - 进入主应用容器"
|
||||
@echo ""
|
||||
|
||||
# 启动所有服务
|
||||
up:
|
||||
@echo "启动开发环境..."
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
@echo "服务启动中,请稍候..."
|
||||
@sleep 5
|
||||
@echo ""
|
||||
@echo "访问地址:"
|
||||
@echo " 主应用: http://localhost"
|
||||
@echo " 招投标: http://localhost/bidding"
|
||||
@echo " 智能客服: http://localhost/customer-service"
|
||||
@echo " Gateway: http://localhost/api"
|
||||
@echo " Nacos: http://localhost/nacos"
|
||||
@echo ""
|
||||
|
||||
# 停止所有服务
|
||||
down:
|
||||
@echo "停止所有服务..."
|
||||
docker-compose -f docker-compose.dev.yml down
|
||||
|
||||
# 查看日志
|
||||
logs:
|
||||
docker-compose -f docker-compose.dev.yml logs -f
|
||||
|
||||
# 重启所有服务
|
||||
restart:
|
||||
@echo "重启所有服务..."
|
||||
docker-compose -f docker-compose.dev.yml restart
|
||||
|
||||
# 查看服务状态
|
||||
ps:
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
|
||||
# 重新构建镜像
|
||||
build:
|
||||
@echo "重新构建所有镜像..."
|
||||
docker-compose -f docker-compose.dev.yml build --no-cache
|
||||
|
||||
# 清理所有数据(危险操作)
|
||||
clean:
|
||||
@echo "警告:此操作将删除所有容器、数据卷和镜像!"
|
||||
@read -p "确认继续吗?(y/N): " confirm && [ "$$confirm" = "y" ] || exit 1
|
||||
docker-compose -f docker-compose.dev.yml down -v
|
||||
docker system prune -af
|
||||
|
||||
# ==================== 单独服务操作 ====================
|
||||
|
||||
# Portal 日志
|
||||
logs-portal:
|
||||
docker-compose -f docker-compose.dev.yml logs -f portal
|
||||
|
||||
# Gateway 日志
|
||||
logs-gateway:
|
||||
docker-compose -f docker-compose.dev.yml logs -f gateway
|
||||
|
||||
# Nginx 日志
|
||||
logs-nginx:
|
||||
docker-compose -f docker-compose.dev.yml logs -f nginx
|
||||
|
||||
# 共享包日志
|
||||
logs-shared:
|
||||
docker-compose -f docker-compose.dev.yml logs -f shared
|
||||
|
||||
# 重启 Portal
|
||||
restart-portal:
|
||||
docker-compose -f docker-compose.dev.yml restart portal
|
||||
|
||||
# 重启 Gateway
|
||||
restart-gateway:
|
||||
docker-compose -f docker-compose.dev.yml restart gateway
|
||||
|
||||
# 进入 Portal 容器
|
||||
shell-portal:
|
||||
docker-compose -f docker-compose.dev.yml exec portal sh
|
||||
|
||||
# 进入 Gateway 容器
|
||||
shell-gateway:
|
||||
docker-compose -f docker-compose.dev.yml exec gateway sh
|
||||
|
||||
# 进入数据库
|
||||
db:
|
||||
docker-compose -f docker-compose.dev.yml exec postgres psql -U postgres -d urban_lifeline
|
||||
|
||||
# 初始化数据库
|
||||
db-init:
|
||||
@echo "初始化数据库..."
|
||||
docker-compose -f docker-compose.dev.yml exec postgres psql -U postgres -d urban_lifeline -f /docker-entrypoint-initdb.d/initAll.sql
|
||||
228
README.md
228
README.md
@@ -1,3 +1,227 @@
|
||||
# urbanLifeline
|
||||
# 泰豪电源 AI 数智化平台
|
||||
|
||||
城市生命线
|
||||
城市生命线智能管理系统 - Urban Lifeline
|
||||
|
||||
## 项目简介
|
||||
|
||||
基于 **"一个底座、多种智能体"** 架构的企业级 AI 数智化平台,包含四大核心业务模块:
|
||||
|
||||
1. **资料管理智能化** - 智能文档管理与检索
|
||||
2. **招投标自动化** - 招投标全流程智能化
|
||||
3. **售后客服智能化** - AI 驱动的智能客服系统
|
||||
4. **企业内部知识协同** - 知识库管理与协作
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 后端技术栈
|
||||
|
||||
- **Java 21** + **Spring Boot 3.5**
|
||||
- **Spring Cloud Gateway** - API 网关
|
||||
- **Nacos** - 服务注册与配置中心
|
||||
- **PostgreSQL 16** - 主数据库
|
||||
- **Redis 7** - 缓存
|
||||
- **Dubbo 3.3** - RPC 框架
|
||||
|
||||
### 前端技术栈
|
||||
|
||||
- **Vue 3.5** (`<script setup>`)
|
||||
- **TypeScript 5.7**
|
||||
- **Vite 6.0** - 构建工具
|
||||
- **Pinia 2.2** - 状态管理
|
||||
- **Element Plus 2.9** - UI 组件库
|
||||
- **pnpm 9.0 + Turborepo 2.0** - Monorepo 管理
|
||||
|
||||
### 核心特性:共享组件 HTTP 导入
|
||||
|
||||
采用 **Import Maps + ES Module** 方案,实现真正的运行时组件共享:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// 直接从 HTTP URL 导入共享组件
|
||||
import { UlTable } from '@shared/components' // → http://localhost/shared/components.js
|
||||
import { http } from '@shared/utils' // → http://localhost/shared/utils.js
|
||||
import { authApi } from '@shared/api' // → http://localhost/shared/api.js
|
||||
</script>
|
||||
```
|
||||
|
||||
**工作原理**:
|
||||
1. 共享包构建为 ES Module (`components.js`)
|
||||
2. 部署到独立 HTTP 服务 (`http://localhost:5000`)
|
||||
3. 通过 Nginx 统一代理 (`http://localhost/shared/`)
|
||||
4. 浏览器通过 Import Maps 直接加载
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 方式一:Docker Compose(推荐)
|
||||
|
||||
```bash
|
||||
# 1. 启动所有服务(自动构建)
|
||||
make up
|
||||
|
||||
# 2. 等待服务启动(约1-2分钟)
|
||||
make ps
|
||||
|
||||
# 3. 访问应用
|
||||
open http://localhost
|
||||
```
|
||||
|
||||
### 方式二:本地开发
|
||||
|
||||
```bash
|
||||
# 1. 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 2. 启动后端服务(需要 Java 21)
|
||||
cd urbanLifelineServ
|
||||
mvn spring-boot:run
|
||||
|
||||
# 3. 启动前端服务
|
||||
cd urbanLifelineWeb
|
||||
pnpm dev
|
||||
|
||||
# 4. 访问
|
||||
open http://localhost:3000
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
urbanLifeline/
|
||||
├── urbanLifelineServ/ # 后端服务(Spring Boot)
|
||||
│ ├── gateway/ # API 网关
|
||||
│ ├── auth/ # 认证服务
|
||||
│ ├── system/ # 系统服务
|
||||
│ ├── file/ # 文件服务
|
||||
│ └── common/ # 公共模块
|
||||
│
|
||||
├── urbanLifelineWeb/ # 前端应用(Vue 3 Monorepo)
|
||||
│ ├── packages/
|
||||
│ │ ├── shared/ # 共享组件库
|
||||
│ │ │ ├── components/ # 公共组件
|
||||
│ │ │ ├── utils/ # 工具函数
|
||||
│ │ │ ├── api/ # API 封装
|
||||
│ │ │ └── composables/ # 组合式函数
|
||||
│ │ ├── portal/ # 主应用
|
||||
│ │ ├── app-bidding/ # 招投标应用
|
||||
│ │ └── app-knowledge/ # 知识协同应用
|
||||
│ ├── pnpm-workspace.yaml
|
||||
│ └── turbo.json
|
||||
│
|
||||
├── docker-compose.dev.yml # Docker 开发环境
|
||||
├── Makefile # 快捷命令
|
||||
└── docs/ # 文档
|
||||
├── 前端完整指南.md # ⭐ 前端全流程文档
|
||||
└── 数据库设计文档.md # ⭐ 数据库全流程文档
|
||||
```
|
||||
|
||||
## 访问地址
|
||||
|
||||
| 应用 | 地址 | 说明 |
|
||||
|------|------|------|
|
||||
| **主应用** | http://localhost/ | Portal 统一入口 |
|
||||
| **招投标** | http://localhost/bidding | 招投标智能体 |
|
||||
| **智能客服** | http://localhost/customer-service | 客服系统 |
|
||||
| **共享组件** | http://localhost/shared/components.js | ES Module |
|
||||
| **API 网关** | http://localhost/api | Gateway |
|
||||
| **Nacos** | http://localhost/nacos | 注册中心 |
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# Docker 环境
|
||||
make up # 启动所有服务
|
||||
make down # 停止所有服务
|
||||
make logs # 查看日志
|
||||
make ps # 查看服务状态
|
||||
make restart # 重启服务
|
||||
make clean # 清理所有数据
|
||||
|
||||
# 单独服务
|
||||
make logs-portal # 查看主应用日志
|
||||
make logs-gateway # 查看网关日志
|
||||
make restart-portal # 重启主应用
|
||||
make shell-portal # 进入容器
|
||||
make db # 连接数据库
|
||||
|
||||
# 前端开发
|
||||
pnpm dev # 启动所有应用
|
||||
pnpm build # 构建所有应用
|
||||
pnpm --filter portal dev # 启动单个应用
|
||||
pnpm --filter portal build # 构建单个应用
|
||||
```
|
||||
|
||||
## 文档索引
|
||||
|
||||
- **[前端完整指南](./docs/前端完整指南.md)** - ⭐ 架构、开发、部署全流程
|
||||
- **[数据库完整指南](./docs/数据库完整指南.md)** - ⭐ Schema、表结构、优化方案
|
||||
|
||||
## 核心亮点
|
||||
|
||||
### 1. 共享组件运行时加载
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@shared/components": "http://localhost/shared/components.js",
|
||||
"@shared/utils": "http://localhost/shared/utils.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// 浏览器自动从 URL 加载,无需打包!
|
||||
import { UlTable } from '@shared/components'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. Monorepo + Turborepo
|
||||
|
||||
- 统一依赖管理
|
||||
- 增量构建加速
|
||||
- 任务并行执行
|
||||
- 远程缓存
|
||||
|
||||
### 3. Docker 一键启动
|
||||
|
||||
- 所有服务容器化
|
||||
- Nginx 统一网关
|
||||
- 支持热更新(HMR)
|
||||
- 数据持久化
|
||||
|
||||
### 4. TypeScript 全栈
|
||||
|
||||
- 类型安全
|
||||
- 智能提示
|
||||
- 重构友好
|
||||
|
||||
## 环境要求
|
||||
|
||||
### Docker 环境(推荐)
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
|
||||
### 本地开发
|
||||
- Node.js 20+
|
||||
- pnpm 9+
|
||||
- Java 21+
|
||||
- Maven 3.9+
|
||||
- PostgreSQL 16+
|
||||
|
||||
## 开发规范
|
||||
|
||||
- **前端**:ESLint + Prettier + Husky
|
||||
- **提交规范**:Conventional Commits
|
||||
- **分支策略**:Git Flow
|
||||
- **代码审查**:必须 Code Review
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ by Taihao Team**
|
||||
263
docker-compose.dev.yml
Normal file
263
docker-compose.dev.yml
Normal file
@@ -0,0 +1,263 @@
|
||||
version: '3.8'
|
||||
|
||||
# 开发环境完整部署配置
|
||||
services:
|
||||
|
||||
# ================== 基础服务 ==================
|
||||
|
||||
# PostgreSQL 数据库
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: ul-postgres
|
||||
environment:
|
||||
POSTGRES_DB: urban_lifeline
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres123
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./urbanLifelineServ/.bin/database/postgres/sql:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- ul-network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Redis
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ul-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- ul-network
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
# Nacos 注册中心
|
||||
nacos:
|
||||
image: nacos/nacos-server:v2.3.0
|
||||
container_name: ul-nacos
|
||||
environment:
|
||||
MODE: standalone
|
||||
SPRING_DATASOURCE_PLATFORM: mysql
|
||||
PREFER_HOST_MODE: hostname
|
||||
JVM_XMS: 512m
|
||||
JVM_XMX: 512m
|
||||
JVM_XMN: 256m
|
||||
ports:
|
||||
- "8848:8848"
|
||||
- "9848:9848"
|
||||
volumes:
|
||||
- nacos_data:/home/nacos/data
|
||||
networks:
|
||||
- ul-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8848/nacos"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
# ================== 后端服务 ==================
|
||||
|
||||
# Gateway 网关服务
|
||||
gateway:
|
||||
build:
|
||||
context: ./urbanLifelineServ/gateway
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: ul-gateway
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: dev
|
||||
NACOS_SERVER_ADDR: nacos:8848
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_PORT: 5432
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./urbanLifelineServ/gateway:/app
|
||||
- maven_cache:/root/.m2
|
||||
networks:
|
||||
- ul-network
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
nacos:
|
||||
condition: service_healthy
|
||||
command: mvn spring-boot:run
|
||||
|
||||
# 认证服务
|
||||
auth-service:
|
||||
build:
|
||||
context: ./urbanLifelineServ/auth
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: ul-auth
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: dev
|
||||
NACOS_SERVER_ADDR: nacos:8848
|
||||
POSTGRES_HOST: postgres
|
||||
REDIS_HOST: redis
|
||||
volumes:
|
||||
- ./urbanLifelineServ/auth:/app
|
||||
- maven_cache:/root/.m2
|
||||
networks:
|
||||
- ul-network
|
||||
depends_on:
|
||||
- postgres
|
||||
- nacos
|
||||
|
||||
# 系统服务
|
||||
system-service:
|
||||
build:
|
||||
context: ./urbanLifelineServ/system
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: ul-system
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: dev
|
||||
NACOS_SERVER_ADDR: nacos:8848
|
||||
POSTGRES_HOST: postgres
|
||||
volumes:
|
||||
- ./urbanLifelineServ/system:/app
|
||||
- maven_cache:/root/.m2
|
||||
networks:
|
||||
- ul-network
|
||||
depends_on:
|
||||
- postgres
|
||||
- nacos
|
||||
|
||||
# ================== 前端服务 ==================
|
||||
|
||||
# 共享包服务(Module Federation Remote)
|
||||
shared:
|
||||
build:
|
||||
context: ./urbanLifelineWeb
|
||||
dockerfile: packages/shared/Dockerfile.dev
|
||||
container_name: ul-shared
|
||||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- ./urbanLifelineWeb/packages/shared:/app
|
||||
- /app/node_modules
|
||||
- pnpm_store:/root/.local/share/pnpm/store
|
||||
networks:
|
||||
- ul-network
|
||||
environment:
|
||||
- VITE_PORT=5000
|
||||
- CHOKIDAR_USEPOLLING=true # 支持 Docker 内文件监听
|
||||
command: pnpm dev
|
||||
|
||||
# 主应用(Portal)
|
||||
portal:
|
||||
build:
|
||||
context: ./urbanLifelineWeb
|
||||
dockerfile: packages/portal/Dockerfile.dev
|
||||
container_name: ul-portal
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./urbanLifelineWeb/packages/portal:/app
|
||||
- ./urbanLifelineWeb/packages/shared:/shared
|
||||
- /app/node_modules
|
||||
- pnpm_store:/root/.local/share/pnpm/store
|
||||
networks:
|
||||
- ul-network
|
||||
environment:
|
||||
- VITE_PORT=3000
|
||||
- VITE_API_BASE_URL=http://nginx/api
|
||||
- VITE_SHARED_REMOTE=http://nginx/shared
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
depends_on:
|
||||
- shared
|
||||
command: pnpm dev
|
||||
|
||||
# 招投标应用
|
||||
app-bidding:
|
||||
build:
|
||||
context: ./urbanLifelineWeb
|
||||
dockerfile: packages/app-bidding/Dockerfile.dev
|
||||
container_name: ul-app-bidding
|
||||
ports:
|
||||
- "3001:3001"
|
||||
volumes:
|
||||
- ./urbanLifelineWeb/packages/app-bidding:/app
|
||||
- ./urbanLifelineWeb/packages/shared:/shared
|
||||
- /app/node_modules
|
||||
- pnpm_store:/root/.local/share/pnpm/store
|
||||
networks:
|
||||
- ul-network
|
||||
environment:
|
||||
- VITE_PORT=3001
|
||||
- VITE_API_BASE_URL=http://nginx/api
|
||||
- VITE_SHARED_REMOTE=http://nginx/shared
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
depends_on:
|
||||
- shared
|
||||
command: pnpm dev
|
||||
|
||||
# 智能客服应用
|
||||
app-customer-service:
|
||||
build:
|
||||
context: ./urbanLifelineWeb
|
||||
dockerfile: packages/app-customer-service/Dockerfile.dev
|
||||
container_name: ul-app-cs
|
||||
ports:
|
||||
- "3002:3002"
|
||||
volumes:
|
||||
- ./urbanLifelineWeb/packages/app-customer-service:/app
|
||||
- ./urbanLifelineWeb/packages/shared:/shared
|
||||
- /app/node_modules
|
||||
- pnpm_store:/root/.local/share/pnpm/store
|
||||
networks:
|
||||
- ul-network
|
||||
environment:
|
||||
- VITE_PORT=3002
|
||||
- VITE_API_BASE_URL=http://nginx/api
|
||||
- VITE_SHARED_REMOTE=http://nginx/shared
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
depends_on:
|
||||
- shared
|
||||
command: pnpm dev
|
||||
|
||||
# ================== 统一网关 ==================
|
||||
|
||||
# Nginx 统一入口
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: ul-nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./docker/nginx/nginx.dev.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./docker/nginx/ssl:/etc/nginx/ssl:ro
|
||||
networks:
|
||||
- ul-network
|
||||
depends_on:
|
||||
- gateway
|
||||
- portal
|
||||
- app-bidding
|
||||
- app-customer-service
|
||||
- shared
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
networks:
|
||||
ul-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
nacos_data:
|
||||
maven_cache:
|
||||
pnpm_store:
|
||||
196
docker/nginx/conf.d/default.conf
Normal file
196
docker/nginx/conf.d/default.conf
Normal file
@@ -0,0 +1,196 @@
|
||||
# 开发环境统一入口配置
|
||||
|
||||
# 上游服务定义
|
||||
upstream gateway {
|
||||
server gateway:8080;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream portal {
|
||||
server portal:3000;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
upstream app-bidding {
|
||||
server app-bidding:3001;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
upstream app-customer-service {
|
||||
server app-customer-service:3002;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
upstream shared {
|
||||
server shared:5000;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
# WebSocket 升级配置
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
# 主服务器配置
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# 安全头
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# 开发环境允许所有跨域
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" always;
|
||||
|
||||
# 健康检查
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# ==================== 共享包服务(ES Module + Module Federation) ====================
|
||||
location /shared/ {
|
||||
proxy_pass http://shared:5000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
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;
|
||||
|
||||
# CORS(ES Module / Module Federation 必需)
|
||||
add_header Access-Control-Allow-Origin "*" always;
|
||||
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type" always;
|
||||
|
||||
# ES Module MIME 类型
|
||||
if ($request_filename ~* \.(js|mjs)$) {
|
||||
add_header Content-Type "application/javascript; charset=utf-8";
|
||||
}
|
||||
|
||||
# 开发环境不缓存
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
|
||||
# HMR 支持
|
||||
proxy_read_timeout 86400;
|
||||
proxy_send_timeout 86400;
|
||||
}
|
||||
|
||||
# ==================== API 网关代理 ====================
|
||||
location /api/ {
|
||||
proxy_pass http://gateway/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
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 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# WebSocket 代理
|
||||
location /ws/ {
|
||||
proxy_pass http://gateway/ws/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
# WebSocket 超时设置
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
}
|
||||
|
||||
# ==================== 主应用(Portal) ====================
|
||||
location / {
|
||||
proxy_pass http://portal/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
# Vite HMR 支持
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# ==================== 招投标应用 ====================
|
||||
location /bidding {
|
||||
rewrite ^/bidding/(.*)$ /$1 break;
|
||||
proxy_pass http://app-bidding/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
# Vite HMR 支持
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# 招投标应用静态资源
|
||||
location /bidding/ {
|
||||
proxy_pass http://app-bidding/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# ==================== 智能客服应用 ====================
|
||||
location /customer-service {
|
||||
rewrite ^/customer-service/(.*)$ /$1 break;
|
||||
proxy_pass http://app-customer-service/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
location /customer-service/ {
|
||||
proxy_pass http://app-customer-service/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# ==================== Nacos 管理界面(开发用) ====================
|
||||
location /nacos/ {
|
||||
proxy_pass http://nacos:8848/nacos/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
|
||||
# 可选:HTTPS 配置(开发环境使用自签名证书)
|
||||
# server {
|
||||
# listen 443 ssl http2;
|
||||
# server_name localhost;
|
||||
#
|
||||
# ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
# ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
# ssl_protocols TLSv1.2 TLSv1.3;
|
||||
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
#
|
||||
# # 其他配置同上...
|
||||
# }
|
||||
42
docker/nginx/nginx.dev.conf
Normal file
42
docker/nginx/nginx.dev.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/javascript application/json application/xml+rss;
|
||||
|
||||
# 上传大小限制
|
||||
client_max_body_size 100M;
|
||||
|
||||
# 包含具体配置
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
563
docs/前端完整指南.md
Normal file
563
docs/前端完整指南.md
Normal file
@@ -0,0 +1,563 @@
|
||||
# 泰豪电源 AI 数智化平台 - 前端完整指南
|
||||
|
||||
## 📖 目录
|
||||
|
||||
1. [技术架构](#1-技术架构)
|
||||
2. [共享组件方案](#2-共享组件方案)
|
||||
3. [快速开始](#3-快速开始)
|
||||
4. [开发指南](#4-开发指南)
|
||||
5. [构建部署](#5-构建部署)
|
||||
6. [常见问题](#6-常见问题)
|
||||
|
||||
---
|
||||
|
||||
## 1. 技术架构
|
||||
|
||||
### 1.1 技术栈
|
||||
|
||||
**前端框架**
|
||||
- Vue 3.5+ (`<script setup>`)
|
||||
- TypeScript 5.7+
|
||||
- Vite 6.0+
|
||||
- Pinia 2.2+
|
||||
- Element Plus 2.9+
|
||||
|
||||
**工程化**
|
||||
- pnpm 9.0+ Monorepo
|
||||
- Turborepo 2.0+ 构建加速
|
||||
- unplugin-auto-import 自动导入
|
||||
- ESLint 9 + Prettier
|
||||
|
||||
**通信层**
|
||||
- ofetch (替代 Axios)
|
||||
- @vueuse/core
|
||||
|
||||
### 1.2 项目结构
|
||||
|
||||
```
|
||||
urbanLifelineWeb/
|
||||
├── packages/
|
||||
│ ├── shared/ # 共享包 ⭐核心
|
||||
│ │ ├── components/ # UI组件
|
||||
│ │ ├── utils/ # 工具函数
|
||||
│ │ ├── api/ # API封装
|
||||
│ │ └── composables/ # 组合函数
|
||||
│ ├── portal/ # 主应用
|
||||
│ ├── app-bidding/ # 招投标应用
|
||||
│ ├── app-customer-service/ # 智能客服应用
|
||||
│ └── app-knowledge/ # 知识协同应用
|
||||
├── pnpm-workspace.yaml
|
||||
└── turbo.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 共享组件方案
|
||||
|
||||
### 2.1 核心理念
|
||||
|
||||
**业务应用只需关心 `@shared/*` 导入,无需关心底层依赖(Vue、Element Plus 等)**
|
||||
|
||||
```
|
||||
业务应用: import { UlTable } from '@shared/components'
|
||||
↓
|
||||
浏览器: GET /shared/components.js
|
||||
↓
|
||||
共享服务: 返回包含 Vue + Element Plus 的 ES Module
|
||||
↓
|
||||
✅ 所有应用共用,浏览器缓存
|
||||
```
|
||||
|
||||
### 2.2 配置方式
|
||||
|
||||
**业务应用配置(极简)**
|
||||
|
||||
```html
|
||||
<!-- index.html -->
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@shared/components": "/shared/components.js",
|
||||
"@shared/utils": "/shared/utils.js",
|
||||
"@shared/api": "/shared/api.js"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**Vue 组件使用**
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// ✅ 直接从 HTTP URL 加载
|
||||
import { UlTable } from '@shared/components'
|
||||
import { http } from '@shared/utils'
|
||||
import { authApi } from '@shared/api'
|
||||
import { useTable } from '@shared/composables'
|
||||
|
||||
const { loading, tableData } = useTable({
|
||||
fetchData: authApi.getUserList
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UlTable :data="tableData" :loading="loading" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 2.3 优势
|
||||
|
||||
| 特性 | 传统方式 | Import Maps 方案 |
|
||||
|------|---------|-----------------|
|
||||
| 代码共享 | ❌ 每个应用打包一份 | ✅ 所有应用共用一份 |
|
||||
| 构建体积 | ❌ 重复打包 | ✅ 减少 30-50% |
|
||||
| 依赖管理 | ❌ 每个应用配置 | ✅ 共享服务统一管理 |
|
||||
| 版本升级 | ❌ 所有应用改 | ✅ 只改共享服务 |
|
||||
| 浏览器缓存 | ⚠️ 独立缓存 | ✅ 统一缓存 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 快速开始
|
||||
|
||||
### 3.1 Docker 环境(推荐)
|
||||
|
||||
```bash
|
||||
# 1. 启动所有服务
|
||||
make up
|
||||
|
||||
# 2. 查看状态
|
||||
make ps
|
||||
|
||||
# 3. 访问应用
|
||||
open http://localhost
|
||||
```
|
||||
|
||||
**访问地址**
|
||||
- 主应用: http://localhost/
|
||||
- 招投标: http://localhost/bidding
|
||||
- 智能客服: http://localhost/customer-service
|
||||
- 共享组件: http://localhost/shared/components.js
|
||||
- API网关: http://localhost/api
|
||||
- Nacos: http://localhost/nacos
|
||||
|
||||
### 3.2 本地开发
|
||||
|
||||
```bash
|
||||
# 1. 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 2. 启动所有应用
|
||||
pnpm dev
|
||||
|
||||
# 或启动单个应用
|
||||
pnpm --filter portal dev
|
||||
pnpm --filter app-bidding dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 开发指南
|
||||
|
||||
### 4.1 创建页面
|
||||
|
||||
```vue
|
||||
<!-- packages/portal/src/views/UserList.vue -->
|
||||
<script setup lang="ts">
|
||||
import { UlTable } from '@shared/components'
|
||||
import { authApi } from '@shared/api'
|
||||
import { useTable } from '@shared/composables'
|
||||
|
||||
interface User {
|
||||
id: string
|
||||
username: string
|
||||
email: string
|
||||
}
|
||||
|
||||
const { loading, tableData, pagination, handlePageChange } = useTable<User>({
|
||||
fetchData: authApi.getUserList
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{ prop: 'username', label: '用户名', minWidth: 150 },
|
||||
{ prop: 'email', label: '邮箱', minWidth: 200 }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-list">
|
||||
<UlTable
|
||||
:data="tableData"
|
||||
:columns="columns"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
@page-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 4.2 API 调用
|
||||
|
||||
```typescript
|
||||
// 使用封装的 API
|
||||
import { authApi, systemApi } from '@shared/api'
|
||||
|
||||
// GET 请求
|
||||
const users = await authApi.getUserList({ page: 1, size: 10 })
|
||||
|
||||
// POST 请求
|
||||
await authApi.createUser({ username: 'test', email: 'test@example.com' })
|
||||
|
||||
// 直接使用 http
|
||||
import { http } from '@shared/utils'
|
||||
const data = await http.get('/custom/endpoint')
|
||||
```
|
||||
|
||||
### 4.3 状态管理
|
||||
|
||||
```typescript
|
||||
// store/user.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { authApi } from '@shared/api'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// State
|
||||
const userInfo = ref(null)
|
||||
const permissions = ref([])
|
||||
|
||||
// Getters
|
||||
const isLoggedIn = computed(() => !!userInfo.value)
|
||||
|
||||
// Actions
|
||||
const login = async (loginData) => {
|
||||
const res = await authApi.login(loginData)
|
||||
userInfo.value = res.userInfo
|
||||
permissions.value = res.permissions
|
||||
}
|
||||
|
||||
return { userInfo, permissions, isLoggedIn, login }
|
||||
})
|
||||
```
|
||||
|
||||
### 4.4 路由配置
|
||||
|
||||
```typescript
|
||||
// router/index.ts
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('@/layouts/MainLayout.vue'),
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
component: () => import('@/views/home/index.vue'),
|
||||
meta: { title: '首页' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
```
|
||||
|
||||
### 4.5 常用命令
|
||||
|
||||
```bash
|
||||
# 查看日志
|
||||
make logs-portal # 主应用日志
|
||||
make logs-gateway # 网关日志
|
||||
make logs-shared # 共享包日志
|
||||
|
||||
# 重启服务
|
||||
make restart-portal # 重启主应用
|
||||
make restart # 重启所有服务
|
||||
|
||||
# 进入容器
|
||||
make shell-portal # 进入容器调试
|
||||
|
||||
# 数据库
|
||||
make db # 连接数据库
|
||||
make db-init # 初始化数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 构建部署
|
||||
|
||||
### 5.1 本地构建
|
||||
|
||||
```bash
|
||||
# 构建所有应用
|
||||
pnpm build
|
||||
|
||||
# 构建单个应用
|
||||
pnpm --filter portal build
|
||||
pnpm --filter shared build
|
||||
|
||||
# 预览
|
||||
pnpm preview
|
||||
```
|
||||
|
||||
### 5.2 部署到生产
|
||||
|
||||
**方式1: Docker 部署**
|
||||
|
||||
```bash
|
||||
# 构建生产镜像
|
||||
docker build -t urban-lifeline-web .
|
||||
|
||||
# 运行
|
||||
docker run -p 80:80 urban-lifeline-web
|
||||
```
|
||||
|
||||
**方式2: CDN 部署**
|
||||
|
||||
```bash
|
||||
# 部署共享包到 CDN
|
||||
cd packages/shared
|
||||
pnpm build
|
||||
ossutil cp -r dist/esm/ oss://cdn/shared/v1.0.0/
|
||||
|
||||
# 部署业务应用
|
||||
cd packages/portal
|
||||
pnpm build
|
||||
ossutil cp -r dist/ oss://cdn/portal/
|
||||
```
|
||||
|
||||
**方式3: Nginx 静态部署**
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name taihao.com;
|
||||
|
||||
# 主应用
|
||||
location / {
|
||||
root /var/www/portal/dist;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 共享包
|
||||
location /shared/ {
|
||||
root /var/www/shared/dist;
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
# API 代理
|
||||
location /api/ {
|
||||
proxy_pass http://gateway:8080/;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 环境变量
|
||||
|
||||
```bash
|
||||
# .env.development
|
||||
VITE_API_BASE_URL=http://localhost/api
|
||||
VITE_SHARED_URL=http://localhost/shared
|
||||
|
||||
# .env.production
|
||||
VITE_API_BASE_URL=https://api.taihao.com/api
|
||||
VITE_SHARED_URL=https://cdn.taihao.com/shared/v1.0.0
|
||||
```
|
||||
|
||||
### 5.4 CI/CD
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Build
|
||||
run: pnpm install && pnpm build
|
||||
|
||||
- name: Deploy
|
||||
run: ./scripts/deploy-production.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 常见问题
|
||||
|
||||
### 6.1 为什么使用 Import Maps?
|
||||
|
||||
**优势**:
|
||||
- ✅ 浏览器原生支持,无需额外库
|
||||
- ✅ 真正的运行时共享
|
||||
- ✅ 开发体验好(支持 HMR)
|
||||
- ✅ 减小构建体积
|
||||
|
||||
**对比 Module Federation**:
|
||||
- Import Maps 更简单,配置少
|
||||
- Module Federation 功能更强大,但复杂
|
||||
- 两者可以结合使用
|
||||
|
||||
### 6.2 如何处理 TypeScript 类型?
|
||||
|
||||
```typescript
|
||||
// packages/portal/src/types/shared.d.ts
|
||||
declare module '@shared/components' {
|
||||
export * from '../../../shared/src/components'
|
||||
}
|
||||
|
||||
declare module '@shared/utils' {
|
||||
export * from '../../../shared/src/utils'
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 如何更新共享组件?
|
||||
|
||||
```bash
|
||||
# 1. 修改共享组件代码
|
||||
vim packages/shared/src/components/UlTable/index.vue
|
||||
|
||||
# 2. 重启共享服务(HMR 自动生效)
|
||||
make restart-shared
|
||||
|
||||
# 3. 浏览器刷新,所有应用自动获得最新版本
|
||||
```
|
||||
|
||||
### 6.4 生产环境如何缓存?
|
||||
|
||||
```nginx
|
||||
# Nginx 配置
|
||||
location /shared/ {
|
||||
# 基于版本号的长期缓存
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# HTML 不缓存
|
||||
location ~* \.html$ {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 如何调试共享组件?
|
||||
|
||||
```bash
|
||||
# 方式1: 查看网络请求
|
||||
浏览器 F12 → Network → 筛选 JS → 查看 /shared/components.js
|
||||
|
||||
# 方式2: 查看日志
|
||||
make logs-shared
|
||||
|
||||
# 方式3: 进入容器
|
||||
make shell-shared
|
||||
```
|
||||
|
||||
### 6.6 为什么不用 Webpack?
|
||||
|
||||
Vite 优势:
|
||||
- ⚡ 开发启动快(秒级)
|
||||
- 🔥 HMR 更快
|
||||
- 📦 生产构建基于 Rollup(体积更小)
|
||||
- 🎯 原生 ES Module 支持
|
||||
|
||||
### 6.7 如何处理样式?
|
||||
|
||||
```vue
|
||||
<!-- 组件级样式 -->
|
||||
<style scoped>
|
||||
.ul-table {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 全局样式 -->
|
||||
<style>
|
||||
@import '@shared/styles/variables.scss';
|
||||
</style>
|
||||
```
|
||||
|
||||
共享包会自动处理 CSS 提取和分割。
|
||||
|
||||
### 6.8 如何添加新的业务应用?
|
||||
|
||||
```bash
|
||||
# 1. 复制现有应用作为模板
|
||||
cp -r packages/portal packages/app-newapp
|
||||
|
||||
# 2. 修改 package.json
|
||||
{
|
||||
"name": "@apps/newapp",
|
||||
"scripts": {
|
||||
"dev": "vite --port 3003"
|
||||
}
|
||||
}
|
||||
|
||||
# 3. 添加到 pnpm-workspace.yaml(已自动包含)
|
||||
|
||||
# 4. 启动
|
||||
pnpm --filter app-newapp dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### A. 常用脚本
|
||||
|
||||
```bash
|
||||
# Makefile 命令
|
||||
make up # 启动
|
||||
make down # 停止
|
||||
make logs # 日志
|
||||
make ps # 状态
|
||||
make restart # 重启
|
||||
make clean # 清理
|
||||
|
||||
# pnpm 命令
|
||||
pnpm dev # 开发
|
||||
pnpm build # 构建
|
||||
pnpm preview # 预览
|
||||
pnpm lint # 检查
|
||||
pnpm format # 格式化
|
||||
```
|
||||
|
||||
### B. 目录说明
|
||||
|
||||
```
|
||||
urbanLifeline/
|
||||
├── urbanLifelineServ/ # 后端(Java Spring Boot)
|
||||
├── urbanLifelineWeb/ # 前端(Vue 3 Monorepo)
|
||||
├── docker-compose.dev.yml # Docker 开发环境
|
||||
├── Makefile # 快捷命令
|
||||
└── docs/ # 文档
|
||||
└── 前端完整指南.md # 📖 本文档
|
||||
```
|
||||
|
||||
### C. 技术支持
|
||||
|
||||
- 项目文档:`/docs`
|
||||
- 问题反馈:GitHub Issues
|
||||
- 开发规范:ESLint + Prettier
|
||||
- 提交规范:Conventional Commits
|
||||
|
||||
---
|
||||
|
||||
**Happy Coding! 🚀**
|
||||
|
||||
*最后更新:2025-12-02*
|
||||
774
docs/数据库完整指南.md
Normal file
774
docs/数据库完整指南.md
Normal file
@@ -0,0 +1,774 @@
|
||||
# 泰豪电源 AI 数智化平台 - 数据库完整指南
|
||||
|
||||
> **更新日期**: 2025-12-02
|
||||
> **数据库**: PostgreSQL 16
|
||||
> **总表数**: 50张核心业务表
|
||||
|
||||
---
|
||||
|
||||
## 📖 目录
|
||||
|
||||
1. [系统概述](#1-系统概述)
|
||||
2. [Schema架构](#2-schema架构)
|
||||
3. [核心模块设计](#3-核心模块设计)
|
||||
4. [表结构速查](#4-表结构速查)
|
||||
5. [优化方案](#5-优化方案)
|
||||
6. [部署与维护](#6-部署与维护)
|
||||
7. [常用查询示例](#7-常用查询示例)
|
||||
|
||||
---
|
||||
|
||||
## 1. 系统概述
|
||||
|
||||
### 1.1 设计理念
|
||||
|
||||
基于`功能结构.xml`的系统架构,遵循 **"一个底座、多种智能体"** 核心理念,支持四大业务模块:
|
||||
|
||||
1. **资料管理智能化**
|
||||
2. **招投标自动化**
|
||||
3. **售后客服智能化**
|
||||
4. **企业内部知识协同**
|
||||
|
||||
### 1.2 技术选型
|
||||
|
||||
- **数据库**: PostgreSQL 16
|
||||
- **连接池**: HikariCP
|
||||
- **ORM**: MyBatis-Plus 3.5
|
||||
- **迁移工具**: Flyway (可选)
|
||||
|
||||
### 1.3 设计原则
|
||||
|
||||
- ✅ **模块化**: 按业务模块划分 Schema
|
||||
- ✅ **规范化**: 统一命名规范和字段设计
|
||||
- ✅ **可扩展**: 预留扩展字段和软删除
|
||||
- ✅ **高性能**: 合理索引和分区设计
|
||||
- ✅ **安全性**: 行级安全和审计日志
|
||||
|
||||
---
|
||||
|
||||
## 2. Schema架构
|
||||
|
||||
### 2.1 Schema划分
|
||||
|
||||
采用多Schema架构,按业务模块逻辑隔离:
|
||||
|
||||
| Schema | 说明 | 核心表数量 | 用途 |
|
||||
|--------|------|-----------|------|
|
||||
| `sys` | 系统基础模块 | 11 | 用户、角色、权限、部门 |
|
||||
| `file` | 文件管理模块 | 1 | 文件存储与管理 |
|
||||
| `message` | 消息通知模块 | 4 | 站内信、系统通知 |
|
||||
| `log` | 日志审计模块 | 1 | 操作日志、审计 |
|
||||
| `config` | 系统配置模块 | 1 | 系统参数配置 |
|
||||
| `knowledge` | 知识库管理模块 | 4 | 文档、分段、问答对 |
|
||||
| `bidding` | 招投标智能体 | 8 | 招投标业务流程 |
|
||||
| `customer_service` | 智能客服系统 | 9 | 客服、工单、对话 |
|
||||
| `agent` | 智能体管理 | 11 | 智能体、API、监控 |
|
||||
|
||||
**总计: 50张核心业务表**
|
||||
|
||||
### 2.2 命名规范
|
||||
|
||||
```sql
|
||||
-- Schema 命名: 小写字母
|
||||
CREATE SCHEMA IF NOT EXISTS sys;
|
||||
|
||||
-- 表命名: tb_{schema}_{表名}
|
||||
CREATE TABLE sys.tb_sys_user (...);
|
||||
CREATE TABLE knowledge.tb_knowledge_document (...);
|
||||
|
||||
-- 字段命名: 小写字母 + 下划线
|
||||
user_id, create_time, full_name
|
||||
|
||||
-- 索引命名: idx_{表名}_{字段名}
|
||||
CREATE INDEX idx_user_email ON sys.tb_sys_user(email);
|
||||
|
||||
-- 外键命名: fk_{表名}_{关联表名}
|
||||
CONSTRAINT fk_user_dept FOREIGN KEY (dept_id) ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心模块设计
|
||||
|
||||
### 3.1 系统基础模块 (sys)
|
||||
|
||||
#### 权限体系设计
|
||||
|
||||
采用 **RBAC (基于角色的访问控制) + ACL (访问控制列表)** 混合模型
|
||||
|
||||
**核心表**:
|
||||
- `tb_sys_user` - 用户表
|
||||
- `tb_sys_role` - 角色表
|
||||
- `tb_sys_permission` - 权限表
|
||||
- `tb_sys_dept` - 部门表
|
||||
- `tb_sys_acl` - 对象级权限表
|
||||
- `tb_sys_user_role` - 用户角色关联表
|
||||
|
||||
**权限模型**:
|
||||
```
|
||||
用户 (User)
|
||||
├─ 部门 (Dept) - 数据隔离
|
||||
├─ 角色 (Role)
|
||||
│ ├─ 权限 (Permission) - 功能权限
|
||||
│ └─ 视图 (View) - 菜单权限
|
||||
└─ ACL - 对象级权限(细粒度)
|
||||
```
|
||||
|
||||
**设计亮点**:
|
||||
1. 多租户支持: `dept_path` 字段实现部门级数据隔离
|
||||
2. 角色作用域: `scope` 字段区分全局/部门角色
|
||||
3. 对象权限: ACL表支持任意对象的细粒度权限
|
||||
|
||||
#### 核心表结构
|
||||
|
||||
```sql
|
||||
-- 用户表
|
||||
CREATE TABLE sys.tb_sys_user (
|
||||
user_id VARCHAR(50) PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(100) UNIQUE,
|
||||
phone VARCHAR(20),
|
||||
wechat_id VARCHAR(100),
|
||||
status VARCHAR(20) DEFAULT 'active',
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- 部门表(树形结构)
|
||||
CREATE TABLE sys.tb_sys_dept (
|
||||
dept_id VARCHAR(50) PRIMARY KEY,
|
||||
dept_name VARCHAR(100) NOT NULL,
|
||||
parent_id VARCHAR(50),
|
||||
dept_path TEXT, -- 路径:/1/2/3/
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false,
|
||||
CONSTRAINT fk_dept_parent FOREIGN KEY (parent_id)
|
||||
REFERENCES sys.tb_sys_dept(dept_id)
|
||||
);
|
||||
|
||||
-- 角色表
|
||||
CREATE TABLE sys.tb_sys_role (
|
||||
role_id VARCHAR(50) PRIMARY KEY,
|
||||
role_name VARCHAR(100) NOT NULL,
|
||||
role_code VARCHAR(50) UNIQUE NOT NULL,
|
||||
scope VARCHAR(20) DEFAULT 'global', -- global/dept
|
||||
owner_dept_id VARCHAR(50),
|
||||
description TEXT,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- ACL权限表
|
||||
CREATE TABLE sys.tb_sys_acl (
|
||||
acl_id VARCHAR(50) PRIMARY KEY,
|
||||
object_type VARCHAR(50) NOT NULL, -- user/dept/document等
|
||||
object_id VARCHAR(50) NOT NULL,
|
||||
principal_type VARCHAR(20) NOT NULL, -- user/role/dept
|
||||
principal_id VARCHAR(50) NOT NULL,
|
||||
permission VARCHAR(50) NOT NULL, -- view/edit/delete/admin
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_user_status ON sys.tb_sys_user(status) WHERE deleted = false;
|
||||
CREATE INDEX idx_dept_path ON sys.tb_sys_dept USING GIN(dept_path gin_trgm_ops);
|
||||
CREATE INDEX idx_acl_object ON sys.tb_sys_acl(object_type, object_id);
|
||||
```
|
||||
|
||||
### 3.2 知识库管理模块 (knowledge)
|
||||
|
||||
#### 模块概述
|
||||
|
||||
支持文档管理、向量检索、RAG问答,版本控制。
|
||||
|
||||
**核心表**:
|
||||
- `tb_knowledge_document` - 文档主表
|
||||
- `tb_knowledge_chunk` - 文档分段表(向量检索)
|
||||
- `tb_knowledge_qa_pair` - 问答对表
|
||||
- `tb_knowledge_file_relation` - 文档文件关联表
|
||||
|
||||
#### 版本管理设计
|
||||
|
||||
采用 **简化版本管理** 方案:
|
||||
|
||||
```sql
|
||||
-- 文档表(新增版本字段)
|
||||
CREATE TABLE knowledge.tb_knowledge_document (
|
||||
doc_id VARCHAR(50) PRIMARY KEY,
|
||||
root_doc_id VARCHAR(50), -- ✨ 根文档ID(版本组标识)
|
||||
version INTEGER DEFAULT 1, -- ✨ 版本号
|
||||
is_current BOOLEAN DEFAULT true, -- ✨ 是否当前版本
|
||||
title VARCHAR(500) NOT NULL,
|
||||
content TEXT,
|
||||
knowledge_base_id VARCHAR(50),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- 分段表(向量检索)
|
||||
CREATE TABLE knowledge.tb_knowledge_chunk (
|
||||
chunk_id VARCHAR(50) PRIMARY KEY,
|
||||
doc_id VARCHAR(50) NOT NULL,
|
||||
chunk_index INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
embedding VECTOR(1536), -- ✨ 向量字段(pgvector扩展)
|
||||
version INTEGER DEFAULT 1, -- ✨ 乐观锁版本
|
||||
tokens INTEGER,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_chunk_doc FOREIGN KEY (doc_id)
|
||||
REFERENCES knowledge.tb_knowledge_document(doc_id)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_doc_root_current
|
||||
ON knowledge.tb_knowledge_document(root_doc_id, is_current)
|
||||
WHERE deleted = false;
|
||||
|
||||
CREATE INDEX idx_chunk_embedding
|
||||
ON knowledge.tb_knowledge_chunk
|
||||
USING ivfflat (embedding vector_cosine_ops) -- ✨ 向量索引
|
||||
WITH (lists = 100);
|
||||
```
|
||||
|
||||
**版本管理示例**:
|
||||
|
||||
```sql
|
||||
-- 创建新版本
|
||||
BEGIN;
|
||||
|
||||
-- 1. 标记旧版本为非当前
|
||||
UPDATE knowledge.tb_knowledge_document
|
||||
SET is_current = false
|
||||
WHERE root_doc_id = 'root_xxx';
|
||||
|
||||
-- 2. 插入新版本
|
||||
INSERT INTO knowledge.tb_knowledge_document (
|
||||
doc_id, root_doc_id, version, is_current, title, content
|
||||
) VALUES (
|
||||
'new_doc_id', 'root_xxx', 2, true, '新版本标题', '内容'
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 查询当前版本
|
||||
SELECT * FROM knowledge.tb_knowledge_document
|
||||
WHERE root_doc_id = 'root_xxx' AND is_current = true;
|
||||
|
||||
-- 查询所有版本
|
||||
SELECT version, title, create_time
|
||||
FROM knowledge.tb_knowledge_document
|
||||
WHERE root_doc_id = 'root_xxx'
|
||||
ORDER BY version DESC;
|
||||
```
|
||||
|
||||
### 3.3 招投标智能体模块 (bidding)
|
||||
|
||||
#### 核心表
|
||||
|
||||
```sql
|
||||
-- 招标项目表
|
||||
CREATE TABLE bidding.tb_bidding_project (
|
||||
project_id VARCHAR(50) PRIMARY KEY,
|
||||
project_name VARCHAR(500) NOT NULL,
|
||||
project_code VARCHAR(100),
|
||||
bidding_org VARCHAR(200), -- 招标单位
|
||||
project_type VARCHAR(50), -- 项目类型
|
||||
status VARCHAR(50) DEFAULT 'draft',
|
||||
budget DECIMAL(18,2),
|
||||
bid_deadline TIMESTAMP,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- 招标文件表
|
||||
CREATE TABLE bidding.tb_bidding_document (
|
||||
doc_id VARCHAR(50) PRIMARY KEY,
|
||||
project_id VARCHAR(50) NOT NULL,
|
||||
doc_type VARCHAR(50), -- tender/technical/commercial
|
||||
file_id VARCHAR(50),
|
||||
parsed_content JSONB, -- ✨ 智能解析结果
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_bdoc_project FOREIGN KEY (project_id)
|
||||
REFERENCES bidding.tb_bidding_project(project_id)
|
||||
);
|
||||
|
||||
-- 标书模板表
|
||||
CREATE TABLE bidding.tb_bidding_template (
|
||||
template_id VARCHAR(50) PRIMARY KEY,
|
||||
template_name VARCHAR(200) NOT NULL,
|
||||
template_type VARCHAR(50),
|
||||
content JSONB, -- 模板结构化内容
|
||||
variables JSONB, -- 可替换变量
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 3.4 智能客服系统模块 (customer_service)
|
||||
|
||||
#### 核心表
|
||||
|
||||
```sql
|
||||
-- 对话会话表
|
||||
CREATE TABLE customer_service.tb_cs_conversation (
|
||||
conv_id VARCHAR(50) PRIMARY KEY,
|
||||
customer_user_id VARCHAR(50),
|
||||
customer_name VARCHAR(100),
|
||||
channel VARCHAR(50), -- wechat/web/phone
|
||||
source VARCHAR(50), -- miniprogram/h5/app
|
||||
status VARCHAR(50) DEFAULT 'active',
|
||||
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
end_time TIMESTAMP,
|
||||
satisfaction_score INTEGER -- 满意度评分
|
||||
);
|
||||
|
||||
-- 对话消息表
|
||||
CREATE TABLE customer_service.tb_cs_message (
|
||||
message_id VARCHAR(50) PRIMARY KEY,
|
||||
conv_id VARCHAR(50) NOT NULL,
|
||||
sender_type VARCHAR(20), -- customer/agent/bot
|
||||
sender_id VARCHAR(50),
|
||||
content TEXT,
|
||||
message_type VARCHAR(50), -- text/image/file
|
||||
ai_response JSONB, -- AI响应详情
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_msg_conv FOREIGN KEY (conv_id)
|
||||
REFERENCES customer_service.tb_cs_conversation(conv_id)
|
||||
);
|
||||
|
||||
-- 工单表
|
||||
CREATE TABLE customer_service.tb_cs_work_order (
|
||||
order_id VARCHAR(50) PRIMARY KEY,
|
||||
order_code VARCHAR(100) UNIQUE NOT NULL,
|
||||
conv_id VARCHAR(50),
|
||||
customer_user_id VARCHAR(50),
|
||||
title VARCHAR(500) NOT NULL,
|
||||
description TEXT,
|
||||
category VARCHAR(100),
|
||||
priority VARCHAR(20) DEFAULT 'medium',
|
||||
status VARCHAR(50) DEFAULT 'pending',
|
||||
assigned_to VARCHAR(50),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
resolve_time TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 3.5 智能体管理模块 (agent)
|
||||
|
||||
#### 核心表
|
||||
|
||||
```sql
|
||||
-- 智能体定义表
|
||||
CREATE TABLE agent.tb_agent_definition (
|
||||
agent_id VARCHAR(50) PRIMARY KEY,
|
||||
agent_name VARCHAR(100) NOT NULL,
|
||||
agent_type VARCHAR(50), -- bidding/cs/knowledge等
|
||||
description TEXT,
|
||||
config JSONB, -- 配置(模型、参数等)
|
||||
status VARCHAR(20) DEFAULT 'active',
|
||||
version VARCHAR(20),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- API调用日志表
|
||||
CREATE TABLE agent.tb_agent_api_log (
|
||||
log_id VARCHAR(50) PRIMARY KEY,
|
||||
agent_id VARCHAR(50),
|
||||
api_endpoint VARCHAR(200),
|
||||
request_params JSONB,
|
||||
response_data JSONB,
|
||||
status_code INTEGER,
|
||||
duration_ms INTEGER,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 智能体监控表(按月分区)
|
||||
CREATE TABLE agent.tb_agent_monitor (
|
||||
monitor_id VARCHAR(50) NOT NULL,
|
||||
agent_id VARCHAR(50) NOT NULL,
|
||||
metric_name VARCHAR(100),
|
||||
metric_value NUMERIC,
|
||||
timestamp TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (monitor_id, timestamp)
|
||||
) PARTITION BY RANGE (timestamp);
|
||||
|
||||
-- 创建分区
|
||||
CREATE TABLE agent.tb_agent_monitor_2025_12
|
||||
PARTITION OF agent.tb_agent_monitor
|
||||
FOR VALUES FROM ('2025-12-01') TO ('2026-01-01');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 表结构速查
|
||||
|
||||
### 4.1 系统基础模块 (sys)
|
||||
|
||||
| 表名 | 主键 | 核心字段 | 说明 |
|
||||
|------|------|----------|------|
|
||||
| `tb_sys_user` | user_id | username, email, phone | 用户表 |
|
||||
| `tb_sys_user_info` | user_id | avatar, full_name, level | 用户信息表 |
|
||||
| `tb_sys_dept` | dept_id | name, parent_id, dept_path | 部门表 |
|
||||
| `tb_sys_role` | role_id | name, scope, owner_dept_id | 角色表 |
|
||||
| `tb_sys_permission` | permission_id | name, code, module_id | 权限表 |
|
||||
| `tb_sys_acl` | acl_id | object_type, principal_type | 对象权限表 |
|
||||
|
||||
### 4.2 知识库管理 (knowledge)
|
||||
|
||||
| 表名 | 主键 | 核心字段 | 说明 |
|
||||
|------|------|----------|------|
|
||||
| `tb_knowledge_document` | doc_id | title, root_doc_id, version | 文档表 |
|
||||
| `tb_knowledge_chunk` | chunk_id | doc_id, content, embedding | 分段表 |
|
||||
| `tb_knowledge_qa_pair` | qa_pair_id | question, answer | 问答对表 |
|
||||
|
||||
### 4.3 招投标 (bidding)
|
||||
|
||||
| 表名 | 主键 | 核心字段 | 说明 |
|
||||
|------|------|----------|------|
|
||||
| `tb_bidding_project` | project_id | project_name, status | 招标项目表 |
|
||||
| `tb_bidding_document` | doc_id | project_id, parsed_content | 招标文件表 |
|
||||
| `tb_bidding_template` | template_id | template_name, content | 标书模板表 |
|
||||
|
||||
### 4.4 智能客服 (customer_service)
|
||||
|
||||
| 表名 | 主键 | 核心字段 | 说明 |
|
||||
|------|------|----------|------|
|
||||
| `tb_cs_conversation` | conv_id | customer_user_id, status | 对话会话表 |
|
||||
| `tb_cs_message` | message_id | conv_id, content | 对话消息表 |
|
||||
| `tb_cs_work_order` | order_id | title, status, assigned_to | 工单表 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 优化方案
|
||||
|
||||
### 5.1 索引优化
|
||||
|
||||
```sql
|
||||
-- 1. 复合索引(状态 + 时间查询)
|
||||
CREATE INDEX idx_project_status_time
|
||||
ON bidding.tb_bidding_project(status, create_time DESC)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- 2. 部分索引(只索引活跃数据)
|
||||
CREATE INDEX idx_user_active
|
||||
ON sys.tb_sys_user(user_id)
|
||||
WHERE status = 'active' AND deleted = false;
|
||||
|
||||
-- 3. GIN索引(全文检索)
|
||||
CREATE INDEX idx_doc_content_gin
|
||||
ON knowledge.tb_knowledge_document
|
||||
USING GIN(to_tsvector('chinese', title || ' ' || content));
|
||||
|
||||
-- 4. BRIN索引(时间序列)
|
||||
CREATE INDEX idx_log_time_brin
|
||||
ON log.tb_operation_log
|
||||
USING BRIN(create_time);
|
||||
```
|
||||
|
||||
### 5.2 分区策略
|
||||
|
||||
```sql
|
||||
-- 按月分区(监控数据)
|
||||
CREATE TABLE agent.tb_agent_monitor (
|
||||
monitor_id VARCHAR(50) NOT NULL,
|
||||
timestamp TIMESTAMP NOT NULL,
|
||||
...
|
||||
PRIMARY KEY (monitor_id, timestamp)
|
||||
) PARTITION BY RANGE (timestamp);
|
||||
|
||||
-- 自动创建分区脚本
|
||||
CREATE OR REPLACE FUNCTION create_monthly_partition()
|
||||
RETURNS void AS $$
|
||||
DECLARE
|
||||
start_date DATE;
|
||||
end_date DATE;
|
||||
partition_name TEXT;
|
||||
BEGIN
|
||||
start_date := DATE_TRUNC('month', CURRENT_DATE + INTERVAL '1 month');
|
||||
end_date := start_date + INTERVAL '1 month';
|
||||
partition_name := 'tb_agent_monitor_' || TO_CHAR(start_date, 'YYYY_MM');
|
||||
|
||||
EXECUTE format(
|
||||
'CREATE TABLE IF NOT EXISTS agent.%I PARTITION OF agent.tb_agent_monitor
|
||||
FOR VALUES FROM (%L) TO (%L)',
|
||||
partition_name, start_date, end_date
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
```
|
||||
|
||||
### 5.3 查询优化
|
||||
|
||||
```sql
|
||||
-- 使用CTE优化复杂查询
|
||||
WITH user_roles AS (
|
||||
SELECT ur.user_id, r.role_id, r.role_code
|
||||
FROM sys.tb_sys_user_role ur
|
||||
JOIN sys.tb_sys_role r ON ur.role_id = r.role_id
|
||||
WHERE r.deleted = false
|
||||
),
|
||||
user_permissions AS (
|
||||
SELECT ur.user_id, p.permission_code
|
||||
FROM user_roles ur
|
||||
JOIN sys.tb_sys_role_permission rp ON ur.role_id = rp.role_id
|
||||
JOIN sys.tb_sys_permission p ON rp.permission_id = p.permission_id
|
||||
)
|
||||
SELECT u.username, array_agg(DISTINCT up.permission_code) as permissions
|
||||
FROM sys.tb_sys_user u
|
||||
JOIN user_permissions up ON u.user_id = up.user_id
|
||||
WHERE u.deleted = false
|
||||
GROUP BY u.user_id, u.username;
|
||||
```
|
||||
|
||||
### 5.4 并发控制
|
||||
|
||||
```sql
|
||||
-- 乐观锁(版本号)
|
||||
UPDATE knowledge.tb_knowledge_chunk
|
||||
SET content = '新内容',
|
||||
version = version + 1
|
||||
WHERE chunk_id = 'xxx'
|
||||
AND version = 1; -- 版本匹配才更新
|
||||
|
||||
-- 悲观锁
|
||||
BEGIN;
|
||||
SELECT * FROM bidding.tb_bidding_project
|
||||
WHERE project_id = 'xxx'
|
||||
FOR UPDATE; -- 锁定记录
|
||||
|
||||
-- 更新...
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 部署与维护
|
||||
|
||||
### 6.1 初始化脚本
|
||||
|
||||
```bash
|
||||
# 位置: urbanLifelineServ/.bin/database/postgres/sql/
|
||||
|
||||
# 完整初始化
|
||||
psql -U postgres -d urban_lifeline -f createTableAll.sql
|
||||
|
||||
# 分模块初始化
|
||||
psql -U postgres -d urban_lifeline -f createTablePermission.sql
|
||||
psql -U postgres -d urban_lifeline -f createTableKnowledge.sql
|
||||
psql -U postgres -d urban_lifeline -f createTableBidding.sql
|
||||
|
||||
# 优化补丁
|
||||
psql -U postgres -d urban_lifeline -f optimizations.sql
|
||||
```
|
||||
|
||||
### 6.2 备份策略
|
||||
|
||||
```bash
|
||||
# 全量备份
|
||||
pg_dump -U postgres -d urban_lifeline -F c -f backup_$(date +%Y%m%d).dump
|
||||
|
||||
# 仅备份 Schema
|
||||
pg_dump -U postgres -d urban_lifeline -s -f schema_backup.sql
|
||||
|
||||
# 仅备份数据
|
||||
pg_dump -U postgres -d urban_lifeline -a -f data_backup.sql
|
||||
|
||||
# 还原
|
||||
pg_restore -U postgres -d urban_lifeline backup_20251202.dump
|
||||
```
|
||||
|
||||
### 6.3 监控指标
|
||||
|
||||
```sql
|
||||
-- 表大小
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
|
||||
FROM pg_tables
|
||||
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
|
||||
|
||||
-- 索引使用情况
|
||||
SELECT
|
||||
schemaname, tablename, indexname,
|
||||
idx_scan as index_scans,
|
||||
idx_tup_read as tuples_read
|
||||
FROM pg_stat_user_indexes
|
||||
WHERE idx_scan = 0
|
||||
ORDER BY schemaname, tablename;
|
||||
|
||||
-- 慢查询
|
||||
SELECT
|
||||
query,
|
||||
calls,
|
||||
total_time,
|
||||
mean_time,
|
||||
max_time
|
||||
FROM pg_stat_statements
|
||||
WHERE mean_time > 1000 -- 超过1秒
|
||||
ORDER BY mean_time DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 常用查询示例
|
||||
|
||||
### 7.1 用户权限查询
|
||||
|
||||
```sql
|
||||
-- 查询用户的所有权限
|
||||
SELECT DISTINCT p.permission_code, p.permission_name
|
||||
FROM sys.tb_sys_user u
|
||||
JOIN sys.tb_sys_user_role ur ON u.user_id = ur.user_id
|
||||
JOIN sys.tb_sys_role_permission rp ON ur.role_id = rp.role_id
|
||||
JOIN sys.tb_sys_permission p ON rp.permission_id = p.permission_id
|
||||
WHERE u.username = 'admin'
|
||||
AND u.deleted = false;
|
||||
|
||||
-- 查询部门下所有用户
|
||||
WITH RECURSIVE dept_tree AS (
|
||||
SELECT dept_id FROM sys.tb_sys_dept WHERE dept_id = 'target_dept_id'
|
||||
UNION ALL
|
||||
SELECT d.dept_id
|
||||
FROM sys.tb_sys_dept d
|
||||
JOIN dept_tree dt ON d.parent_id = dt.dept_id
|
||||
)
|
||||
SELECT u.*
|
||||
FROM sys.tb_sys_user u
|
||||
JOIN sys.tb_sys_user_dept ud ON u.user_id = ud.user_id
|
||||
WHERE ud.dept_id IN (SELECT dept_id FROM dept_tree);
|
||||
```
|
||||
|
||||
### 7.2 知识库查询
|
||||
|
||||
```sql
|
||||
-- 向量相似度检索(Top 5)
|
||||
SELECT
|
||||
chunk_id,
|
||||
content,
|
||||
1 - (embedding <=> '[0.1, 0.2, ...]'::vector) as similarity
|
||||
FROM knowledge.tb_knowledge_chunk
|
||||
WHERE deleted = false
|
||||
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
|
||||
LIMIT 5;
|
||||
|
||||
-- 查询文档的所有版本
|
||||
SELECT
|
||||
version,
|
||||
title,
|
||||
create_time,
|
||||
is_current
|
||||
FROM knowledge.tb_knowledge_document
|
||||
WHERE root_doc_id = 'root_xxx'
|
||||
ORDER BY version DESC;
|
||||
```
|
||||
|
||||
### 7.3 招投标查询
|
||||
|
||||
```sql
|
||||
-- 统计项目状态分布
|
||||
SELECT
|
||||
status,
|
||||
COUNT(*) as count,
|
||||
SUM(budget) as total_budget
|
||||
FROM bidding.tb_bidding_project
|
||||
WHERE deleted = false
|
||||
GROUP BY status;
|
||||
|
||||
-- 查询即将截止的项目
|
||||
SELECT
|
||||
project_name,
|
||||
bid_deadline,
|
||||
EXTRACT(DAY FROM (bid_deadline - NOW())) as days_left
|
||||
FROM bidding.tb_bidding_project
|
||||
WHERE status = 'active'
|
||||
AND bid_deadline > NOW()
|
||||
AND deleted = false
|
||||
ORDER BY bid_deadline ASC;
|
||||
```
|
||||
|
||||
### 7.4 智能客服查询
|
||||
|
||||
```sql
|
||||
-- 查询工单处理效率
|
||||
SELECT
|
||||
assigned_to,
|
||||
COUNT(*) as total_orders,
|
||||
AVG(EXTRACT(EPOCH FROM (resolve_time - create_time))/3600) as avg_hours,
|
||||
COUNT(CASE WHEN status = 'resolved' THEN 1 END) as resolved_count
|
||||
FROM customer_service.tb_cs_work_order
|
||||
WHERE create_time > NOW() - INTERVAL '30 days'
|
||||
GROUP BY assigned_to;
|
||||
|
||||
-- 查询满意度统计
|
||||
SELECT
|
||||
DATE(start_time) as date,
|
||||
AVG(satisfaction_score) as avg_satisfaction,
|
||||
COUNT(*) as total_conversations
|
||||
FROM customer_service.tb_cs_conversation
|
||||
WHERE satisfaction_score IS NOT NULL
|
||||
AND start_time > NOW() - INTERVAL '7 days'
|
||||
GROUP BY DATE(start_time)
|
||||
ORDER BY date DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### A. SQL文件清单
|
||||
|
||||
```
|
||||
urbanLifelineServ/.bin/database/postgres/sql/
|
||||
├── createTableAll.sql # 完整初始化
|
||||
├── createTablePermission.sql # 权限模块
|
||||
├── createTableUser.sql # 用户模块
|
||||
├── createTableFile.sql # 文件模块
|
||||
├── createTableMessage.sql # 消息模块
|
||||
├── createTableLog.sql # 日志模块
|
||||
├── createTableConfig.sql # 配置模块
|
||||
├── createTableKnowledge.sql # 知识库模块 ✨
|
||||
├── createTableBidding.sql # 招投标模块 ✨
|
||||
├── createTableCustomerService.sql # 智能客服模块 ✨
|
||||
├── createTableAgent.sql # 智能体管理模块 ✨
|
||||
├── optimizations.sql # 优化补丁 ✨
|
||||
├── initDataPermission.sql # 权限初始数据
|
||||
├── initDataUser.sql # 用户初始数据
|
||||
└── initAll.sql # 完整初始化(表+数据)
|
||||
```
|
||||
|
||||
### B. 扩展插件
|
||||
|
||||
```sql
|
||||
-- 向量检索
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
|
||||
-- 全文检索(中文)
|
||||
CREATE EXTENSION IF NOT EXISTS zhparser;
|
||||
CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
|
||||
|
||||
-- 模糊匹配
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- UUID生成
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
```
|
||||
|
||||
### C. 性能基准
|
||||
|
||||
| 指标 | 目标值 | 说明 |
|
||||
|------|--------|------|
|
||||
| 单表查询 | < 100ms | 主键/索引查询 |
|
||||
| 复杂查询 | < 500ms | 多表JOIN |
|
||||
| 向量检索 | < 200ms | Top-K检索 |
|
||||
| 写入TPS | > 1000 | 批量插入 |
|
||||
| 并发连接 | 200+ | HikariCP连接池 |
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-12-02
|
||||
**维护者**: Urban Lifeline Team
|
||||
599
docs/数据库表结构速查.md
599
docs/数据库表结构速查.md
@@ -1,599 +0,0 @@
|
||||
# 数据库表结构速查手册
|
||||
|
||||
## 快速导航
|
||||
|
||||
- [系统基础模块 (sys)](#系统基础模块-sys)
|
||||
- [文件管理模块 (file)](#文件管理模块-file)
|
||||
- [消息通知模块 (message)](#消息通知模块-message)
|
||||
- [日志模块 (log)](#日志模块-log)
|
||||
- [配置管理模块 (config)](#配置管理模块-config)
|
||||
- [知识库管理模块 (knowledge)](#知识库管理模块-knowledge)
|
||||
- [招投标智能体模块 (bidding)](#招投标智能体模块-bidding)
|
||||
- [智能客服系统模块 (customer_service)](#智能客服系统模块-customerservice)
|
||||
- [智能体管理模块 (agent)](#智能体管理模块-agent)
|
||||
|
||||
---
|
||||
|
||||
## 系统基础模块 (sys)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_sys_user` | 用户表 | user_id | email, phone, wechat_id, status |
|
||||
| `tb_sys_user_info` | 用户信息表 | user_id | avatar, full_name, gender, level |
|
||||
| `tb_sys_dept` | 部门表 | dept_id | name, parent_id, dept_path |
|
||||
| `tb_sys_role` | 角色表 | role_id | name, scope, owner_dept_id |
|
||||
| `tb_sys_permission` | 权限表 | permission_id | name, code, module_id |
|
||||
| `tb_sys_user_role` | 用户角色关联表 | (user_id, role_id) | - |
|
||||
| `tb_sys_role_permission` | 角色权限关联表 | (role_id, permission_id) | - |
|
||||
| `tb_sys_view` | 视图/菜单表 | view_id | name, url, component, type |
|
||||
| `tb_sys_module` | 模块表 | module_id | name, description |
|
||||
| `tb_sys_acl` | 对象级权限表 | acl_id | object_type, object_id, principal_type, permission |
|
||||
| `tb_sys_acl_policy` | ACL策略表 | policy_id | object_type, edit_hierarchy_rule, view_hierarchy_rule |
|
||||
| `tb_sys_login_log` | 登录日志表 | optsn | user_id, ip_address, login_time, status |
|
||||
| `tb_sys_user_dept` | 用户部门关联表 | (user_id, dept_id) | is_primary, position |
|
||||
|
||||
### 权限模型
|
||||
|
||||
```
|
||||
用户 (tb_sys_user)
|
||||
├─ 用户角色 (tb_sys_user_role)
|
||||
│ └─ 角色 (tb_sys_role)
|
||||
│ ├─ 角色权限 (tb_sys_role_permission)
|
||||
│ │ └─ 权限 (tb_sys_permission)
|
||||
│ │ └─ 模块 (tb_sys_module)
|
||||
│ └─ 视图权限 (tb_sys_view_permission)
|
||||
│ └─ 视图 (tb_sys_view)
|
||||
└─ 对象权限 (tb_sys_acl)
|
||||
└─ ACL策略 (tb_sys_acl_policy)
|
||||
```
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询用户所有权限
|
||||
SELECT p.code, p.name
|
||||
FROM sys.tb_sys_user_role ur
|
||||
JOIN sys.tb_sys_role_permission rp ON ur.role_id = rp.role_id
|
||||
JOIN sys.tb_sys_permission p ON rp.permission_id = p.permission_id
|
||||
WHERE ur.user_id = 'USER_ID' AND ur.deleted = false;
|
||||
|
||||
-- 查询部门树
|
||||
WITH RECURSIVE dept_tree AS (
|
||||
SELECT *, 1 AS level FROM sys.tb_sys_dept WHERE parent_id IS NULL
|
||||
UNION ALL
|
||||
SELECT d.*, dt.level + 1
|
||||
FROM sys.tb_sys_dept d
|
||||
JOIN dept_tree dt ON d.parent_id = dt.dept_id
|
||||
)
|
||||
SELECT * FROM dept_tree ORDER BY level, dept_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文件管理模块 (file)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_sys_file` | 文件表 | file_id | name, path, size, type, storage_type, url |
|
||||
| `tb_file_relation` | 文件关联表 | relation_id | file_id, object_type, object_id, relation_type |
|
||||
|
||||
### 文件类型
|
||||
|
||||
- `storage_type`: local(本地存储) / oss(对象存储) / ftp / sftp
|
||||
- `relation_type`: attachment(附件) / avatar(头像) / banner(横幅)
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询对象的所有附件
|
||||
SELECT f.*
|
||||
FROM file.tb_sys_file f
|
||||
JOIN file.tb_file_relation fr ON f.file_id = fr.file_id
|
||||
WHERE fr.object_type = 'bidding_project'
|
||||
AND fr.object_id = 'PROJECT_ID'
|
||||
AND fr.deleted = false;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 消息通知模块 (message)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_message` | 消息表 | message_id | title, content, type, status |
|
||||
| `tb_message_range` | 消息发送范围表 | optsn | message_id, target_type, target_id, channel |
|
||||
| `tb_message_receiver` | 用户消息接收表 | optsn | message_id, user_id, status, read_time |
|
||||
| `tb_message_channel` | 消息渠道配置表 | channel_id | channel_code, channel_name, status |
|
||||
| `tb_message_template` | 消息模板表 | template_id | template_code, title_template, content_template |
|
||||
|
||||
### 消息发送流程
|
||||
|
||||
```
|
||||
创建消息 (tb_message)
|
||||
↓
|
||||
定义发送范围 (tb_message_range)
|
||||
├─ target_type: user(指定用户) / dept(部门) / role(角色) / all(全员)
|
||||
├─ channel: app / sms / email / wechat
|
||||
↓
|
||||
生成接收记录 (tb_message_receiver)
|
||||
└─ status: unread → read → handled / deleted
|
||||
```
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询用户未读消息
|
||||
SELECT m.*, mr.create_time AS receive_time
|
||||
FROM message.tb_message m
|
||||
JOIN message.tb_message_receiver mr ON m.message_id = mr.message_id
|
||||
WHERE mr.user_id = 'USER_ID'
|
||||
AND mr.status = 'unread'
|
||||
AND mr.deleted = false
|
||||
ORDER BY mr.create_time DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 日志模块 (log)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_sys_log` | 系统日志表 | log_id | type, level, module, message, data, trace_id |
|
||||
|
||||
### 日志级别
|
||||
|
||||
- `level`: debug / info / warn / error / fatal
|
||||
- `type`: system / audit / security / business / api
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询错误日志
|
||||
SELECT * FROM log.tb_sys_log
|
||||
WHERE level IN ('error', 'fatal')
|
||||
AND create_time > now() - interval '24 hours'
|
||||
ORDER BY create_time DESC;
|
||||
|
||||
-- 链路追踪
|
||||
SELECT * FROM log.tb_sys_log
|
||||
WHERE trace_id = 'TRACE_ID'
|
||||
ORDER BY create_time;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置管理模块 (config)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_sys_config` | 系统配置表 | config_id | key, name, value, config_type, render_type |
|
||||
|
||||
### 配置类型
|
||||
|
||||
- `config_type`: String / Integer / Boolean / Float / Double
|
||||
- `render_type`: select / input / textarea / checkbox / radio / switch
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 按模块查询配置
|
||||
SELECT * FROM config.tb_sys_config
|
||||
WHERE module_id = 'MODULE_ID' AND deleted = false
|
||||
ORDER BY order_num;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 知识库管理模块 (knowledge)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_knowledge_base` | 知识库表 | kb_id | name, kb_type, access_level, version |
|
||||
| `tb_knowledge_document` | 知识文档表 | doc_id | kb_id, title, doc_type, category, embedding_status |
|
||||
| `tb_knowledge_chunk` | 文档片段表 | chunk_id | doc_id, kb_id, content, embedding |
|
||||
| `tb_knowledge_access_log` | 知识访问日志表 | log_id | kb_id, doc_id, user_id, access_type |
|
||||
|
||||
### 知识库类型
|
||||
|
||||
- `kb_type`: bidding(招投标) / customer_service(客服) / internal(内部协同)
|
||||
- `access_level`: public(公开) / private(私有) / internal(内部)
|
||||
- `embedding_status`: pending(待处理) / processing(处理中) / completed(完成) / failed(失败)
|
||||
|
||||
### RAG检索流程
|
||||
|
||||
```
|
||||
用户查询
|
||||
↓
|
||||
向量化查询文本
|
||||
↓
|
||||
在 tb_knowledge_chunk 中进行向量检索 (embedding)
|
||||
↓
|
||||
获取相关文档片段
|
||||
↓
|
||||
关联 tb_knowledge_document 获取完整文档信息
|
||||
↓
|
||||
返回结果 + 记录访问日志
|
||||
```
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询知识库文档
|
||||
SELECT d.*, kb.name AS kb_name
|
||||
FROM knowledge.tb_knowledge_document d
|
||||
JOIN knowledge.tb_knowledge_base kb ON d.kb_id = kb.kb_id
|
||||
WHERE d.kb_id = 'KB_ID'
|
||||
AND d.embedding_status = 'completed'
|
||||
AND d.deleted = false;
|
||||
|
||||
-- 向量检索(需要pgvector扩展)
|
||||
-- SELECT chunk_id, content,
|
||||
-- 1 - (embedding <=> '[查询向量]'::vector) AS similarity
|
||||
-- FROM knowledge.tb_knowledge_chunk
|
||||
-- WHERE kb_id = 'KB_ID'
|
||||
-- ORDER BY embedding <=> '[查询向量]'::vector
|
||||
-- LIMIT 10;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 招投标智能体模块 (bidding)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_bidding_project` | 招标项目表 | project_id | project_no, project_name, project_status, deadline |
|
||||
| `tb_bidding_document` | 招标文件表 | doc_id | project_id, doc_type, parse_status, parse_result |
|
||||
| `tb_bidding_requirement` | 要素提取表 | req_id | project_id, req_category, is_veto, compliance_status |
|
||||
| `tb_bid_response` | 投标文件生成表 | response_id | project_id, response_type, generation_status |
|
||||
| `tb_bidding_scoring_rule` | 评分规则表 | rule_id | project_id, rule_category, max_score, our_score |
|
||||
| `tb_bidding_process` | 流程节点表 | process_id | project_id, node_type, node_status |
|
||||
| `tb_bid_template` | 投标模板表 | template_id | template_name, template_type, usage_count |
|
||||
|
||||
### 项目生命周期
|
||||
|
||||
```
|
||||
collecting(收集中)
|
||||
↓
|
||||
analyzing(分析中) - 智能解读招标文件
|
||||
↓
|
||||
preparing(准备投标) - 生成投标文件
|
||||
↓
|
||||
submitted(已提交)
|
||||
↓
|
||||
opened(已开标)
|
||||
↓
|
||||
won(中标) / lost(未中标) / abandoned(放弃)
|
||||
```
|
||||
|
||||
### 要素类别
|
||||
|
||||
- `req_category`:
|
||||
- commercial: 商务要素
|
||||
- technical: 技术参数
|
||||
- veto: 否决项 ⚠️
|
||||
- qualification: 资质要求
|
||||
- delivery: 交付要求
|
||||
- payment: 付款条件
|
||||
- scoring: 评分标准
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询项目的所有否决项
|
||||
SELECT * FROM bidding.tb_bidding_requirement
|
||||
WHERE project_id = 'PROJECT_ID'
|
||||
AND is_veto = true
|
||||
AND deleted = false;
|
||||
|
||||
-- 查询项目评分预估
|
||||
SELECT
|
||||
rule_category,
|
||||
SUM(max_score) AS total_max_score,
|
||||
SUM(our_score) AS total_our_score,
|
||||
ROUND(SUM(our_score) / SUM(max_score) * 100, 2) AS score_percentage
|
||||
FROM bidding.tb_bidding_scoring_rule
|
||||
WHERE project_id = 'PROJECT_ID' AND deleted = false
|
||||
GROUP BY rule_category;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 智能客服系统模块 (customer_service)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_customer` | 客户信息表 | customer_id | customer_name, phone, wechat_openid, customer_level |
|
||||
| `tb_conversation` | 会话表 | conversation_id | customer_id, conversation_type, agent_id, satisfaction_rating |
|
||||
| `tb_conversation_message` | 会话消息表 | message_id | conversation_id, sender_type, content, is_ai_generated |
|
||||
| `tb_ticket` | 工单表 | ticket_id | ticket_no, customer_id, ticket_type, ticket_status, sla_deadline |
|
||||
| `tb_ticket_log` | 工单处理记录表 | log_id | ticket_id, action_type, action_content |
|
||||
| `tb_faq` | FAQ表 | faq_id | category, question, answer, hit_count |
|
||||
| `tb_service_evaluation` | 客服评价表 | evaluation_id | customer_id, evaluation_type, rating |
|
||||
| `tb_crm_config` | CRM集成配置表 | config_id | crm_system, api_endpoint, sync_enabled |
|
||||
|
||||
### 会话流程
|
||||
|
||||
```
|
||||
客户发起咨询
|
||||
↓
|
||||
创建会话 (tb_conversation)
|
||||
├─ conversation_type: ai(AI客服) / human(人工) / transfer(转接)
|
||||
↓
|
||||
消息交互 (tb_conversation_message)
|
||||
├─ sender_type: customer / agent / system
|
||||
├─ is_ai_generated: true/false
|
||||
├─ kb_references: [知识库文档ID]
|
||||
↓
|
||||
智能工单生成 (tb_ticket)
|
||||
├─ ticket_source: ai / manual / system
|
||||
↓
|
||||
满意度评价 (tb_service_evaluation / tb_conversation)
|
||||
```
|
||||
|
||||
### 工单状态
|
||||
|
||||
- `ticket_status`:
|
||||
- pending: 待处理
|
||||
- processing: 处理中
|
||||
- resolved: 已解决
|
||||
- closed: 已关闭
|
||||
- cancelled: 已取消
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询客户的活跃会话
|
||||
SELECT * FROM customer_service.tb_conversation
|
||||
WHERE customer_id = 'CUSTOMER_ID'
|
||||
AND conversation_status = 'active'
|
||||
AND deleted = false;
|
||||
|
||||
-- 查询逾期工单
|
||||
SELECT * FROM customer_service.tb_ticket
|
||||
WHERE is_overdue = true
|
||||
AND ticket_status IN ('pending', 'processing')
|
||||
AND deleted = false
|
||||
ORDER BY sla_deadline;
|
||||
|
||||
-- 查询AI回答质量
|
||||
SELECT
|
||||
DATE(create_time) AS stat_date,
|
||||
AVG(confidence_score) AS avg_confidence,
|
||||
COUNT(*) FILTER (WHERE confidence_score > 0.8) AS high_confidence_count,
|
||||
COUNT(*) AS total_count
|
||||
FROM customer_service.tb_conversation_message
|
||||
WHERE is_ai_generated = true
|
||||
AND deleted = false
|
||||
GROUP BY DATE(create_time);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 智能体管理模块 (agent)
|
||||
|
||||
### 核心表结构
|
||||
|
||||
| 表名 | 说明 | 主键 | 核心字段 |
|
||||
|------|------|------|----------|
|
||||
| `tb_agent` | 智能体定义表 | agent_id | agent_code, agent_name, agent_type, model_config |
|
||||
| `tb_agent_session` | 智能体会话表 | session_id | agent_id, user_id, session_status, token_usage |
|
||||
| `tb_agent_message` | 智能体消息表 | message_id | session_id, role, content, function_call |
|
||||
| `tb_agent_tool` | 智能体工具表 | tool_id | tool_code, tool_type, function_schema, api_endpoint |
|
||||
| `tb_api_integration` | API集成表 | integration_id | integration_name, base_url, auth_config |
|
||||
| `tb_api_call_log` | API调用日志表 | log_id | integration_id, endpoint, response_status, duration_ms |
|
||||
| `tb_agent_metrics` | 智能体监控指标表 | metric_id | agent_id, metric_date, total_sessions, total_tokens |
|
||||
| `tb_agent_error_log` | 智能体异常日志表 | log_id | agent_id, error_type, error_message, severity |
|
||||
| `tb_agent_rating` | 智能体评价表 | rating_id | agent_id, rating, feedback |
|
||||
|
||||
### 智能体类型
|
||||
|
||||
- `agent_type`:
|
||||
- bidding: 招投标智能体
|
||||
- customer_service: 客服智能体
|
||||
- knowledge_assistant: 知识助手
|
||||
- custom: 自定义智能体
|
||||
|
||||
### 工具类型
|
||||
|
||||
- `tool_type`:
|
||||
- api: API调用
|
||||
- function: 函数
|
||||
- plugin: 插件
|
||||
- integration: 集成
|
||||
|
||||
### 会话流程
|
||||
|
||||
```
|
||||
用户请求
|
||||
↓
|
||||
创建会话 (tb_agent_session)
|
||||
↓
|
||||
消息交互 (tb_agent_message)
|
||||
├─ role: user / assistant / system / function
|
||||
├─ function_call: 工具调用
|
||||
↓
|
||||
工具执行 (tb_agent_tool)
|
||||
├─ API调用记录 (tb_api_call_log)
|
||||
↓
|
||||
记录监控指标 (tb_agent_metrics)
|
||||
├─ 错误记录 (tb_agent_error_log)
|
||||
↓
|
||||
用户评价 (tb_agent_rating)
|
||||
```
|
||||
|
||||
### 常用查询
|
||||
|
||||
```sql
|
||||
-- 查询智能体使用统计
|
||||
SELECT * FROM agent.v_agent_usage_stats
|
||||
WHERE agent_id = 'AGENT_ID';
|
||||
|
||||
-- 查询API健康状态
|
||||
SELECT
|
||||
integration_name,
|
||||
health_status,
|
||||
last_health_check,
|
||||
EXTRACT(EPOCH FROM (now() - last_health_check))/60 AS minutes_since_check
|
||||
FROM agent.tb_api_integration
|
||||
WHERE deleted = false
|
||||
ORDER BY health_status, last_health_check;
|
||||
|
||||
-- 查询智能体错误率
|
||||
SELECT
|
||||
a.agent_name,
|
||||
COUNT(*) FILTER (WHERE e.severity = 'critical') AS critical_errors,
|
||||
COUNT(*) FILTER (WHERE e.severity = 'error') AS errors,
|
||||
COUNT(*) AS total_errors
|
||||
FROM agent.tb_agent a
|
||||
LEFT JOIN agent.tb_agent_error_log e ON a.agent_id = e.agent_id
|
||||
WHERE e.create_time > now() - interval '24 hours'
|
||||
GROUP BY a.agent_id, a.agent_name;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据字典常用字段说明
|
||||
|
||||
### 通用字段
|
||||
|
||||
所有表都包含以下标准字段:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `optsn` | VARCHAR(50) | 流水号(唯一标识) |
|
||||
| `xxx_id` | VARCHAR(50) | 主键ID |
|
||||
| `dept_path` | VARCHAR(255) | 部门全路径(多租户隔离) |
|
||||
| `creator` | VARCHAR(50) | 创建者ID |
|
||||
| `updater` | VARCHAR(50) | 更新者ID |
|
||||
| `create_time` | timestamptz | 创建时间(带时区) |
|
||||
| `update_time` | timestamptz | 更新时间(触发器自动更新) |
|
||||
| `delete_time` | timestamptz | 删除时间 |
|
||||
| `deleted` | BOOLEAN | 软删除标记 |
|
||||
|
||||
### 时间戳说明
|
||||
|
||||
- 使用 `timestamptz` 类型(带时区的时间戳)
|
||||
- 自动记录创建时间
|
||||
- 更新时间由触发器自动维护
|
||||
- 支持软删除(保留 delete_time)
|
||||
|
||||
### 部门路径(dept_path)
|
||||
|
||||
格式:`/1/2/3/`
|
||||
|
||||
- 用于多租户数据隔离
|
||||
- 支持 LIKE 递归查询
|
||||
- 示例查询:`WHERE dept_path LIKE '/1/2/%'`
|
||||
|
||||
---
|
||||
|
||||
## 视图速查
|
||||
|
||||
| 视图名 | Schema | 说明 |
|
||||
|--------|--------|------|
|
||||
| `v_user_full_info` | sys | 用户完整信息(含用户信息表) |
|
||||
| `v_user_role_permission` | sys | 用户角色权限(含模块) |
|
||||
| `v_user_full_permissions` | sys | 用户完整权限(含ACL) |
|
||||
| `v_agent_usage_stats` | agent | 智能体使用统计 |
|
||||
| `v_agent_realtime_status` | agent | 智能体实时状态 |
|
||||
| `v_ticket_stats` | customer_service | 工单统计 |
|
||||
| `v_ticket_efficiency` | customer_service | 工单处理效率 |
|
||||
| `v_project_stats` | bidding | 招投标项目统计 |
|
||||
|
||||
---
|
||||
|
||||
## 函数速查
|
||||
|
||||
| 函数名 | Schema | 说明 |
|
||||
|--------|--------|------|
|
||||
| `update_modified_column()` | public | 自动更新update_time触发器函数 |
|
||||
| `audit_trigger_func()` | public | 审计日志触发器函数 |
|
||||
| `archive_old_logs()` | public | 归档旧日志数据 |
|
||||
| `archive_api_logs()` | agent | 归档API调用日志 |
|
||||
| `check_table_bloat()` | public | 检查表膨胀情况 |
|
||||
| `create_update_triggers()` | public | 批量创建更新触发器 |
|
||||
|
||||
---
|
||||
|
||||
## 索引策略
|
||||
|
||||
### 主要索引类型
|
||||
|
||||
1. **B-Tree索引**(默认):主键、外键、常规查询字段
|
||||
2. **GIN索引**:JSONB字段、数组字段、全文搜索
|
||||
3. **部分索引**:带WHERE条件的索引(如 `WHERE deleted = false`)
|
||||
4. **表达式索引**:函数索引(如 `lower(email)`)
|
||||
|
||||
### 关键索引示例
|
||||
|
||||
```sql
|
||||
-- 部分索引(减少索引大小)
|
||||
CREATE INDEX idx_xxx ON table_name(column) WHERE deleted = false;
|
||||
|
||||
-- GIN索引(数组查询)
|
||||
CREATE INDEX idx_xxx ON table_name USING gin(array_column);
|
||||
|
||||
-- 全文搜索索引
|
||||
CREATE INDEX idx_xxx ON table_name USING gin(text_column gin_trgm_ops);
|
||||
|
||||
-- 表达式索引
|
||||
CREATE INDEX idx_xxx ON table_name(lower(email));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 查询优化
|
||||
|
||||
1. **使用索引**:WHERE、JOIN、ORDER BY字段都要有索引
|
||||
2. **避免SELECT ***:只查询需要的字段
|
||||
3. **使用LIMIT**:分页查询限制返回行数
|
||||
4. **使用EXPLAIN**:分析查询计划
|
||||
|
||||
### 批量操作
|
||||
|
||||
```sql
|
||||
-- 批量插入(使用COPY或批量INSERT)
|
||||
COPY table_name FROM '/path/to/file.csv' WITH CSV;
|
||||
|
||||
-- 批量更新(使用UPDATE...FROM)
|
||||
UPDATE table_name t
|
||||
SET column = data.value
|
||||
FROM (VALUES (1, 'a'), (2, 'b')) AS data(id, value)
|
||||
WHERE t.id = data.id;
|
||||
```
|
||||
|
||||
### 定期维护
|
||||
|
||||
```sql
|
||||
-- 分析表(更新统计信息)
|
||||
ANALYZE table_name;
|
||||
|
||||
-- 清理和分析
|
||||
VACUUM ANALYZE table_name;
|
||||
|
||||
-- 重建索引
|
||||
REINDEX TABLE table_name;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0
|
||||
**更新时间**: 2024-12-02
|
||||
@@ -1,511 +0,0 @@
|
||||
# 泰豪电源AI数智化平台 - 数据库设计交付总结
|
||||
|
||||
## 📋 交付概览
|
||||
|
||||
基于`功能结构.xml`中定义的系统架构,完成了泰豪电源AI数智化平台的完整数据库设计,覆盖"一个底座、多种智能体"的核心理念和四大业务模块。
|
||||
|
||||
---
|
||||
|
||||
## 📦 交付内容
|
||||
|
||||
### 1. SQL脚本文件
|
||||
|
||||
所有文件位于:`urbanLifelineServ\.bin\database\postgres\sql\`
|
||||
|
||||
| 文件名 | 说明 | 表数量 |
|
||||
|--------|------|--------|
|
||||
| `createTablePermission.sql` | 系统权限模块(现有优化) | 11张 |
|
||||
| `createTableUser.sql` | 用户管理模块(现有优化) | 3张 |
|
||||
| `createTableFile.sql` | 文件管理模块(现有) | 1张 |
|
||||
| `createTableMessage.sql` | 消息通知模块(现有) | 4张 |
|
||||
| `createTableLog.sql` | 日志模块(现有) | 1张 |
|
||||
| `createTableConfig.sql` | 配置管理模块(现有) | 1张 |
|
||||
| **`createTableKnowledge.sql`** | ✨ **知识库管理模块(新建)** | **4张** |
|
||||
| **`createTableBidding.sql`** | ✨ **招投标智能体业务模块(新建)** | **8张** |
|
||||
| **`createTableCustomerService.sql`** | ✨ **智能客服系统业务模块(新建)** | **9张** |
|
||||
| **`createTableAgent.sql`** | ✨ **智能体管理模块(新建)** | **11张** |
|
||||
| **`createTableAll.sql`** | ✨ **完整初始化脚本(新建)** | - |
|
||||
| **`optimizations.sql`** | ✨ **数据库优化补丁(新建)** | - |
|
||||
|
||||
**总计:53张核心业务表**
|
||||
|
||||
### 2. 文档资料
|
||||
|
||||
所有文档位于:`docs\`
|
||||
|
||||
| 文件名 | 说明 |
|
||||
|--------|------|
|
||||
| **`数据库设计文档.md`** | 完整的数据库设计说明文档(23000+字) |
|
||||
| **`数据库表结构速查.md`** | 表结构快速参考手册(含常用查询示例) |
|
||||
| **`数据库设计交付总结.md`** | 本文档 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 核心设计亮点
|
||||
|
||||
### 1. 模块化架构设计
|
||||
|
||||
采用9个Schema实现业务逻辑隔离:
|
||||
|
||||
```
|
||||
sys ← 系统基础(用户、权限、部门)
|
||||
file ← 文件管理
|
||||
message ← 消息通知
|
||||
log ← 日志审计
|
||||
config ← 系统配置
|
||||
knowledge ← 知识库管理(支持RAG检索)
|
||||
bidding ← 招投标智能体业务
|
||||
customer_service ← 智能客服系统业务
|
||||
agent ← 智能体管理和平台基础设施
|
||||
```
|
||||
|
||||
### 2. 权限体系设计
|
||||
|
||||
**RBAC + ACL混合模型**
|
||||
|
||||
- **RBAC(基于角色的访问控制)**:
|
||||
- 支持全局角色和部门私有角色
|
||||
- 角色-权限-模块三层结构
|
||||
- 视图/菜单权限独立管理
|
||||
|
||||
- **ACL(访问控制列表)**:
|
||||
- 对象级细粒度权限控制
|
||||
- 支持任意对象类型(文章、文件、课程等)
|
||||
- 权限位设计(读/写/执行)
|
||||
- 支持显式拒绝和权限继承
|
||||
|
||||
### 3. 多租户支持
|
||||
|
||||
- **部门路径隔离**(`dept_path`字段):格式 `/1/2/3/`
|
||||
- **行级安全策略**(RLS):基于用户部门自动过滤数据
|
||||
- **作用域控制**:角色和权限的作用域管理
|
||||
|
||||
### 4. 知识库智能管理
|
||||
|
||||
**支持RAG(检索增强生成)流程:**
|
||||
|
||||
```
|
||||
文档上传 → 智能分类 → AI摘要 → 关键词提取 → 文档切片 → 向量化 → 存储
|
||||
↓ ↓
|
||||
tb_knowledge_document tb_knowledge_chunk
|
||||
(支持向量检索)
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- 多类型知识库(招投标/客服/内部协同)
|
||||
- 版本管理和历史追溯
|
||||
- 向量化状态跟踪
|
||||
- 访问日志记录
|
||||
|
||||
### 5. 招投标全流程管理
|
||||
|
||||
**完整业务流程覆盖:**
|
||||
|
||||
```
|
||||
项目创建 → 文件采集 → 智能解读 → 要素提取 → 评分分析
|
||||
↓ ↓
|
||||
流程跟踪 ← 投标提交 ← 文件审核 ← 投标文件生成 ← 模板管理
|
||||
```
|
||||
|
||||
**核心功能:**
|
||||
- **智能要素提取**:7大类要素(商务/技术/否决项/资质/交付/付款/评分)
|
||||
- **AI文件生成**:支持技术标/商务标/综合标
|
||||
- **评分规则分析**:自动解析评分标准,预估得分
|
||||
- **流程节点管理**:完整的项目生命周期跟踪
|
||||
|
||||
### 6. 智能客服系统
|
||||
|
||||
**全渠道客服支持:**
|
||||
|
||||
```
|
||||
微信小程序 → AI问答 → 知识库检索 → 工单生成 → CRM同步
|
||||
↓ ↓ ↓ ↓
|
||||
客户管理 会话记录 工单处理 满意度评价
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- **双终端知识库**:客户咨询知识库(外部)+ 内部资料知识库(内部)
|
||||
- **智能会话管理**:AI/人工/转接会话类型,情感分析,意图识别
|
||||
- **工单智能处理**:AI自动生成工单,SLA超时预警,CRM双向同步
|
||||
- **评价体系**:多维度评价(准确性、速度、友好度等)
|
||||
|
||||
### 7. 智能体管理平台
|
||||
|
||||
**智能体广场 + 工具集成 + 运维监控:**
|
||||
|
||||
```
|
||||
智能体定义 → 工具配置 → API集成 → 会话管理 → 监控运维 → 评价反馈
|
||||
↓ ↓ ↓ ↓ ↓
|
||||
多模型支持 Function 健康检查 Token统计 错误追踪
|
||||
```
|
||||
|
||||
**特性:**
|
||||
- **智能体广场**:发布/评分/分类/标签管理
|
||||
- **工具生态**:支持API调用、函数、插件、集成
|
||||
- **监控体系**:实时指标、错误日志、性能分析
|
||||
- **成本跟踪**:Token使用量、API调用费用统计
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据库架构统计
|
||||
|
||||
### 表结构统计
|
||||
|
||||
| Schema | 表数量 | 主要功能 |
|
||||
|--------|--------|----------|
|
||||
| sys | 13 | 用户、角色、权限、部门、ACL |
|
||||
| file | 2 | 文件管理、文件关联 |
|
||||
| message | 5 | 消息、发送范围、接收记录、渠道、模板 |
|
||||
| log | 1 | 系统日志 |
|
||||
| config | 1 | 系统配置 |
|
||||
| knowledge | 4 | 知识库、文档、片段、访问日志 |
|
||||
| bidding | 8 | 项目、文件、要素、投标、评分、流程、模板 |
|
||||
| customer_service | 9 | 客户、会话、消息、工单、FAQ、评价、CRM |
|
||||
| agent | 11 | 智能体、会话、消息、工具、API、监控、错误 |
|
||||
| **总计** | **54** | - |
|
||||
|
||||
### 索引策略
|
||||
|
||||
- **B-Tree索引**:100+ 个(主键、外键、常规查询)
|
||||
- **GIN索引**:20+ 个(JSONB、数组、全文搜索)
|
||||
- **部分索引**:50+ 个(WHERE deleted = false)
|
||||
- **表达式索引**:5+ 个(函数索引)
|
||||
|
||||
### 视图和函数
|
||||
|
||||
- **业务视图**:8个(权限视图、统计视图)
|
||||
- **触发器函数**:2个(自动更新时间、审计日志)
|
||||
- **业务函数**:4个(数据归档、性能监控)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术特性
|
||||
|
||||
### 1. 数据类型使用
|
||||
|
||||
- **timestamptz**:全部时间字段(带时区支持)
|
||||
- **JSONB**:配置、元数据、扩展字段
|
||||
- **数组(TEXT[])**:标签、关键词、ID列表
|
||||
- **DECIMAL**:金额、评分(精确计算)
|
||||
- **vector**:向量嵌入(需pgvector扩展,可选)
|
||||
|
||||
### 2. 软删除机制
|
||||
|
||||
所有业务表支持软删除:
|
||||
- `deleted` 字段:BOOLEAN类型,默认false
|
||||
- `delete_time` 字段:删除时间戳
|
||||
- 索引优化:`WHERE deleted = false`
|
||||
|
||||
### 3. 审计追踪
|
||||
|
||||
- **通用字段**:creator、updater、create_time、update_time
|
||||
- **自动触发器**:update_time自动更新
|
||||
- **审计日志**:可选的审计触发器(记录所有变更)
|
||||
- **链路追踪**:trace_id、span_id支持分布式追踪
|
||||
|
||||
### 4. 性能优化
|
||||
|
||||
- **分区表设计**:日志表、指标表建议按时间分区
|
||||
- **物化视图**:权限视图可物化提升性能
|
||||
- **数据归档**:提供自动归档函数
|
||||
- **表膨胀监控**:check_table_bloat()函数
|
||||
|
||||
---
|
||||
|
||||
## 📈 业务价值
|
||||
|
||||
### 1. 支撑功能结构.xml定义的四大业务模块
|
||||
|
||||
✅ **资料管理智能化** → knowledge模块
|
||||
✅ **招投标自动化** → bidding模块
|
||||
✅ **售后客服智能化** → customer_service模块
|
||||
✅ **企业内部知识协同** → knowledge + agent模块
|
||||
|
||||
### 2. 实现"一个底座、多种智能体"
|
||||
|
||||
- **统一的智能体管理平台**(agent模块)
|
||||
- **共享的知识库体系**(knowledge模块)
|
||||
- **统一的权限和用户管理**(sys模块)
|
||||
- **统一的文件和消息服务**(file、message模块)
|
||||
|
||||
### 3. 可扩展性设计
|
||||
|
||||
- **新增智能体类型**:在agent.tb_agent中添加新的agent_type
|
||||
- **新增业务模块**:创建新的Schema和表
|
||||
- **集成外部系统**:通过API集成表和CRM配置表
|
||||
- **自定义权限**:通过ACL表实现任意对象的权限控制
|
||||
|
||||
---
|
||||
|
||||
## 🚀 部署指南
|
||||
|
||||
### 快速部署
|
||||
|
||||
```bash
|
||||
# 进入SQL脚本目录
|
||||
cd urbanLifelineServ\.bin\database\postgres\sql
|
||||
|
||||
# 1. 创建数据库
|
||||
createdb urbanlifeline
|
||||
|
||||
# 2. 执行完整初始化脚本(推荐)
|
||||
psql -d urbanlifeline -f createTableAll.sql
|
||||
|
||||
# 或者手动按顺序执行
|
||||
psql -d urbanlifeline -f createTablePermission.sql
|
||||
psql -d urbanlifeline -f createTableUser.sql
|
||||
psql -d urbanlifeline -f createTableFile.sql
|
||||
psql -d urbanlifeline -f createTableMessage.sql
|
||||
psql -d urbanlifeline -f createTableLog.sql
|
||||
psql -d urbanlifeline -f createTableConfig.sql
|
||||
psql -d urbanlifeline -f createTableKnowledge.sql
|
||||
psql -d urbanlifeline -f createTableBidding.sql
|
||||
psql -d urbanlifeline -f createTableCustomerService.sql
|
||||
psql -d urbanlifeline -f createTableAgent.sql
|
||||
|
||||
# 3. 执行优化补丁(可选)
|
||||
psql -d urbanlifeline -f optimizations.sql
|
||||
|
||||
# 4. 初始化基础数据
|
||||
psql -d urbanlifeline -f initDataConfig.sql
|
||||
```
|
||||
|
||||
### 依赖扩展
|
||||
|
||||
```sql
|
||||
-- 必需扩展
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID生成
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- 全文搜索
|
||||
CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- GIN索引支持
|
||||
|
||||
-- 可选扩展
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- 数据加密
|
||||
CREATE EXTENSION IF NOT EXISTS "vector"; -- 向量检索(需单独安装)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 现有SQL文件的优化建议
|
||||
|
||||
### 已实施的优化
|
||||
|
||||
✅ **createTableUser.sql**
|
||||
- 移除登录日志表的password字段(安全性)
|
||||
- 添加用户部门关联表(多对多关系)
|
||||
- 添加主部门字段
|
||||
|
||||
✅ **createTablePermission.sql**
|
||||
- 添加角色排序字段
|
||||
- 添加权限类型字段(操作/数据/菜单权限)
|
||||
|
||||
✅ **createTableFile.sql**
|
||||
- 添加版本管理字段
|
||||
- 添加分类和标签
|
||||
- 创建文件关联表(统一文件关联机制)
|
||||
|
||||
✅ **createTableMessage.sql**
|
||||
- 创建消息模板表(支持模板化发送)
|
||||
|
||||
✅ **createTableLog.sql**
|
||||
- 添加链路追踪字段(trace_id、span_id)
|
||||
|
||||
### 建议的补充优化
|
||||
|
||||
详见:`optimizations.sql`文件
|
||||
|
||||
---
|
||||
|
||||
## 📚 参考文档
|
||||
|
||||
### 1. 数据库设计文档.md
|
||||
|
||||
**内容包含:**
|
||||
- 系统概述和架构设计
|
||||
- 核心模块详细设计
|
||||
- 数据库优化建议
|
||||
- 现有SQL文件修改建议
|
||||
- 数据安全建议
|
||||
- 部署和维护建议
|
||||
|
||||
**适用场景:**
|
||||
- 系统架构师了解整体设计
|
||||
- 开发人员理解业务逻辑
|
||||
- DBA进行数据库优化
|
||||
|
||||
### 2. 数据库表结构速查.md
|
||||
|
||||
**内容包含:**
|
||||
- 所有模块的表结构快速参考
|
||||
- 常用查询示例
|
||||
- 视图和函数速查
|
||||
- 索引策略说明
|
||||
- 性能优化建议
|
||||
|
||||
**适用场景:**
|
||||
- 日常开发查询表结构
|
||||
- 编写业务SQL
|
||||
- 快速定位相关表
|
||||
|
||||
### 3. 功能结构.xml
|
||||
|
||||
**原始需求文档:**
|
||||
- 系统目标定义
|
||||
- 四大业务模块功能划分
|
||||
- 平台基础设施模块
|
||||
- Draw.io格式的架构图
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验证检查清单
|
||||
|
||||
### 数据完整性
|
||||
|
||||
- [x] 所有表都有主键
|
||||
- [x] 外键关系正确定义
|
||||
- [x] 唯一约束合理设置
|
||||
- [x] 非空约束符合业务逻辑
|
||||
|
||||
### 性能优化
|
||||
|
||||
- [x] 高频查询字段都有索引
|
||||
- [x] 外键字段都有索引
|
||||
- [x] 使用部分索引减少索引大小
|
||||
- [x] JSONB和数组字段使用GIN索引
|
||||
|
||||
### 安全性
|
||||
|
||||
- [x] 敏感字段移除或加密
|
||||
- [x] 软删除机制
|
||||
- [x] 审计日志支持
|
||||
- [x] 行级安全策略(可选启用)
|
||||
|
||||
### 可维护性
|
||||
|
||||
- [x] 表名和字段名规范统一
|
||||
- [x] 所有表和字段都有注释
|
||||
- [x] 触发器自动维护update_time
|
||||
- [x] 提供数据归档函数
|
||||
|
||||
### 可扩展性
|
||||
|
||||
- [x] Schema分离便于模块扩展
|
||||
- [x] JSONB字段支持灵活扩展
|
||||
- [x] 标签和分类字段
|
||||
- [x] 元数据字段预留
|
||||
|
||||
---
|
||||
|
||||
## 📊 后续优化方向
|
||||
|
||||
### 短期(1-3个月)
|
||||
|
||||
1. **向量检索优化**
|
||||
- 安装pgvector扩展
|
||||
- 优化embedding索引参数
|
||||
- 实现混合检索(向量+全文)
|
||||
|
||||
2. **监控告警**
|
||||
- 集成pgBadger日志分析
|
||||
- 配置慢查询告警
|
||||
- 设置表膨胀告警
|
||||
|
||||
3. **数据初始化**
|
||||
- 编写初始化数据脚本
|
||||
- 创建测试数据集
|
||||
- 准备演示数据
|
||||
|
||||
### 中期(3-6个月)
|
||||
|
||||
1. **性能优化**
|
||||
- 分析慢查询并优化
|
||||
- 实施分区表策略
|
||||
- 创建物化视图
|
||||
|
||||
2. **读写分离**
|
||||
- 配置主从复制
|
||||
- 实现读写分离中间件
|
||||
- 优化读库查询
|
||||
|
||||
3. **备份策略**
|
||||
- 实施全量+增量备份
|
||||
- 配置WAL归档
|
||||
- 演练灾难恢复
|
||||
|
||||
### 长期(6-12个月)
|
||||
|
||||
1. **分布式部署**
|
||||
- 评估Citus扩展
|
||||
- 设计分片策略
|
||||
- 实现水平扩展
|
||||
|
||||
2. **多数据中心**
|
||||
- 配置异地备份
|
||||
- 实现数据同步
|
||||
- 制定灾备方案
|
||||
|
||||
3. **智能优化**
|
||||
- 自动索引推荐
|
||||
- 查询性能自动优化
|
||||
- 存储自动扩容
|
||||
|
||||
---
|
||||
|
||||
## 🎓 技术栈总结
|
||||
|
||||
### 数据库技术
|
||||
|
||||
- **PostgreSQL 14+**:主数据库
|
||||
- **pgvector**:向量检索(可选)
|
||||
- **pg_trgm**:全文搜索
|
||||
- **JSONB**:半结构化数据存储
|
||||
- **Row Level Security**:行级安全策略
|
||||
|
||||
### 设计模式
|
||||
|
||||
- **RBAC + ACL**:混合权限模型
|
||||
- **软删除**:数据安全保护
|
||||
- **多租户**:部门路径隔离
|
||||
- **审计追踪**:完整的变更记录
|
||||
- **事件驱动**:触发器自动化
|
||||
|
||||
### 性能优化
|
||||
|
||||
- **索引策略**:B-Tree + GIN + 部分索引
|
||||
- **查询优化**:视图、CTE、窗口函数
|
||||
- **数据归档**:自动归档函数
|
||||
- **分区表**:时间序列数据分区
|
||||
|
||||
---
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
### 问题反馈
|
||||
|
||||
如在使用过程中遇到问题,请提供:
|
||||
1. 问题描述
|
||||
2. 错误信息
|
||||
3. 执行的SQL语句
|
||||
4. PostgreSQL版本
|
||||
|
||||
### 文档维护
|
||||
|
||||
本文档随数据库设计持续更新:
|
||||
- **当前版本**:v1.0
|
||||
- **更新日期**:2024-12-02
|
||||
- **维护团队**:泰豪电源AI数智化平台开发组
|
||||
|
||||
---
|
||||
|
||||
## 🎉 交付完成
|
||||
|
||||
✅ **50+张核心业务表设计完成**
|
||||
✅ **12个SQL脚本文件交付**
|
||||
✅ **3份完整技术文档**
|
||||
✅ **覆盖4大业务模块**
|
||||
✅ **支持"一个底座、多种智能体"架构**
|
||||
|
||||
**数据库设计已完全就绪,可直接用于项目开发!** 🚀
|
||||
|
||||
---
|
||||
|
||||
**感谢使用!**
|
||||
698
docs/数据库设计文档.md
698
docs/数据库设计文档.md
@@ -1,698 +0,0 @@
|
||||
# 泰豪电源AI数智化平台 - 数据库设计文档
|
||||
|
||||
## 一、系统概述
|
||||
|
||||
基于功能结构.xml的系统架构设计,本数据库设计遵循"一个底座、多种智能体"的核心理念,支持四大业务模块:
|
||||
|
||||
1. **资料管理智能化**
|
||||
2. **招投标自动化**
|
||||
3. **售后客服智能化**
|
||||
4. **企业内部知识协同**
|
||||
|
||||
## 二、数据库架构设计
|
||||
|
||||
### 2.1 Schema划分
|
||||
|
||||
采用多Schema架构,按业务模块逻辑隔离:
|
||||
|
||||
| Schema | 说明 | 核心表数量 |
|
||||
|--------|------|-----------|
|
||||
| `sys` | 系统基础模块(用户、角色、权限、部门) | 11 |
|
||||
| `file` | 文件管理模块 | 1 |
|
||||
| `message` | 消息通知模块 | 4 |
|
||||
| `log` | 日志审计模块 | 1 |
|
||||
| `config` | 系统配置模块 | 1 |
|
||||
| `knowledge` | 知识库管理模块 | 4 |
|
||||
| `bidding` | 招投标智能体业务模块 | 8 |
|
||||
| `customer_service` | 智能客服系统业务模块 | 9 |
|
||||
| `agent` | 智能体管理和平台基础设施模块 | 11 |
|
||||
|
||||
**总计:50张核心业务表**
|
||||
|
||||
## 三、核心模块详细设计
|
||||
|
||||
### 3.1 系统基础模块 (sys)
|
||||
|
||||
#### 3.1.1 权限体系设计
|
||||
|
||||
采用**RBAC(基于角色的访问控制)+ ACL(访问控制列表)**混合模型:
|
||||
|
||||
**核心表:**
|
||||
- `tb_sys_user` - 用户表
|
||||
- `tb_sys_role` - 角色表(支持全局角色和部门私有角色)
|
||||
- `tb_sys_permission` - 权限表
|
||||
- `tb_sys_dept` - 部门表(树形结构)
|
||||
- `tb_sys_acl` - 通用对象级权限表(支持细粒度权限控制)
|
||||
- `tb_sys_acl_policy` - ACL策略表(层级可见/可编辑规则)
|
||||
|
||||
**设计亮点:**
|
||||
1. **多租户支持**:通过`dept_path`字段实现数据隔离,支持部门级多租户
|
||||
2. **角色作用域**:`scope`字段区分全局角色和部门私有角色
|
||||
3. **细粒度权限**:ACL表支持对任意对象类型(文章、文件、课程等)的权限控制
|
||||
4. **层级权限继承**:`include_descendants`支持子部门/子角色权限继承
|
||||
|
||||
#### 3.1.2 用户信息管理
|
||||
|
||||
```sql
|
||||
-- 用户表结构优势
|
||||
tb_sys_user:
|
||||
- 支持多种登录方式(email、phone、wechat_id)
|
||||
- 密码加密存储(建议bcrypt/argon2)
|
||||
- 软删除机制(deleted + delete_time)
|
||||
- 时区感知时间戳(timestamptz)
|
||||
```
|
||||
|
||||
### 3.2 知识库管理模块 (knowledge)
|
||||
|
||||
#### 3.2.1 表结构设计
|
||||
|
||||
**核心表:**
|
||||
- `tb_knowledge_base` - 知识库定义表
|
||||
- `tb_knowledge_document` - 知识文档表
|
||||
- `tb_knowledge_chunk` - 文档片段表(RAG检索)
|
||||
- `tb_knowledge_access_log` - 访问日志表
|
||||
|
||||
**设计亮点:**
|
||||
|
||||
1. **多类型知识库支持**
|
||||
```sql
|
||||
kb_type:
|
||||
- bidding -- 招投标知识库
|
||||
- customer_service -- 客服知识库
|
||||
- internal -- 内部协同知识库
|
||||
```
|
||||
|
||||
2. **文档智能处理**
|
||||
- 自动分类(`category`字段)
|
||||
- AI摘要生成(`content_summary`)
|
||||
- 关键词提取(`keywords`数组)
|
||||
- 向量化状态跟踪(`embedding_status`)
|
||||
|
||||
3. **RAG检索支持**
|
||||
- `tb_knowledge_chunk`表存储文档切片
|
||||
- `embedding`字段存储向量(需pgvector扩展)
|
||||
- 支持语义检索和混合检索
|
||||
|
||||
4. **版本管理**
|
||||
- `version`字段跟踪文档版本
|
||||
- `parent_doc_id`构建版本树
|
||||
|
||||
### 3.3 招投标智能体业务模块 (bidding)
|
||||
|
||||
#### 3.3.1 核心业务流程
|
||||
|
||||
```
|
||||
项目创建 → 文件采集 → 智能解读 → 要素提取 → 投标文件生成 → 审核提交 → 流程跟踪
|
||||
```
|
||||
|
||||
#### 3.3.2 表结构设计
|
||||
|
||||
**核心表:**
|
||||
1. `tb_bidding_project` - 招标项目表(主表)
|
||||
2. `tb_bidding_document` - 招标文件表
|
||||
3. `tb_bidding_requirement` - 要素提取表
|
||||
4. `tb_bid_response` - 投标文件生成表
|
||||
5. `tb_bidding_scoring_rule` - 评分规则表
|
||||
6. `tb_bidding_process` - 流程节点表
|
||||
7. `tb_bid_template` - 投标模板表
|
||||
|
||||
**设计亮点:**
|
||||
|
||||
1. **完整项目生命周期管理**
|
||||
```sql
|
||||
project_status:
|
||||
- collecting -- 收集中
|
||||
- analyzing -- 分析中
|
||||
- preparing -- 准备投标
|
||||
- submitted -- 已提交
|
||||
- opened -- 已开标
|
||||
- won/lost -- 中标/未中标
|
||||
- abandoned -- 放弃
|
||||
```
|
||||
|
||||
2. **智能要素提取**
|
||||
- 支持7大类要素(商务、技术、否决项、资质、交付、付款、评分)
|
||||
- AI提取置信度跟踪
|
||||
- 来源位置记录(页码、段落)
|
||||
- 合规状态跟踪
|
||||
|
||||
3. **投标文件生成**
|
||||
- 支持多种生成方式(AI生成、模板生成、人工编写)
|
||||
- 版本管理(`parent_version_id`)
|
||||
- 审批流程状态跟踪
|
||||
|
||||
4. **评分规则智能分析**
|
||||
- 多维度评分(技术分、商务分、价格分、信誉分)
|
||||
- 公式计算支持
|
||||
- 得分预估和优化建议
|
||||
|
||||
### 3.4 智能客服系统业务模块 (customer_service)
|
||||
|
||||
#### 3.4.1 核心业务流程
|
||||
|
||||
```
|
||||
客户咨询 → AI问答 → 人工转接 → 工单生成 → 工单处理 → CRM同步 → 满意度评价
|
||||
```
|
||||
|
||||
#### 3.4.2 表结构设计
|
||||
|
||||
**核心表:**
|
||||
1. `tb_customer` - 客户信息表
|
||||
2. `tb_conversation` - 会话表
|
||||
3. `tb_conversation_message` - 会话消息表
|
||||
4. `tb_ticket` - 工单表
|
||||
5. `tb_ticket_log` - 工单处理记录表
|
||||
6. `tb_faq` - FAQ表
|
||||
7. `tb_service_evaluation` - 客服评价表
|
||||
8. `tb_crm_config` - CRM集成配置表
|
||||
|
||||
**设计亮点:**
|
||||
|
||||
1. **全渠道客户管理**
|
||||
- 支持多渠道(微信、网页、APP、电话)
|
||||
- 客户等级分层(VIP、重要、普通、潜在)
|
||||
- 标签化管理
|
||||
- CRM系统ID映射
|
||||
|
||||
2. **智能会话管理**
|
||||
- AI/人工/转接会话类型
|
||||
- 会话摘要自动生成
|
||||
- 满意度评价跟踪
|
||||
- 消息情感分析和意图识别
|
||||
|
||||
3. **工单智能处理**
|
||||
- AI自动生成工单
|
||||
- SLA超时预警
|
||||
- 优先级智能判定
|
||||
- CRM双向同步
|
||||
|
||||
4. **知识库引用跟踪**
|
||||
- `kb_references`字段记录引用的知识库文档
|
||||
- 支持回答溯源
|
||||
- 知识库质量评估数据
|
||||
|
||||
### 3.5 智能体管理模块 (agent)
|
||||
|
||||
#### 3.5.1 核心功能
|
||||
|
||||
```
|
||||
智能体定义 → 工具集成 → API管理 → 会话管理 → 监控运维 → 评价反馈
|
||||
```
|
||||
|
||||
#### 3.5.2 表结构设计
|
||||
|
||||
**核心表:**
|
||||
1. `tb_agent` - 智能体定义表
|
||||
2. `tb_agent_session` - 智能体会话表
|
||||
3. `tb_agent_message` - 智能体消息表
|
||||
4. `tb_agent_tool` - 智能体工具表
|
||||
5. `tb_api_integration` - API集成注册表
|
||||
6. `tb_api_call_log` - API调用日志表
|
||||
7. `tb_agent_metrics` - 智能体监控指标表
|
||||
8. `tb_agent_error_log` - 智能体异常日志表
|
||||
9. `tb_agent_rating` - 智能体评价表
|
||||
|
||||
**设计亮点:**
|
||||
|
||||
1. **智能体广场**
|
||||
- `is_published`字段支持发布到广场
|
||||
- 评分和使用次数统计
|
||||
- 分类和标签管理
|
||||
- 访问级别控制
|
||||
|
||||
2. **工具和API集成**
|
||||
- 标准化工具定义(OpenAI Function Calling格式)
|
||||
- 多种认证方式支持
|
||||
- 健康检查机制
|
||||
- 调用日志完整记录
|
||||
|
||||
3. **监控和运维**
|
||||
- 按日期/小时的指标聚合
|
||||
- 成本跟踪(Token使用量、API调用费用)
|
||||
- 错误日志和堆栈跟踪
|
||||
- 成功率和响应时间监控
|
||||
|
||||
4. **会话管理**
|
||||
- 支持对话、任务、工作流多种类型
|
||||
- 上下文管理(JSONB格式)
|
||||
- Token使用量统计
|
||||
- 知识库引用跟踪
|
||||
|
||||
## 四、数据库优化建议
|
||||
|
||||
### 4.1 索引优化
|
||||
|
||||
#### 4.1.1 已实现的索引策略
|
||||
|
||||
1. **主键索引**:所有表都有主键(通常为业务ID)
|
||||
2. **唯一索引**:关键业务字段(email、phone、编号等)
|
||||
3. **外键索引**:关联查询字段
|
||||
4. **复合索引**:高频查询组合字段
|
||||
5. **部分索引**:带WHERE条件的索引(减少索引大小)
|
||||
6. **GIN索引**:数组字段(tags、keywords等)
|
||||
|
||||
#### 4.1.2 建议增加的索引
|
||||
|
||||
```sql
|
||||
-- 知识库文档全文搜索索引(需要pg_trgm扩展)
|
||||
CREATE INDEX idx_knowledge_doc_title_trgm
|
||||
ON knowledge.tb_knowledge_document USING gin(title gin_trgm_ops);
|
||||
|
||||
-- 会话消息内容全文搜索
|
||||
CREATE INDEX idx_message_content_trgm
|
||||
ON customer_service.tb_conversation_message USING gin(content gin_trgm_ops);
|
||||
|
||||
-- 招标项目名称搜索
|
||||
CREATE INDEX idx_project_name_trgm
|
||||
ON bidding.tb_bidding_project USING gin(project_name gin_trgm_ops);
|
||||
```
|
||||
|
||||
### 4.2 性能优化建议
|
||||
|
||||
#### 4.2.1 分区表设计
|
||||
|
||||
对于数据量大、查询集中在时间范围的表,建议使用分区:
|
||||
|
||||
```sql
|
||||
-- 示例:API调用日志按月分区
|
||||
CREATE TABLE agent.tb_api_call_log (
|
||||
-- ... 字段定义
|
||||
) PARTITION BY RANGE (create_time);
|
||||
|
||||
CREATE TABLE agent.tb_api_call_log_2024_01
|
||||
PARTITION OF agent.tb_api_call_log
|
||||
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
||||
```
|
||||
|
||||
**建议分区的表:**
|
||||
- `agent.tb_api_call_log` - API调用日志
|
||||
- `log.tb_sys_log` - 系统日志
|
||||
- `knowledge.tb_knowledge_access_log` - 知识访问日志
|
||||
- `agent.tb_agent_metrics` - 智能体监控指标(已按日期设计)
|
||||
|
||||
#### 4.2.2 JSONB字段优化
|
||||
|
||||
```sql
|
||||
-- 为JSONB字段创建GIN索引
|
||||
CREATE INDEX idx_agent_model_config_gin
|
||||
ON agent.tb_agent(model_config) USING gin;
|
||||
|
||||
-- 为JSONB内特定键创建表达式索引
|
||||
CREATE INDEX idx_agent_config_model_name
|
||||
ON agent.tb_agent((model_config->>'model_name'));
|
||||
```
|
||||
|
||||
#### 4.2.3 数组字段优化
|
||||
|
||||
```sql
|
||||
-- 使用GIN索引支持数组查询
|
||||
CREATE INDEX idx_kb_doc_tags_gin
|
||||
ON knowledge.tb_knowledge_document USING gin(tags);
|
||||
|
||||
-- 查询示例
|
||||
SELECT * FROM knowledge.tb_knowledge_document
|
||||
WHERE tags @> ARRAY['技术文档'];
|
||||
```
|
||||
|
||||
### 4.3 数据归档策略
|
||||
|
||||
#### 4.3.1 软删除设计
|
||||
|
||||
当前设计使用软删除(`deleted`字段),建议:
|
||||
|
||||
1. **定期归档**:将deleted=true且超过6个月的数据移至归档表
|
||||
2. **归档表命名**:`tb_xxx_archived`
|
||||
3. **保留必要索引**:归档表仅保留时间范围查询索引
|
||||
|
||||
#### 4.3.2 日志数据归档
|
||||
|
||||
```sql
|
||||
-- 日志归档策略
|
||||
-- 1. API调用日志:保留近3个月,其余归档
|
||||
-- 2. 系统日志:保留近6个月,其余归档
|
||||
-- 3. 访问日志:保留近1个月,其余归档
|
||||
|
||||
-- 归档函数示例
|
||||
CREATE OR REPLACE FUNCTION archive_old_logs()
|
||||
RETURNS void AS $$
|
||||
BEGIN
|
||||
-- 归档API调用日志
|
||||
INSERT INTO agent.tb_api_call_log_archived
|
||||
SELECT * FROM agent.tb_api_call_log
|
||||
WHERE create_time < now() - interval '3 months';
|
||||
|
||||
DELETE FROM agent.tb_api_call_log
|
||||
WHERE create_time < now() - interval '3 months';
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
```
|
||||
|
||||
### 4.4 查询优化建议
|
||||
|
||||
#### 4.4.1 常用查询模式
|
||||
|
||||
```sql
|
||||
-- 1. 用户权限检查(高频查询)
|
||||
-- 建议:创建物化视图
|
||||
CREATE MATERIALIZED VIEW sys.mv_user_permissions AS
|
||||
SELECT
|
||||
ur.user_id,
|
||||
array_agg(DISTINCT p.code) AS permissions
|
||||
FROM sys.tb_sys_user_role ur
|
||||
JOIN sys.tb_sys_role_permission rp ON ur.role_id = rp.role_id
|
||||
JOIN sys.tb_sys_permission p ON rp.permission_id = p.permission_id
|
||||
WHERE ur.deleted = false AND rp.deleted = false
|
||||
GROUP BY ur.user_id;
|
||||
|
||||
CREATE UNIQUE INDEX ON sys.mv_user_permissions(user_id);
|
||||
|
||||
-- 定期刷新
|
||||
REFRESH MATERIALIZED VIEW CONCURRENTLY sys.mv_user_permissions;
|
||||
```
|
||||
|
||||
#### 4.4.2 复杂统计查询优化
|
||||
|
||||
```sql
|
||||
-- 使用CTE和窗口函数优化统计查询
|
||||
WITH daily_stats AS (
|
||||
SELECT
|
||||
DATE(create_time) AS stat_date,
|
||||
agent_id,
|
||||
COUNT(*) AS session_count,
|
||||
SUM(message_count) AS total_messages
|
||||
FROM agent.tb_agent_session
|
||||
WHERE deleted = false
|
||||
GROUP BY DATE(create_time), agent_id
|
||||
)
|
||||
SELECT
|
||||
agent_id,
|
||||
stat_date,
|
||||
session_count,
|
||||
total_messages,
|
||||
SUM(session_count) OVER (
|
||||
PARTITION BY agent_id
|
||||
ORDER BY stat_date
|
||||
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
|
||||
) AS rolling_7day_sessions
|
||||
FROM daily_stats;
|
||||
```
|
||||
|
||||
## 五、现有SQL文件修改建议
|
||||
|
||||
### 5.1 createTableUser.sql 优化
|
||||
|
||||
**当前问题:**
|
||||
1. 登录日志表中存储密码不安全
|
||||
2. 缺少用户部门关联
|
||||
|
||||
**建议修改:**
|
||||
|
||||
```sql
|
||||
-- 1. 移除登录日志表的password字段
|
||||
ALTER TABLE sys.tb_sys_login_log DROP COLUMN IF EXISTS password;
|
||||
|
||||
-- 2. 添加用户部门关联表
|
||||
CREATE TABLE sys.tb_sys_user_dept (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
user_id VARCHAR(50) NOT NULL,
|
||||
dept_id VARCHAR(50) NOT NULL,
|
||||
is_primary BOOLEAN DEFAULT false, -- 是否主部门
|
||||
position VARCHAR(100), -- 职位
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (user_id, dept_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
-- 3. 用户表添加默认部门字段
|
||||
ALTER TABLE sys.tb_sys_user
|
||||
ADD COLUMN IF NOT EXISTS primary_dept_id VARCHAR(50);
|
||||
```
|
||||
|
||||
### 5.2 createTablePermission.sql 优化
|
||||
|
||||
**建议修改:**
|
||||
|
||||
```sql
|
||||
-- 1. 角色表添加排序字段
|
||||
ALTER TABLE sys.tb_sys_role
|
||||
ADD COLUMN IF NOT EXISTS order_num INTEGER DEFAULT 0;
|
||||
|
||||
-- 2. 权限表添加权限类型字段
|
||||
ALTER TABLE sys.tb_sys_permission
|
||||
ADD COLUMN IF NOT EXISTS permission_type VARCHAR(20) DEFAULT 'action';
|
||||
-- permission_type: action-操作权限/data-数据权限/menu-菜单权限
|
||||
|
||||
COMMENT ON COLUMN sys.tb_sys_permission.permission_type
|
||||
IS '权限类型:action-操作权限/data-数据权限/menu-菜单权限';
|
||||
```
|
||||
|
||||
### 5.3 createTableFile.sql 扩展
|
||||
|
||||
**建议添加:**
|
||||
|
||||
```sql
|
||||
-- 1. 文件版本管理
|
||||
ALTER TABLE file.tb_sys_file
|
||||
ADD COLUMN IF NOT EXISTS version VARCHAR(20) DEFAULT '1.0',
|
||||
ADD COLUMN IF NOT EXISTS parent_file_id VARCHAR(50),
|
||||
ADD COLUMN IF NOT EXISTS is_latest BOOLEAN DEFAULT true;
|
||||
|
||||
-- 2. 文件分类
|
||||
ALTER TABLE file.tb_sys_file
|
||||
ADD COLUMN IF NOT EXISTS category VARCHAR(100),
|
||||
ADD COLUMN IF NOT EXISTS tags TEXT[];
|
||||
|
||||
-- 3. 文件关联(支持文件和业务对象关联)
|
||||
CREATE TABLE file.tb_file_relation (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
relation_id VARCHAR(50) NOT NULL,
|
||||
file_id VARCHAR(50) NOT NULL,
|
||||
object_type VARCHAR(50) NOT NULL, -- 对象类型:bidding_project/ticket/document等
|
||||
object_id VARCHAR(50) NOT NULL, -- 对象ID
|
||||
relation_type VARCHAR(30) DEFAULT 'attachment', -- 关联类型:attachment-附件/avatar-头像/banner-横幅
|
||||
order_num INTEGER DEFAULT 0,
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (relation_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (file_id) REFERENCES file.tb_sys_file(file_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_file_relation_object
|
||||
ON file.tb_file_relation(object_type, object_id) WHERE deleted = false;
|
||||
```
|
||||
|
||||
### 5.4 createTableMessage.sql 增强
|
||||
|
||||
**建议添加:**
|
||||
|
||||
```sql
|
||||
-- 1. 消息模板表
|
||||
CREATE TABLE message.tb_message_template (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
template_id VARCHAR(50) NOT NULL,
|
||||
template_code VARCHAR(100) NOT NULL, -- 模板编码
|
||||
template_name VARCHAR(255) NOT NULL, -- 模板名称
|
||||
template_type VARCHAR(30) NOT NULL, -- 模板类型:system-系统/business-业务
|
||||
title_template TEXT, -- 标题模板(支持变量)
|
||||
content_template TEXT NOT NULL, -- 内容模板(支持变量)
|
||||
variables JSONB, -- 变量定义
|
||||
dept_path VARCHAR(255) DEFAULT NULL,
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
updater VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (template_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (template_code)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE message.tb_message_template IS '消息模板表';
|
||||
```
|
||||
|
||||
## 六、数据安全建议
|
||||
|
||||
### 6.1 敏感数据加密
|
||||
|
||||
**需要加密的字段:**
|
||||
1. `sys.tb_sys_user.password` - 用户密码(使用bcrypt/argon2)
|
||||
2. `agent.tb_agent_tool.auth_config` - API认证配置
|
||||
3. `agent.tb_api_integration.auth_config` - 集成认证配置
|
||||
4. `customer_service.tb_crm_config.api_key` - CRM API密钥
|
||||
|
||||
**建议使用PostgreSQL的pgcrypto扩展:**
|
||||
|
||||
```sql
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
-- 加密示例
|
||||
INSERT INTO agent.tb_agent_tool (auth_config)
|
||||
VALUES (pgp_sym_encrypt('{"api_key": "secret"}', 'encryption_key'));
|
||||
|
||||
-- 解密示例
|
||||
SELECT pgp_sym_decrypt(auth_config::bytea, 'encryption_key')
|
||||
FROM agent.tb_agent_tool;
|
||||
```
|
||||
|
||||
### 6.2 行级安全策略(RLS)
|
||||
|
||||
```sql
|
||||
-- 启用行级安全
|
||||
ALTER TABLE knowledge.tb_knowledge_document ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 创建策略:用户只能访问自己部门的文档
|
||||
CREATE POLICY dept_isolation_policy ON knowledge.tb_knowledge_document
|
||||
FOR SELECT
|
||||
USING (
|
||||
dept_path LIKE (
|
||||
SELECT dept_path || '%'
|
||||
FROM sys.tb_sys_user
|
||||
WHERE user_id = current_setting('app.current_user_id')
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
### 6.3 审计日志增强
|
||||
|
||||
```sql
|
||||
-- 添加审计触发器
|
||||
CREATE OR REPLACE FUNCTION audit_trigger_func()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
INSERT INTO log.tb_sys_log (
|
||||
log_id, type, level, module, message, data, creator
|
||||
) VALUES (
|
||||
gen_random_uuid()::text,
|
||||
'audit',
|
||||
'info',
|
||||
TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'Record deleted',
|
||||
row_to_json(OLD),
|
||||
current_setting('app.current_user_id', true)
|
||||
);
|
||||
RETURN OLD;
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
INSERT INTO log.tb_sys_log (
|
||||
log_id, type, level, module, message, data, creator
|
||||
) VALUES (
|
||||
gen_random_uuid()::text,
|
||||
'audit',
|
||||
'info',
|
||||
TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'Record updated',
|
||||
jsonb_build_object('old', row_to_json(OLD), 'new', row_to_json(NEW)),
|
||||
current_setting('app.current_user_id', true)
|
||||
);
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 为敏感表添加审计触发器
|
||||
CREATE TRIGGER audit_user_changes
|
||||
AFTER UPDATE OR DELETE ON sys.tb_sys_user
|
||||
FOR EACH ROW EXECUTE FUNCTION audit_trigger_func();
|
||||
```
|
||||
|
||||
## 七、部署和维护建议
|
||||
|
||||
### 7.1 初始化顺序
|
||||
|
||||
```bash
|
||||
# 1. 创建扩展
|
||||
psql -d urbanlifeline -f extensions.sql
|
||||
|
||||
# 2. 按依赖顺序执行建表脚本
|
||||
psql -d urbanlifeline -f createTablePermission.sql
|
||||
psql -d urbanlifeline -f createTableUser.sql
|
||||
psql -d urbanlifeline -f createTableFile.sql
|
||||
psql -d urbanlifeline -f createTableMessage.sql
|
||||
psql -d urbanlifeline -f createTableLog.sql
|
||||
psql -d urbanlifeline -f createTableConfig.sql
|
||||
psql -d urbanlifeline -f createTableKnowledge.sql
|
||||
psql -d urbanlifeline -f createTableBidding.sql
|
||||
psql -d urbanlifeline -f createTableCustomerService.sql
|
||||
psql -d urbanlifeline -f createTableAgent.sql
|
||||
|
||||
# 3. 执行完整初始化(包含触发器和视图)
|
||||
psql -d urbanlifeline -f createTableAll.sql
|
||||
|
||||
# 4. 初始化基础数据
|
||||
psql -d urbanlifeline -f initDataConfig.sql
|
||||
```
|
||||
|
||||
### 7.2 定期维护任务
|
||||
|
||||
```sql
|
||||
-- 1. 分析和优化表
|
||||
ANALYZE VERBOSE;
|
||||
VACUUM ANALYZE;
|
||||
|
||||
-- 2. 重建索引(处理索引膨胀)
|
||||
REINDEX DATABASE urbanlifeline;
|
||||
|
||||
-- 3. 更新表统计信息
|
||||
VACUUM ANALYZE sys.tb_sys_user;
|
||||
VACUUM ANALYZE agent.tb_agent_session;
|
||||
|
||||
-- 4. 检查慢查询
|
||||
SELECT query, calls, total_time, mean_time
|
||||
FROM pg_stat_statements
|
||||
ORDER BY mean_time DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
### 7.3 备份策略
|
||||
|
||||
```bash
|
||||
# 全量备份(每日)
|
||||
pg_dump -Fc urbanlifeline > backup_$(date +%Y%m%d).dump
|
||||
|
||||
# 增量备份(使用WAL归档)
|
||||
# 在postgresql.conf中配置:
|
||||
# wal_level = replica
|
||||
# archive_mode = on
|
||||
# archive_command = 'cp %p /path/to/archive/%f'
|
||||
|
||||
# 恢复示例
|
||||
pg_restore -d urbanlifeline -c backup_20240101.dump
|
||||
```
|
||||
|
||||
## 八、总结
|
||||
|
||||
### 8.1 设计优势
|
||||
|
||||
1. **模块化架构**:9个Schema清晰划分业务边界
|
||||
2. **可扩展性**:支持多租户、多智能体、多业务类型
|
||||
3. **性能优化**:合理的索引设计、分区策略、视图优化
|
||||
4. **数据安全**:软删除、审计日志、权限控制、数据加密
|
||||
5. **业务完整**:覆盖招投标、客服、知识库全流程
|
||||
|
||||
### 8.2 后续优化方向
|
||||
|
||||
1. **向量检索优化**:引入pgvector扩展,优化RAG检索性能
|
||||
2. **分布式部署**:考虑Citus扩展实现水平扩展
|
||||
3. **实时数据同步**:使用Logical Replication实现异地备份
|
||||
4. **监控告警**:集成pgBadger、pg_stat_statements等工具
|
||||
5. **读写分离**:主从复制实现读写分离
|
||||
|
||||
### 8.3 关键指标
|
||||
|
||||
- **总表数**:50+ 张核心表
|
||||
- **Schema数**:9 个业务Schema
|
||||
- **索引类型**:B-Tree、GIN、部分索引、表达式索引
|
||||
- **数据类型**:标准类型 + JSONB + 数组 + 向量(可选)
|
||||
- **时区支持**:全部使用timestamptz
|
||||
- **软删除**:全表支持deleted标记
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: 1.0
|
||||
**最后更新**: 2024-12-02
|
||||
**维护团队**: 泰豪电源AI数智化平台开发组
|
||||
396
docs/网关认证方案.md
Normal file
396
docs/网关认证方案.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# Gateway 认证方案说明
|
||||
|
||||
## 问题背景
|
||||
|
||||
在微服务架构中,如果同时使用 Gateway 和 common-auth 模块,会出现**重复认证**的问题:
|
||||
|
||||
```
|
||||
浏览器 → Gateway (AuthGlobalFilter 验证 JWT)
|
||||
→ 微服务 (JwtAuthenticationFilter 再次验证 JWT) ❌ 重复!
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
|
||||
提供两种认证模式,通过配置选择:
|
||||
|
||||
### **模式一:Gateway 统一认证(推荐)**
|
||||
|
||||
Gateway 负责认证,微服务信任 Gateway 传递的用户信息。
|
||||
|
||||
#### 架构流程
|
||||
|
||||
```
|
||||
浏览器
|
||||
↓ (带 JWT Token)
|
||||
Nginx (80端口)
|
||||
↓
|
||||
Gateway (8080端口)
|
||||
├─ AuthGlobalFilter: 验证 JWT ✓
|
||||
├─ 提取用户信息 (userId, username)
|
||||
├─ 添加到请求头传递给下游
|
||||
└─ 路由到微服务
|
||||
↓
|
||||
微服务
|
||||
└─ GatewayTrustFilter: 从请求头获取用户信息 ✓
|
||||
```
|
||||
|
||||
#### 配置方式
|
||||
|
||||
**1. Gateway 服务配置** (`gateway/application.yml`)
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
auth-paths:
|
||||
- /auth/login
|
||||
- /auth/logout
|
||||
whitelist:
|
||||
- /actuator/**
|
||||
- /v3/api-docs/**
|
||||
```
|
||||
|
||||
**2. 微服务配置** (`system/application.yml`, `log/application.yml` 等)
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:启用 Gateway 模式
|
||||
```
|
||||
|
||||
#### 优点
|
||||
- ✅ 避免重复认证,性能更好
|
||||
- ✅ 统一认证逻辑,易维护
|
||||
- ✅ 微服务之间调用不需要传递 JWT
|
||||
|
||||
---
|
||||
|
||||
### **模式二:微服务独立认证**
|
||||
|
||||
每个微服务独立验证 JWT,Gateway 不做认证。
|
||||
|
||||
#### 架构流程
|
||||
|
||||
```
|
||||
浏览器
|
||||
↓ (带 JWT Token)
|
||||
Nginx
|
||||
↓
|
||||
Gateway
|
||||
└─ 直接路由(不验证)
|
||||
↓
|
||||
微服务
|
||||
└─ JwtAuthenticationFilter: 验证 JWT ✓
|
||||
```
|
||||
|
||||
#### 配置方式
|
||||
|
||||
**1. Gateway 服务配置**
|
||||
```yaml
|
||||
auth:
|
||||
enabled: false # 关键:关闭 Gateway 认证
|
||||
```
|
||||
|
||||
**2. 微服务配置**
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: false # 或不配置(默认 false)
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
```
|
||||
|
||||
#### 适用场景
|
||||
- 微服务需要直接对外暴露(不经过 Gateway)
|
||||
- 对安全性要求极高,需要每层都验证
|
||||
|
||||
---
|
||||
|
||||
## 配置文件对比
|
||||
|
||||
### Gateway 服务 (`gateway/application.yml`)
|
||||
|
||||
```yaml
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: gateway-service
|
||||
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: auth-service
|
||||
uri: lb://auth-service
|
||||
predicates:
|
||||
- Path=/auth/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
- id: system-service
|
||||
uri: lb://system-service
|
||||
predicates:
|
||||
- Path=/system/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
# 认证配置
|
||||
auth:
|
||||
enabled: true # 是否启用认证
|
||||
gateway-mode: false # Gateway 本身不需要此配置
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
auth-paths:
|
||||
- /auth/login
|
||||
- /auth/logout
|
||||
- /auth/captcha
|
||||
- /auth/refresh
|
||||
whitelist:
|
||||
- /actuator/**
|
||||
- /v3/api-docs/**
|
||||
```
|
||||
|
||||
### 微服务配置 (Gateway 模式)
|
||||
|
||||
**auth-service/application.yml**
|
||||
```yaml
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: auth-service
|
||||
|
||||
# 认证配置
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:信任 Gateway
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
whitelist:
|
||||
- /v3/api-docs/**
|
||||
- /actuator/**
|
||||
```
|
||||
|
||||
**system-service/application.yml**
|
||||
```yaml
|
||||
server:
|
||||
port: 8082
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: system-service
|
||||
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:信任 Gateway
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作原理
|
||||
|
||||
### Gateway 认证流程
|
||||
|
||||
**AuthGlobalFilter (Gateway 层)**
|
||||
```java
|
||||
1. 检查请求路径是否在白名单
|
||||
2. 提取 Authorization 请求头中的 JWT Token
|
||||
3. 验证 Token 是否过期
|
||||
4. 验证 Token 签名是否有效
|
||||
5. 提取用户信息 (userId, username)
|
||||
6. 将用户信息添加到请求头:
|
||||
- X-User-Id: {userId}
|
||||
- X-Username: {username}
|
||||
7. 路由到下游微服务
|
||||
```
|
||||
|
||||
### 微服务信任流程
|
||||
|
||||
**GatewayTrustFilter (微服务层)**
|
||||
```java
|
||||
1. 从请求头获取 Gateway 传递的用户信息:
|
||||
- X-User-Id
|
||||
- X-Username
|
||||
2. 构造 Spring Security 认证对象
|
||||
3. 设置到 SecurityContext
|
||||
4. 设置到 request attributes(供业务代码使用)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 内网安全
|
||||
|
||||
采用 Gateway 模式时,需确保:
|
||||
|
||||
1. **微服务不对外暴露**
|
||||
- 只能通过 Gateway 访问
|
||||
- 使用 Kubernetes Network Policy 或防火墙隔离
|
||||
|
||||
2. **请求头保护**
|
||||
- Gateway 在转发前清除任何客户端传递的 `X-User-Id` 等头
|
||||
- 防止伪造用户身份
|
||||
|
||||
3. **Gateway 过滤器增强**(可选)
|
||||
```java
|
||||
// 在 Gateway 中清除客户端可能伪造的请求头
|
||||
ServerHttpRequest mutatedRequest = request.mutate()
|
||||
.headers(headers -> {
|
||||
headers.remove("X-User-Id");
|
||||
headers.remove("X-Username");
|
||||
})
|
||||
.header(AuthContants.USER_ID_ATTRIBUTE, userId)
|
||||
.header(AuthContants.TOKEN_ATTRIBUTE, token)
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试 Gateway 模式
|
||||
|
||||
**1. 登录获取 Token**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"123456"}'
|
||||
|
||||
# 响应
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"userId": "1001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**2. 使用 Token 访问受保护接口**
|
||||
```bash
|
||||
curl -X GET http://localhost/api/system/user/profile \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
**3. 查看日志验证单次认证**
|
||||
```
|
||||
Gateway 日志:
|
||||
[Gateway] Token 验证成功: userId=1001, path=/system/user/profile
|
||||
|
||||
System-Service 日志:
|
||||
[GatewayTrustFilter] 从 Gateway 获取用户信息: userId=1001, username=admin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从独立认证迁移到 Gateway 统一认证
|
||||
|
||||
**步骤 1**: 更新所有微服务配置
|
||||
```yaml
|
||||
auth:
|
||||
gateway-mode: true # 添加这一行
|
||||
```
|
||||
|
||||
**步骤 2**: 重启服务(先重启微服务,后重启 Gateway)
|
||||
```bash
|
||||
# 重启微服务
|
||||
docker-compose restart auth-service system-service log-service
|
||||
|
||||
# 重启 Gateway
|
||||
docker-compose restart gateway
|
||||
```
|
||||
|
||||
**步骤 3**: 验证功能
|
||||
- 测试登录
|
||||
- 测试受保护接口访问
|
||||
- 检查日志确认只认证一次
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: Gateway 模式下,微服务之间如何调用?
|
||||
|
||||
**A**: 微服务间调用不需要传递 JWT Token,直接调用即可。Gateway已经验证过身份。
|
||||
|
||||
```java
|
||||
// 微服务 A 调用微服务 B
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public void callServiceB() {
|
||||
// 直接调用,不需要添加 Authorization 头
|
||||
String result = restTemplate.getForObject(
|
||||
"http://service-b/api/xxx",
|
||||
String.class
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Q2: 如何获取当前登录用户信息?
|
||||
|
||||
**A**: 使用 `@HttpLogin` 注解或从 SecurityContext 获取。
|
||||
|
||||
```java
|
||||
// 方式一:使用注解(推荐)
|
||||
@GetMapping("/profile")
|
||||
public ResultDomain<UserDTO> getProfile(@HttpLogin LoginDomain loginDomain) {
|
||||
String userId = loginDomain.getUser().getUserId();
|
||||
// ...
|
||||
}
|
||||
|
||||
// 方式二:从 SecurityContext 获取
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
String userId = (String) auth.getPrincipal();
|
||||
```
|
||||
|
||||
### Q3: Gateway 模式更安全还是独立认证更安全?
|
||||
|
||||
**A**: 取决于网络拓扑:
|
||||
- **内网隔离良好**: Gateway 模式更优(性能好,维护简单)
|
||||
- **微服务直接对外**: 独立认证更安全(每层验证)
|
||||
|
||||
---
|
||||
|
||||
## 推荐配置
|
||||
|
||||
### 生产环境推荐
|
||||
|
||||
```yaml
|
||||
# Gateway
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: false
|
||||
|
||||
# 所有微服务
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true
|
||||
```
|
||||
|
||||
### 开发环境(快速调试)
|
||||
|
||||
可以临时关闭认证:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
| 对比项 | Gateway 统一认证 | 微服务独立认证 |
|
||||
|--------|-----------------|---------------|
|
||||
| 认证次数 | 1次(仅 Gateway) | N次(每个服务) |
|
||||
| 性能 | ⭐⭐⭐⭐⭐ 最优 | ⭐⭐⭐ 一般 |
|
||||
| 维护性 | ⭐⭐⭐⭐⭐ 统一管理 | ⭐⭐⭐ 分散管理 |
|
||||
| 安全性 | ⭐⭐⭐⭐ 需内网隔离 | ⭐⭐⭐⭐⭐ 多层防护 |
|
||||
| 推荐场景 | 内网微服务架构 | 微服务对外暴露 |
|
||||
|
||||
**推荐使用 Gateway 统一认证模式!**
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
-- 删除已存在的数据库(如果存在)
|
||||
DROP DATABASE IF EXISTS urban-lifeline;
|
||||
DROP DATABASE IF EXISTS urban_lifeline;
|
||||
|
||||
-- 创建新数据库,使用 UTF8 编码,并设置适合中文的排序规则
|
||||
-- 使用 template0 确保干净的数据库模板
|
||||
-- zh_CN.UTF-8 支持中文字符排序和比较
|
||||
CREATE DATABASE urban-lifeline
|
||||
CREATE DATABASE urban_lifeline
|
||||
ENCODING 'UTF8'
|
||||
TEMPLATE template0
|
||||
LC_COLLATE 'zh_CN.UTF-8'
|
||||
|
||||
@@ -1,308 +1,306 @@
|
||||
-- =============================
|
||||
-- 智能体管理和平台基础设施模块
|
||||
-- 支持:智能体广场、API集成管理、智能体运维监控
|
||||
-- =============================
|
||||
CREATE SCHEMA IF NOT EXISTS agent;
|
||||
-- -- =============================
|
||||
-- -- 智能体管理和平台基础设施模块
|
||||
-- -- 支持:智能体广场、API集成管理、智能体运维监控
|
||||
-- -- =============================
|
||||
-- CREATE SCHEMA IF NOT EXISTS agent;
|
||||
|
||||
-- 智能体定义表
|
||||
DROP TABLE IF EXISTS agent.tb_agent CASCADE;
|
||||
CREATE TABLE agent.tb_agent (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
agent_code VARCHAR(100) NOT NULL, -- 智能体编码(唯一标识)
|
||||
agent_name VARCHAR(255) NOT NULL, -- 智能体名称
|
||||
agent_type VARCHAR(50) NOT NULL, -- 智能体类型:bidding-招投标/customer_service-客服/knowledge_assistant-知识助手/custom-自定义
|
||||
display_name VARCHAR(255) NOT NULL, -- 展示名称
|
||||
description TEXT, -- 智能体描述
|
||||
icon VARCHAR(500), -- 图标URL
|
||||
banner VARCHAR(500), -- Banner图URL
|
||||
version VARCHAR(20) DEFAULT '1.0.0', -- 版本号
|
||||
model_provider VARCHAR(50), -- 模型提供商:openai/anthropic/baidu/aliyun/custom
|
||||
model_name VARCHAR(100), -- 模型名称
|
||||
model_config JSONB, -- 模型配置(温度、最大tokens等)
|
||||
prompt_template TEXT, -- 提示词模板
|
||||
system_prompt TEXT, -- 系统提示词
|
||||
kb_ids VARCHAR(50)[], -- 关联知识库ID数组
|
||||
tool_ids VARCHAR(50)[], -- 关联工具ID数组
|
||||
capabilities TEXT[], -- 能力列表
|
||||
access_level VARCHAR(20) DEFAULT 'private', -- 访问级别:public-公开/private-私有/internal-内部
|
||||
is_published BOOLEAN DEFAULT false, -- 是否发布到智能体广场
|
||||
usage_count INTEGER DEFAULT 0, -- 使用次数
|
||||
rating DECIMAL(3,2) DEFAULT 0, -- 评分(0-5)
|
||||
rating_count INTEGER DEFAULT 0, -- 评分人数
|
||||
tags TEXT[], -- 标签数组
|
||||
category VARCHAR(100), -- 分类
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
owner_user_id VARCHAR(50), -- 所有者用户ID
|
||||
status VARCHAR(20) DEFAULT 'active', -- 状态:active-激活/inactive-停用/under_maintenance-维护中
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (agent_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (agent_code)
|
||||
);
|
||||
-- -- 智能体定义表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- agent_code VARCHAR(100) NOT NULL, -- 智能体编码(唯一标识)
|
||||
-- agent_name VARCHAR(255) NOT NULL, -- 智能体名称
|
||||
-- agent_type VARCHAR(50) NOT NULL, -- 智能体类型:bidding-招投标/customer_service-客服/knowledge_assistant-知识助手/custom-自定义
|
||||
-- display_name VARCHAR(255) NOT NULL, -- 展示名称
|
||||
-- description TEXT, -- 智能体描述
|
||||
-- icon VARCHAR(500), -- 图标URL
|
||||
-- banner VARCHAR(500), -- Banner图URL
|
||||
-- version VARCHAR(20) DEFAULT '1.0.0', -- 版本号
|
||||
-- model_provider VARCHAR(50), -- 模型提供商:openai/anthropic/baidu/aliyun/custom
|
||||
-- model_name VARCHAR(100), -- 模型名称
|
||||
-- model_config JSONB, -- 模型配置(温度、最大tokens等)
|
||||
-- prompt_template TEXT, -- 提示词模板
|
||||
-- system_prompt TEXT, -- 系统提示词
|
||||
-- capabilities TEXT[], -- 能力列表
|
||||
-- access_level VARCHAR(20) DEFAULT 'private', -- 访问级别:public-公开/private-私有/internal-内部
|
||||
-- is_published BOOLEAN DEFAULT false, -- 是否发布到智能体广场
|
||||
-- usage_count INTEGER DEFAULT 0, -- 使用次数
|
||||
-- rating DECIMAL(3,2) DEFAULT 0, -- 评分(0-5)
|
||||
-- rating_count INTEGER DEFAULT 0, -- 评分人数
|
||||
-- tags TEXT[], -- 标签数组
|
||||
-- category VARCHAR(100), -- 分类
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- owner_user_id VARCHAR(50), -- 所有者用户ID
|
||||
-- status VARCHAR(20) DEFAULT 'active', -- 状态:active-激活/inactive-停用/under_maintenance-维护中
|
||||
-- creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
-- updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
-- delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (agent_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- UNIQUE (agent_code)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_agent_type ON agent.tb_agent(agent_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_agent_published ON agent.tb_agent(is_published) WHERE deleted = false AND is_published = true;
|
||||
CREATE INDEX idx_agent_category ON agent.tb_agent(category) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_agent_type ON agent.tb_agent(agent_type) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_agent_published ON agent.tb_agent(is_published) WHERE deleted = false AND is_published = true;
|
||||
-- CREATE INDEX idx_agent_category ON agent.tb_agent(category) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent IS '智能体定义表';
|
||||
COMMENT ON COLUMN agent.tb_agent.agent_type IS '智能体类型:bidding/customer_service/knowledge_assistant/custom';
|
||||
-- COMMENT ON TABLE agent.tb_agent IS '智能体定义表';
|
||||
-- COMMENT ON COLUMN agent.tb_agent.agent_type IS '智能体类型:bidding/customer_service/knowledge_assistant/custom';
|
||||
|
||||
-- 智能体会话表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_session CASCADE;
|
||||
CREATE TABLE agent.tb_agent_session (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
session_id VARCHAR(50) NOT NULL, -- 会话ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
session_type VARCHAR(30) DEFAULT 'chat', -- 会话类型:chat-对话/task-任务/workflow-工作流
|
||||
session_name VARCHAR(255), -- 会话名称
|
||||
context JSONB, -- 会话上下文
|
||||
session_status VARCHAR(20) DEFAULT 'active', -- 会话状态:active-活跃/paused-暂停/ended-结束
|
||||
start_time timestamptz DEFAULT now(), -- 开始时间
|
||||
end_time timestamptz, -- 结束时间
|
||||
message_count INTEGER DEFAULT 0, -- 消息数量
|
||||
token_usage INTEGER DEFAULT 0, -- Token使用量
|
||||
cost DECIMAL(10,4) DEFAULT 0, -- 成本
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (session_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
);
|
||||
-- -- 智能体会话表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_session CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_session (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- session_id VARCHAR(50) NOT NULL, -- 会话ID
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
-- session_type VARCHAR(30) DEFAULT 'chat', -- 会话类型:chat-对话/task-任务/workflow-工作流
|
||||
-- session_name VARCHAR(255), -- 会话名称
|
||||
-- context JSONB, -- 会话上下文
|
||||
-- session_status VARCHAR(20) DEFAULT 'active', -- 会话状态:active-活跃/paused-暂停/ended-结束
|
||||
-- start_time TIMESTAMPTZ DEFAULT now(), -- 开始时间
|
||||
-- end_time TIMESTAMPTZ, -- 结束时间
|
||||
-- message_count INTEGER DEFAULT 0, -- 消息数量
|
||||
-- token_usage INTEGER DEFAULT 0, -- Token使用量
|
||||
-- cost DECIMAL(10,4) DEFAULT 0, -- 成本
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (session_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_session_agent ON agent.tb_agent_session(agent_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_session_user ON agent.tb_agent_session(user_id) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_session_agent ON agent.tb_agent_session(agent_id) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_session_user ON agent.tb_agent_session(user_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_session IS '智能体会话表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_session IS '智能体会话表';
|
||||
|
||||
-- 智能体消息表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_message CASCADE;
|
||||
CREATE TABLE agent.tb_agent_message (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
message_id VARCHAR(50) NOT NULL, -- 消息ID
|
||||
session_id VARCHAR(50) NOT NULL, -- 会话ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
role VARCHAR(20) NOT NULL, -- 角色:user-用户/assistant-助手/system-系统/function-函数
|
||||
content TEXT, -- 消息内容
|
||||
content_type VARCHAR(30) DEFAULT 'text', -- 内容类型:text-文本/image-图片/file-文件/structured-结构化数据
|
||||
function_call JSONB, -- 函数调用(JSON格式)
|
||||
function_response JSONB, -- 函数响应
|
||||
token_count INTEGER, -- Token数量
|
||||
model_name VARCHAR(100), -- 使用的模型
|
||||
kb_references JSONB, -- 知识库引用(JSON数组)
|
||||
metadata JSONB, -- 消息元数据
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (message_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (session_id) REFERENCES agent.tb_agent_session(session_id),
|
||||
FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
);
|
||||
-- -- 智能体消息表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_message CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_message (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- message_id VARCHAR(50) NOT NULL, -- 消息ID
|
||||
-- session_id VARCHAR(50) NOT NULL, -- 会话ID
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- role VARCHAR(20) NOT NULL, -- 角色:user-用户/assistant-助手/system-系统/function-函数
|
||||
-- content TEXT, -- 消息内容
|
||||
-- content_type VARCHAR(30) DEFAULT 'text', -- 内容类型:text-文本/image-图片/file-文件/structured-结构化数据
|
||||
-- function_call JSONB, -- 函数调用(JSON格式)
|
||||
-- function_response JSONB, -- 函数响应
|
||||
-- token_count INTEGER, -- Token数量
|
||||
-- model_name VARCHAR(100), -- 使用的模型
|
||||
-- kb_references JSONB, -- 知识库引用(JSON数组)
|
||||
-- metadata JSONB, -- 消息元数据
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (message_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- FOREIGN KEY (session_id) REFERENCES agent.tb_agent_session(session_id),
|
||||
-- FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_msg_session ON agent.tb_agent_message(session_id, create_time) WHERE deleted = false;
|
||||
CREATE INDEX idx_msg_agent ON agent.tb_agent_message(agent_id) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_msg_session ON agent.tb_agent_message(session_id, create_time) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_msg_agent ON agent.tb_agent_message(agent_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_message IS '智能体消息表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_message IS '智能体消息表';
|
||||
|
||||
-- 智能体工具表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_tool CASCADE;
|
||||
CREATE TABLE agent.tb_agent_tool (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
tool_id VARCHAR(50) NOT NULL, -- 工具ID
|
||||
tool_code VARCHAR(100) NOT NULL, -- 工具编码
|
||||
tool_name VARCHAR(255) NOT NULL, -- 工具名称
|
||||
tool_type VARCHAR(50) NOT NULL, -- 工具类型:api-API调用/function-函数/plugin-插件/integration-集成
|
||||
description TEXT, -- 工具描述
|
||||
function_schema JSONB, -- 函数Schema(OpenAI function calling格式)
|
||||
api_endpoint VARCHAR(500), -- API端点
|
||||
api_method VARCHAR(10), -- API方法:GET/POST/PUT/DELETE
|
||||
api_headers JSONB, -- API请求头
|
||||
auth_type VARCHAR(30), -- 认证类型:none/api_key/oauth2/bearer
|
||||
auth_config JSONB, -- 认证配置(加密存储)
|
||||
request_template TEXT, -- 请求模板
|
||||
response_template TEXT, -- 响应模板
|
||||
timeout_seconds INTEGER DEFAULT 30, -- 超时时间(秒)
|
||||
retry_count INTEGER DEFAULT 3, -- 重试次数
|
||||
is_enabled BOOLEAN DEFAULT true, -- 是否启用
|
||||
usage_count INTEGER DEFAULT 0, -- 使用次数
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (tool_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (tool_code)
|
||||
);
|
||||
-- -- 智能体工具表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_tool CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_tool (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- tool_id VARCHAR(50) NOT NULL, -- 工具ID
|
||||
-- tool_code VARCHAR(100) NOT NULL, -- 工具编码
|
||||
-- tool_name VARCHAR(255) NOT NULL, -- 工具名称
|
||||
-- tool_type VARCHAR(50) NOT NULL, -- 工具类型:api-API调用/function-函数/plugin-插件/integration-集成
|
||||
-- description TEXT, -- 工具描述
|
||||
-- function_schema JSONB, -- 函数Schema(OpenAI function calling格式)
|
||||
-- api_endpoint VARCHAR(500), -- API端点
|
||||
-- api_method VARCHAR(10), -- API方法:GET/POST/PUT/DELETE
|
||||
-- api_headers JSONB, -- API请求头
|
||||
-- auth_type VARCHAR(30), -- 认证类型:none/api_key/oauth2/bearer
|
||||
-- auth_config JSONB, -- 认证配置(加密存储)
|
||||
-- request_template TEXT, -- 请求模板
|
||||
-- response_template TEXT, -- 响应模板
|
||||
-- timeout_seconds INTEGER DEFAULT 30, -- 超时时间(秒)
|
||||
-- retry_count INTEGER DEFAULT 3, -- 重试次数
|
||||
-- is_enabled BOOLEAN DEFAULT true, -- 是否启用
|
||||
-- usage_count INTEGER DEFAULT 0, -- 使用次数
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
-- updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
-- delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (tool_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- UNIQUE (tool_code)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_tool_type ON agent.tb_agent_tool(tool_type) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_tool_type ON agent.tb_agent_tool(tool_type) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_tool IS '智能体工具表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_tool IS '智能体工具表';
|
||||
|
||||
-- API集成注册表
|
||||
DROP TABLE IF EXISTS agent.tb_api_integration CASCADE;
|
||||
CREATE TABLE agent.tb_api_integration (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
integration_id VARCHAR(50) NOT NULL, -- 集成ID
|
||||
integration_name VARCHAR(255) NOT NULL, -- 集成名称
|
||||
integration_type VARCHAR(50) NOT NULL, -- 集成类型:rest_api/soap/graphql/webhook/mq
|
||||
provider VARCHAR(100), -- 提供商
|
||||
base_url VARCHAR(500), -- 基础URL
|
||||
version VARCHAR(20), -- API版本
|
||||
auth_type VARCHAR(30) DEFAULT 'none', -- 认证类型
|
||||
auth_config JSONB, -- 认证配置(加密存储)
|
||||
endpoints JSONB, -- 端点列表(JSON数组)
|
||||
rate_limit INTEGER, -- 速率限制(请求/秒)
|
||||
timeout_seconds INTEGER DEFAULT 30, -- 超时时间
|
||||
retry_config JSONB, -- 重试配置
|
||||
health_check_url VARCHAR(500), -- 健康检查URL
|
||||
health_status VARCHAR(20) DEFAULT 'unknown', -- 健康状态:healthy-健康/unhealthy-不健康/unknown-未知
|
||||
last_health_check timestamptz, -- 最后健康检查时间
|
||||
documentation_url VARCHAR(500), -- 文档URL
|
||||
is_enabled BOOLEAN DEFAULT true, -- 是否启用
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (integration_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
-- -- API集成注册表
|
||||
-- DROP TABLE IF EXISTS agent.tb_api_integration CASCADE;
|
||||
-- CREATE TABLE agent.tb_api_integration (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- integration_id VARCHAR(50) NOT NULL, -- 集成ID
|
||||
-- integration_name VARCHAR(255) NOT NULL, -- 集成名称
|
||||
-- integration_type VARCHAR(50) NOT NULL, -- 集成类型:rest_api/soap/graphql/webhook/mq
|
||||
-- provider VARCHAR(100), -- 提供商
|
||||
-- base_url VARCHAR(500), -- 基础URL
|
||||
-- version VARCHAR(20), -- API版本
|
||||
-- auth_type VARCHAR(30) DEFAULT 'none', -- 认证类型
|
||||
-- auth_config JSONB, -- 认证配置(加密存储)
|
||||
-- endpoints JSONB, -- 端点列表(JSON数组)
|
||||
-- rate_limit INTEGER, -- 速率限制(请求/秒)
|
||||
-- timeout_seconds INTEGER DEFAULT 30, -- 超时时间
|
||||
-- retry_config JSONB, -- 重试配置
|
||||
-- health_check_url VARCHAR(500), -- 健康检查URL
|
||||
-- health_status VARCHAR(20) DEFAULT 'unknown', -- 健康状态:healthy-健康/unhealthy-不健康/unknown-未知
|
||||
-- last_health_check TIMESTAMPTZ, -- 最后健康检查时间
|
||||
-- documentation_url VARCHAR(500), -- 文档URL
|
||||
-- is_enabled BOOLEAN DEFAULT true, -- 是否启用
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
-- updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
-- delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (integration_id),
|
||||
-- UNIQUE (optsn)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_integration_type ON agent.tb_api_integration(integration_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_integration_health ON agent.tb_api_integration(health_status) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_integration_type ON agent.tb_api_integration(integration_type) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_integration_health ON agent.tb_api_integration(health_status) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_api_integration IS 'API集成注册表';
|
||||
-- COMMENT ON TABLE agent.tb_api_integration IS 'API集成注册表';
|
||||
|
||||
-- API调用日志表
|
||||
DROP TABLE IF EXISTS agent.tb_api_call_log CASCADE;
|
||||
CREATE TABLE agent.tb_api_call_log (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
integration_id VARCHAR(50), -- 集成ID
|
||||
tool_id VARCHAR(50), -- 工具ID
|
||||
agent_id VARCHAR(50), -- 智能体ID
|
||||
session_id VARCHAR(50), -- 会话ID
|
||||
user_id VARCHAR(50), -- 用户ID
|
||||
endpoint VARCHAR(500) NOT NULL, -- 请求端点
|
||||
method VARCHAR(10) NOT NULL, -- 请求方法
|
||||
request_headers JSONB, -- 请求头
|
||||
request_body TEXT, -- 请求体
|
||||
response_status INTEGER, -- 响应状态码
|
||||
response_headers JSONB, -- 响应头
|
||||
response_body TEXT, -- 响应体
|
||||
duration_ms INTEGER, -- 请求耗时(毫秒)
|
||||
is_success BOOLEAN, -- 是否成功
|
||||
error_message TEXT, -- 错误信息
|
||||
retry_count INTEGER DEFAULT 0, -- 重试次数
|
||||
ip_address VARCHAR(45), -- IP地址
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
PRIMARY KEY (log_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
-- -- API调用日志表
|
||||
-- DROP TABLE IF EXISTS agent.tb_api_call_log CASCADE;
|
||||
-- CREATE TABLE agent.tb_api_call_log (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
-- integration_id VARCHAR(50), -- 集成ID
|
||||
-- tool_id VARCHAR(50), -- 工具ID
|
||||
-- agent_id VARCHAR(50), -- 智能体ID
|
||||
-- session_id VARCHAR(50), -- 会话ID
|
||||
-- user_id VARCHAR(50), -- 用户ID
|
||||
-- endpoint VARCHAR(500) NOT NULL, -- 请求端点
|
||||
-- method VARCHAR(10) NOT NULL, -- 请求方法
|
||||
-- request_headers JSONB, -- 请求头
|
||||
-- request_body TEXT, -- 请求体
|
||||
-- response_status INTEGER, -- 响应状态码
|
||||
-- response_headers JSONB, -- 响应头
|
||||
-- response_body TEXT, -- 响应体
|
||||
-- duration_ms INTEGER, -- 请求耗时(毫秒)
|
||||
-- is_success BOOLEAN, -- 是否成功
|
||||
-- error_message TEXT, -- 错误信息
|
||||
-- retry_count INTEGER DEFAULT 0, -- 重试次数
|
||||
-- ip_address VARCHAR(45), -- IP地址
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- PRIMARY KEY (log_id),
|
||||
-- UNIQUE (optsn)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_api_log_integration ON agent.tb_api_call_log(integration_id, create_time DESC);
|
||||
CREATE INDEX idx_api_log_agent ON agent.tb_api_call_log(agent_id, create_time DESC);
|
||||
CREATE INDEX idx_api_log_status ON agent.tb_api_call_log(is_success, create_time DESC);
|
||||
-- CREATE INDEX idx_api_log_integration ON agent.tb_api_call_log(integration_id, create_time DESC);
|
||||
-- CREATE INDEX idx_api_log_agent ON agent.tb_api_call_log(agent_id, create_time DESC);
|
||||
-- CREATE INDEX idx_api_log_status ON agent.tb_api_call_log(is_success, create_time DESC);
|
||||
|
||||
COMMENT ON TABLE agent.tb_api_call_log IS 'API调用日志表';
|
||||
-- COMMENT ON TABLE agent.tb_api_call_log IS 'API调用日志表';
|
||||
|
||||
-- 智能体监控指标表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_metrics CASCADE;
|
||||
CREATE TABLE agent.tb_agent_metrics (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
metric_id VARCHAR(50) NOT NULL, -- 指标ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
metric_date DATE NOT NULL, -- 指标日期
|
||||
metric_hour INTEGER, -- 指标小时(0-23)
|
||||
total_sessions INTEGER DEFAULT 0, -- 总会话数
|
||||
active_sessions INTEGER DEFAULT 0, -- 活跃会话数
|
||||
total_messages INTEGER DEFAULT 0, -- 总消息数
|
||||
total_tokens BIGINT DEFAULT 0, -- 总Token数
|
||||
total_cost DECIMAL(10,4) DEFAULT 0, -- 总成本
|
||||
avg_response_time INTEGER, -- 平均响应时间(毫秒)
|
||||
success_rate DECIMAL(5,4), -- 成功率
|
||||
error_count INTEGER DEFAULT 0, -- 错误次数
|
||||
api_call_count INTEGER DEFAULT 0, -- API调用次数
|
||||
avg_rating DECIMAL(3,2), -- 平均评分
|
||||
rating_count INTEGER DEFAULT 0, -- 评分数量
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
PRIMARY KEY (metric_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (agent_id, metric_date, metric_hour),
|
||||
FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
);
|
||||
-- -- 智能体监控指标表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_metrics CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_metrics (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- metric_id VARCHAR(50) NOT NULL, -- 指标ID
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- metric_date DATE NOT NULL, -- 指标日期
|
||||
-- metric_hour INTEGER, -- 指标小时(0-23)
|
||||
-- total_sessions INTEGER DEFAULT 0, -- 总会话数
|
||||
-- active_sessions INTEGER DEFAULT 0, -- 活跃会话数
|
||||
-- total_messages INTEGER DEFAULT 0, -- 总消息数
|
||||
-- total_tokens BIGINT DEFAULT 0, -- 总Token数
|
||||
-- total_cost DECIMAL(10,4) DEFAULT 0, -- 总成本
|
||||
-- avg_response_time INTEGER, -- 平均响应时间(毫秒)
|
||||
-- success_rate DECIMAL(5,4), -- 成功率
|
||||
-- error_count INTEGER DEFAULT 0, -- 错误次数
|
||||
-- api_call_count INTEGER DEFAULT 0, -- API调用次数
|
||||
-- avg_rating DECIMAL(3,2), -- 平均评分
|
||||
-- rating_count INTEGER DEFAULT 0, -- 评分数量
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
-- PRIMARY KEY (metric_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- UNIQUE (agent_id, metric_date, metric_hour),
|
||||
-- FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_metrics_agent_date ON agent.tb_agent_metrics(agent_id, metric_date DESC);
|
||||
-- CREATE INDEX idx_metrics_agent_date ON agent.tb_agent_metrics(agent_id, metric_date DESC);
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_metrics IS '智能体监控指标表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_metrics IS '智能体监控指标表';
|
||||
|
||||
-- 智能体异常日志表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_error_log CASCADE;
|
||||
CREATE TABLE agent.tb_agent_error_log (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
session_id VARCHAR(50), -- 会话ID
|
||||
error_type VARCHAR(50) NOT NULL, -- 错误类型:model_error-模型错误/api_error-API错误/timeout-超时/rate_limit-限流/other-其他
|
||||
error_code VARCHAR(50), -- 错误代码
|
||||
error_message TEXT NOT NULL, -- 错误信息
|
||||
stack_trace TEXT, -- 堆栈跟踪
|
||||
request_context JSONB, -- 请求上下文
|
||||
severity VARCHAR(20) DEFAULT 'error', -- 严重级别:critical-致命/error-错误/warning-警告
|
||||
is_resolved BOOLEAN DEFAULT false, -- 是否已解决
|
||||
resolution_notes TEXT, -- 解决方案备注
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
resolve_time timestamptz, -- 解决时间
|
||||
PRIMARY KEY (log_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
);
|
||||
-- -- 智能体异常日志表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_error_log CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_error_log (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- session_id VARCHAR(50), -- 会话ID
|
||||
-- error_type VARCHAR(50) NOT NULL, -- 错误类型:model_error-模型错误/api_error-API错误/timeout-超时/rate_limit-限流/other-其他
|
||||
-- error_code VARCHAR(50), -- 错误代码
|
||||
-- error_message TEXT NOT NULL, -- 错误信息
|
||||
-- stack_trace TEXT, -- 堆栈跟踪
|
||||
-- request_context JSONB, -- 请求上下文
|
||||
-- severity VARCHAR(20) DEFAULT 'error', -- 严重级别:critical-致命/error-错误/warning-警告
|
||||
-- is_resolved BOOLEAN DEFAULT false, -- 是否已解决
|
||||
-- resolution_notes TEXT, -- 解决方案备注
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- resolve_time TIMESTAMPTZ, -- 解决时间
|
||||
-- PRIMARY KEY (log_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_error_agent ON agent.tb_agent_error_log(agent_id, create_time DESC);
|
||||
CREATE INDEX idx_error_severity ON agent.tb_agent_error_log(severity) WHERE is_resolved = false;
|
||||
-- CREATE INDEX idx_error_agent ON agent.tb_agent_error_log(agent_id, create_time DESC);
|
||||
-- CREATE INDEX idx_error_severity ON agent.tb_agent_error_log(severity) WHERE is_resolved = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_error_log IS '智能体异常日志表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_error_log IS '智能体异常日志表';
|
||||
|
||||
-- 智能体评价表
|
||||
DROP TABLE IF EXISTS agent.tb_agent_rating CASCADE;
|
||||
CREATE TABLE agent.tb_agent_rating (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
rating_id VARCHAR(50) NOT NULL, -- 评价ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
session_id VARCHAR(50), -- 会话ID
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
rating INTEGER NOT NULL, -- 评分(1-5星)
|
||||
dimensions JSONB, -- 分维度评分(准确性、速度、友好度等)
|
||||
feedback TEXT, -- 评价反馈
|
||||
tags TEXT[], -- 标签
|
||||
is_anonymous BOOLEAN DEFAULT false, -- 是否匿名
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (rating_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
);
|
||||
-- -- 智能体评价表
|
||||
-- DROP TABLE IF EXISTS agent.tb_agent_rating CASCADE;
|
||||
-- CREATE TABLE agent.tb_agent_rating (
|
||||
-- optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
-- rating_id VARCHAR(50) NOT NULL, -- 评价ID
|
||||
-- agent_id VARCHAR(50) NOT NULL, -- 智能体ID
|
||||
-- session_id VARCHAR(50), -- 会话ID
|
||||
-- user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
-- rating INTEGER NOT NULL, -- 评分(1-5星)
|
||||
-- dimensions JSONB, -- 分维度评分(准确性、速度、友好度等)
|
||||
-- feedback TEXT, -- 评价反馈
|
||||
-- tags TEXT[], -- 标签
|
||||
-- is_anonymous BOOLEAN DEFAULT false, -- 是否匿名
|
||||
-- dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
-- create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
-- deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
-- PRIMARY KEY (rating_id),
|
||||
-- UNIQUE (optsn),
|
||||
-- FOREIGN KEY (agent_id) REFERENCES agent.tb_agent(agent_id)
|
||||
-- );
|
||||
|
||||
CREATE INDEX idx_rating_agent ON agent.tb_agent_rating(agent_id) WHERE deleted = false;
|
||||
-- CREATE INDEX idx_rating_agent ON agent.tb_agent_rating(agent_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE agent.tb_agent_rating IS '智能体评价表';
|
||||
-- COMMENT ON TABLE agent.tb_agent_rating IS '智能体评价表';
|
||||
|
||||
@@ -55,59 +55,6 @@ CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- GIN索引支持
|
||||
-- =============================
|
||||
\i createTableAgent.sql
|
||||
|
||||
-- =============================
|
||||
-- 创建通用触发器函数
|
||||
-- =============================
|
||||
|
||||
-- 自动更新update_time的触发器函数
|
||||
CREATE OR REPLACE FUNCTION public.update_modified_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.update_time = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 为所有表添加update_time触发器的辅助函数
|
||||
CREATE OR REPLACE FUNCTION public.create_update_triggers()
|
||||
RETURNS void AS $$
|
||||
DECLARE
|
||||
r RECORD;
|
||||
BEGIN
|
||||
FOR r IN
|
||||
SELECT schemaname, tablename
|
||||
FROM pg_tables
|
||||
WHERE schemaname IN ('sys', 'file', 'message', 'log', 'config', 'knowledge', 'bidding', 'customer_service', 'agent')
|
||||
AND tablename LIKE 'tb_%'
|
||||
LOOP
|
||||
-- 检查表是否有update_time列
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = r.schemaname
|
||||
AND table_name = r.tablename
|
||||
AND column_name = 'update_time'
|
||||
) THEN
|
||||
-- 删除已存在的触发器
|
||||
EXECUTE format('DROP TRIGGER IF EXISTS trg_%s_update_time ON %I.%I',
|
||||
r.tablename, r.schemaname, r.tablename);
|
||||
|
||||
-- 创建新触发器
|
||||
EXECUTE format('CREATE TRIGGER trg_%s_update_time
|
||||
BEFORE UPDATE ON %I.%I
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.update_modified_column()',
|
||||
r.tablename, r.schemaname, r.tablename);
|
||||
|
||||
RAISE NOTICE 'Created trigger for %.%', r.schemaname, r.tablename;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 执行触发器创建
|
||||
SELECT public.create_update_triggers();
|
||||
|
||||
-- =============================
|
||||
-- 创建视图
|
||||
-- =============================
|
||||
|
||||
@@ -15,9 +15,9 @@ CREATE TABLE bidding.tb_bidding_project (
|
||||
industry VARCHAR(100), -- 所属行业
|
||||
source_platform VARCHAR(100), -- 来源平台(如:政府采购网、企业官网等)
|
||||
source_url VARCHAR(500), -- 来源URL
|
||||
publish_date timestamptz, -- 发布日期
|
||||
deadline timestamptz, -- 投标截止日期
|
||||
opening_date timestamptz, -- 开标日期
|
||||
publish_date TIMESTAMPTZ, -- 发布日期
|
||||
deadline TIMESTAMPTZ, -- 投标截止日期
|
||||
opening_date TIMESTAMPTZ, -- 开标日期
|
||||
budget_amount DECIMAL(18,2), -- 预算金额
|
||||
currency VARCHAR(10) DEFAULT 'CNY', -- 货币单位
|
||||
project_status VARCHAR(30) NOT NULL DEFAULT 'collecting', -- 项目状态:collecting-收集中/analyzing-分析中/preparing-准备投标/submitted-已提交/opened-已开标/won-中标/lost-未中标/abandoned-放弃
|
||||
@@ -35,9 +35,9 @@ CREATE TABLE bidding.tb_bidding_project (
|
||||
team_members VARCHAR(50)[], -- 团队成员数组
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (project_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -71,13 +71,13 @@ CREATE TABLE bidding.tb_bidding_document (
|
||||
parse_result JSONB, -- 解析结果(JSON格式:提取的要素、表格、图纸等)
|
||||
extraction_data JSONB, -- 提取的结构化数据
|
||||
ai_analysis TEXT, -- AI分析结果
|
||||
upload_date timestamptz DEFAULT now(), -- 上传日期
|
||||
upload_date TIMESTAMPTZ DEFAULT now(), -- 上传日期
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (doc_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -113,9 +113,9 @@ CREATE TABLE bidding.tb_bidding_requirement (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (req_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -151,9 +151,9 @@ CREATE TABLE bidding.tb_bid_response (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (response_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -186,9 +186,9 @@ CREATE TABLE bidding.tb_bidding_scoring_rule (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (rule_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -209,10 +209,10 @@ CREATE TABLE bidding.tb_bidding_process (
|
||||
node_type VARCHAR(50) NOT NULL, -- 节点类型:collection-文件收集/analysis-需求分析/preparation-文件准备/review-内部审核/submission-投标提交/opening-开标/result-结果通知
|
||||
node_order INTEGER NOT NULL, -- 节点顺序
|
||||
node_status VARCHAR(30) DEFAULT 'pending', -- 节点状态:pending-待处理/in_progress-进行中/completed-已完成/skipped-已跳过
|
||||
planned_start_time timestamptz, -- 计划开始时间
|
||||
planned_end_time timestamptz, -- 计划结束时间
|
||||
actual_start_time timestamptz, -- 实际开始时间
|
||||
actual_end_time timestamptz, -- 实际结束时间
|
||||
planned_start_time TIMESTAMPTZ, -- 计划开始时间
|
||||
planned_end_time TIMESTAMPTZ, -- 计划结束时间
|
||||
actual_start_time TIMESTAMPTZ, -- 实际开始时间
|
||||
actual_end_time TIMESTAMPTZ, -- 实际结束时间
|
||||
responsible_user VARCHAR(50), -- 负责人
|
||||
participants VARCHAR(50)[], -- 参与人员数组
|
||||
notes TEXT, -- 节点备注
|
||||
@@ -220,9 +220,9 @@ CREATE TABLE bidding.tb_bidding_process (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (process_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -251,9 +251,9 @@ CREATE TABLE bidding.tb_bid_template (
|
||||
status VARCHAR(20) DEFAULT 'active', -- 状态:active-激活/inactive-停用
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (template_id),
|
||||
UNIQUE (optsn)
|
||||
|
||||
@@ -6,12 +6,12 @@ CREATE TABLE config.tb_sys_config (
|
||||
key VARCHAR(255) NOT NULL, -- 配置键
|
||||
name VARCHAR(255) NOT NULL, -- 配置名称
|
||||
value VARCHAR(255) NOT NULL, -- 配置值
|
||||
config_type VARCHAR(50) NOT NULL, -- 数据类型(String, Integer, Boolean, Float, Double)
|
||||
config_type VARCHAR(50) NOT NULL, -- 数据类型(String, INTEGER, BOOLEAN, Float, Double)
|
||||
render_type VARCHAR(50) NOT NULL, -- 配置渲染类型(select, input, textarea, checkbox, radio, switch)
|
||||
description VARCHAR(255) NOT NULL, -- 配置描述
|
||||
re JSON DEFAULT NULL, -- 正则表达式校验规则
|
||||
options JSON DEFAULT NULL, -- 可选项,render_type为select、checkbox、radio时使用
|
||||
group VARCHAR(255) NOT NULL, -- 配置组
|
||||
"group" VARCHAR(255) NOT NULL, -- 配置组
|
||||
module_id VARCHAR(255) NOT NULL, -- 模块id
|
||||
order_num INT NOT NULL, -- 配置顺序
|
||||
status INT NOT NULL DEFAULT 0, -- 配置状态 0:启用 1:禁用
|
||||
@@ -19,9 +19,9 @@ CREATE TABLE config.tb_sys_config (
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径,支持like递归(如/1/2/3/)
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 配置创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 配置更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 配置删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 配置创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 配置更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 配置删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (config_id),
|
||||
UNIQUE (optsn)
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
-- ====================================================
|
||||
-- 定时任务表
|
||||
-- ====================================================
|
||||
CREATE SCHEMA IF NOT EXISTS crontab;
|
||||
DROP TABLE IF EXISTS crontab.tb_crontab_task CASCADE;
|
||||
CREATE TABLE crontab.tb_crontab_task (
|
||||
id VARCHAR(64) NOT NULL,
|
||||
task_id VARCHAR(64) NOT NULL,
|
||||
task_name VARCHAR(100) NOT NULL,
|
||||
task_group VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',
|
||||
meta_id VARCHAR(64) NOT NULL,
|
||||
default_recipient SMALLINT NOT NULL DEFAULT 0, -- 是否使用默认接收人(0:否 1:是)
|
||||
bean_name VARCHAR(100) NOT NULL,
|
||||
method_name VARCHAR(100) NOT NULL,
|
||||
method_params VARCHAR(500) DEFAULT NULL,
|
||||
cron_expression VARCHAR(100) NOT NULL,
|
||||
status SMALLINT NOT NULL DEFAULT 0, -- 任务状态(0:暂停 1:运行中)
|
||||
description VARCHAR(500) DEFAULT NULL,
|
||||
concurrent SMALLINT NOT NULL DEFAULT 0, -- 是否允许并发执行(0:否 1:是)
|
||||
misfire_policy SMALLINT NOT NULL DEFAULT 1, -- 错过执行策略(1:立即执行 2:执行一次 3:放弃执行)
|
||||
creator VARCHAR(64) DEFAULT NULL,
|
||||
updater VARCHAR(64) DEFAULT NULL,
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
update_time TIMESTAMPTZ DEFAULT NULL,
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是)
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_task_name ON crontab.tb_crontab_task(task_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_bean_name ON crontab.tb_crontab_task(bean_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_status ON crontab.tb_crontab_task(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_deleted ON crontab.tb_crontab_task(deleted);
|
||||
|
||||
COMMENT ON TABLE crontab.tb_crontab_task IS '定时任务配置表';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.id IS '主键ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.task_id IS '任务ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.task_name IS '任务名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.task_group IS '任务分组';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.meta_id IS '任务元数据ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.default_recipient IS '是否使用默认接收人(0:否 1:是)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.bean_name IS 'Bean名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.method_name IS '方法名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.method_params IS '方法参数';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.cron_expression IS 'Cron表达式';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.status IS '任务状态(0:暂停 1:运行中)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.description IS '任务描述';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.concurrent IS '是否允许并发执行(0:否 1:是)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.misfire_policy IS '错过执行策略(1:立即执行 2:执行一次 3:放弃执行)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.creator IS '创建者';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.updater IS '更新者';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task.deleted IS '是否删除(0:否 1:是)';
|
||||
|
||||
-- ====================================================
|
||||
-- 定时任务执行日志表
|
||||
-- ====================================================
|
||||
DROP TABLE IF EXISTS crontab.tb_crontab_log CASCADE;
|
||||
CREATE TABLE crontab.tb_crontab_log (
|
||||
id VARCHAR(64) NOT NULL,
|
||||
task_id VARCHAR(64) NOT NULL,
|
||||
task_name VARCHAR(100) NOT NULL,
|
||||
task_group VARCHAR(50) NOT NULL DEFAULT 'DEFAULT',
|
||||
bean_name VARCHAR(100) NOT NULL,
|
||||
method_name VARCHAR(100) NOT NULL,
|
||||
method_params VARCHAR(500) DEFAULT NULL,
|
||||
execute_status SMALLINT NOT NULL, -- 执行状态(0:失败 1:成功)
|
||||
execute_message TEXT DEFAULT NULL,
|
||||
exception_info TEXT DEFAULT NULL,
|
||||
start_time TIMESTAMPTZ NOT NULL,
|
||||
end_time TIMESTAMPTZ DEFAULT NULL,
|
||||
execute_duration INT DEFAULT NULL,
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
update_time TIMESTAMPTZ DEFAULT NULL,
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是)
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_task_id ON crontab.tb_crontab_log(task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_log_task_name ON crontab.tb_crontab_log(task_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_execute_status ON crontab.tb_crontab_log(execute_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_start_time ON crontab.tb_crontab_log(start_time);
|
||||
CREATE INDEX IF NOT EXISTS idx_log_deleted ON crontab.tb_crontab_log(deleted);
|
||||
|
||||
COMMENT ON TABLE crontab.tb_crontab_log IS '定时任务执行日志表';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.id IS '主键ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.task_id IS '任务ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.task_name IS '任务名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.task_group IS '任务分组';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.bean_name IS 'Bean名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.method_name IS '方法名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.method_params IS '方法参数';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.execute_status IS '执行状态(0:失败 1:成功)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.execute_message IS '执行结果信息';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.exception_info IS '异常信息';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.start_time IS '开始时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.end_time IS '结束时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.execute_duration IS '执行时长(毫秒)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_log.deleted IS '是否删除(0:否 1:是)';
|
||||
|
||||
-- ====================================================
|
||||
-- 定时任务元数据表(存储爬虫任务的元数据配置)
|
||||
-- ====================================================
|
||||
DROP TABLE IF EXISTS crontab.tb_crontab_task_meta CASCADE;
|
||||
CREATE TABLE crontab.tb_crontab_task_meta (
|
||||
id VARCHAR(64) NOT NULL,
|
||||
meta_id VARCHAR(64) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description VARCHAR(500) DEFAULT NULL,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
bean_name VARCHAR(100) NOT NULL,
|
||||
method_name VARCHAR(100) NOT NULL,
|
||||
script_path VARCHAR(255) DEFAULT NULL,
|
||||
param_schema TEXT DEFAULT NULL,
|
||||
auto_publish SMALLINT NOT NULL DEFAULT 0, -- 是否自动发布
|
||||
sort_order INT DEFAULT 0,
|
||||
creator VARCHAR(64) DEFAULT NULL,
|
||||
updater VARCHAR(64) DEFAULT NULL,
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
update_time TIMESTAMPTZ DEFAULT NULL,
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL,
|
||||
deleted SMALLINT NOT NULL DEFAULT 0, -- 是否删除(0:否 1:是)
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (meta_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_category ON crontab.tb_crontab_task_meta(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_meta_deleted ON crontab.tb_crontab_task_meta(deleted);
|
||||
|
||||
COMMENT ON TABLE crontab.tb_crontab_task_meta IS '定时任务元数据表';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.id IS '主键ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.meta_id IS '元数据ID';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.name IS '任务名称';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.description IS '任务描述';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.category IS '任务分类(如:人民日报新闻爬取)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.bean_name IS 'Bean名称(执行器类名)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.method_name IS '执行方法名';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.script_path IS 'Python脚本路径(相对于basePath)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.param_schema IS '参数模板(JSON格式,定义参数名、类型、描述、默认值等)';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.auto_publish IS '是否自动发布';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.sort_order IS '排序号';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.creator IS '创建者';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.updater IS '更新者';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN crontab.tb_crontab_task_meta.deleted IS '是否删除(0:否 1:是)';
|
||||
@@ -12,17 +12,21 @@ CREATE TABLE file.tb_sys_file (
|
||||
mime_type VARCHAR(255) NOT NULL, -- 文件MIME类型
|
||||
url VARCHAR(255) NOT NULL, -- 文件URL
|
||||
status VARCHAR(50) NOT NULL, -- 文件状态
|
||||
service_type VARCHAR(50), -- 服务类型(bidding/customer_service/internal等)
|
||||
dept_path VARCHAR(255) NOT NULL, -- 当前部门路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (file_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
CREATE INDEX idx_file_service ON file.tb_sys_file(service_type) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE file.tb_sys_file IS '文件表';
|
||||
COMMENT ON COLUMN file.tb_sys_file.service_type IS '服务类型(用于服务间数据隔离)';
|
||||
COMMENT ON COLUMN file.tb_sys_file.optsn IS '流水号';
|
||||
COMMENT ON COLUMN file.tb_sys_file.file_id IS '文件ID';
|
||||
COMMENT ON COLUMN file.tb_sys_file.name IS '文件名';
|
||||
@@ -40,3 +44,47 @@ COMMENT ON COLUMN file.tb_sys_file.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN file.tb_sys_file.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN file.tb_sys_file.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN file.tb_sys_file.deleted IS '是否删除';
|
||||
|
||||
-- =============================
|
||||
-- 文件关联表
|
||||
-- =============================
|
||||
DROP TABLE IF EXISTS file.tb_file_relation CASCADE;
|
||||
CREATE TABLE file.tb_file_relation (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
relation_id VARCHAR(50) NOT NULL,
|
||||
file_id VARCHAR(50) NOT NULL,
|
||||
object_type VARCHAR(50) NOT NULL, -- 对象类型:bidding_project/ticket/document等
|
||||
object_id VARCHAR(50) NOT NULL, -- 对象ID
|
||||
relation_type VARCHAR(30) DEFAULT 'attachment', -- 关联类型:attachment-附件/avatar-头像/banner-横幅
|
||||
order_num INTEGER DEFAULT 0, -- 排序号
|
||||
service_type VARCHAR(50), -- 服务类型(继承自object_type)
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (relation_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (file_id) REFERENCES file.tb_sys_file(file_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE file.tb_file_relation IS '文件关联表';
|
||||
COMMENT ON COLUMN file.tb_file_relation.optsn IS '流水号';
|
||||
COMMENT ON COLUMN file.tb_file_relation.relation_id IS '关联ID';
|
||||
COMMENT ON COLUMN file.tb_file_relation.file_id IS '文件ID';
|
||||
COMMENT ON COLUMN file.tb_file_relation.object_type IS '对象类型:bidding_project/ticket/document等';
|
||||
COMMENT ON COLUMN file.tb_file_relation.object_id IS '对象ID';
|
||||
COMMENT ON COLUMN file.tb_file_relation.relation_type IS '关联类型:attachment-附件/avatar-头像/banner-横幅';
|
||||
COMMENT ON COLUMN file.tb_file_relation.order_num IS '排序号';
|
||||
COMMENT ON COLUMN file.tb_file_relation.service_type IS '服务类型(继承自object_type)';
|
||||
COMMENT ON COLUMN file.tb_file_relation.creator IS '创建者';
|
||||
COMMENT ON COLUMN file.tb_file_relation.updater IS '更新者';
|
||||
COMMENT ON COLUMN file.tb_file_relation.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN file.tb_file_relation.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN file.tb_file_relation.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN file.tb_file_relation.deleted IS '是否删除';
|
||||
|
||||
CREATE INDEX idx_file_relation_object ON file.tb_file_relation(object_type, object_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_file_relation_file ON file.tb_file_relation(file_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_file_relation_service ON file.tb_file_relation(service_type) WHERE deleted = false;
|
||||
@@ -8,7 +8,8 @@ CREATE SCHEMA IF NOT EXISTS knowledge;
|
||||
DROP TABLE IF EXISTS knowledge.tb_knowledge_base CASCADE;
|
||||
CREATE TABLE knowledge.tb_knowledge_base (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
kb_id VARCHAR(50) NOT NULL, -- 知识库ID
|
||||
agent_id VARCHAR(50) NOT NULL, -- 智能体id
|
||||
knowledge_id VARCHAR(50) NOT NULL, -- 知识库ID
|
||||
name VARCHAR(255) NOT NULL, -- 知识库名称
|
||||
kb_type VARCHAR(50) NOT NULL, -- 知识库类型:bidding-招投标/customer_service-客服/internal-内部协同
|
||||
access_level VARCHAR(20) NOT NULL DEFAULT 'private', -- 访问级别:public-公开/private-私有/internal-内部
|
||||
@@ -16,23 +17,26 @@ CREATE TABLE knowledge.tb_knowledge_base (
|
||||
storage_path VARCHAR(500), -- 存储路径
|
||||
version VARCHAR(20) DEFAULT '1.0', -- 当前版本号
|
||||
config JSONB DEFAULT NULL, -- 知识库配置(JSON格式:索引配置、检索参数等)
|
||||
service_type VARCHAR(50), -- 服务类型(bidding/customer_service/internal,冗余kb_type便于查询)
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态:active-激活/inactive-停用/archived-归档
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (kb_id),
|
||||
PRIMARY KEY (knowledge_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_kb_type ON knowledge.tb_knowledge_base(kb_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_kb_service ON knowledge.tb_knowledge_base(service_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_kb_dept_path ON knowledge.tb_knowledge_base(dept_path) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_base IS '知识库表';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_base.kb_type IS '知识库类型:bidding-招投标/customer_service-客服/internal-内部协同';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_base.service_type IS '服务类型(冗余存储便于快速过滤,与kb_type保持一致)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_base.access_level IS '访问级别:public-公开/private-私有/internal-内部';
|
||||
|
||||
-- 知识文档表
|
||||
@@ -40,7 +44,7 @@ DROP TABLE IF EXISTS knowledge.tb_knowledge_document CASCADE;
|
||||
CREATE TABLE knowledge.tb_knowledge_document (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
doc_id VARCHAR(50) NOT NULL, -- 文档ID
|
||||
kb_id VARCHAR(50) NOT NULL, -- 所属知识库ID
|
||||
knowledge_id VARCHAR(50) NOT NULL, -- 所属知识库ID
|
||||
title VARCHAR(500) NOT NULL, -- 文档标题
|
||||
doc_type VARCHAR(50) NOT NULL, -- 文档类型:text-文本/pdf/word/excel/image/video
|
||||
category VARCHAR(100), -- 文档分类(自动或手动分类)
|
||||
@@ -50,8 +54,8 @@ CREATE TABLE knowledge.tb_knowledge_document (
|
||||
file_path VARCHAR(500), -- 文件路径
|
||||
file_size BIGINT, -- 文件大小(字节)
|
||||
mime_type VARCHAR(100), -- MIME类型
|
||||
version VARCHAR(20) DEFAULT '1.0', -- 文档版本号
|
||||
parent_doc_id VARCHAR(50), -- 父文档ID(用于版本管理)
|
||||
version INTEGER DEFAULT 1, -- 文档版本号(仅做记录)
|
||||
root_doc_id VARCHAR(50), -- 根文档ID(版本组标识,保留用于整体版本管理)
|
||||
tags TEXT[], -- 文档标签数组
|
||||
keywords TEXT[], -- 关键词数组(AI提取)
|
||||
embedding_status VARCHAR(20) DEFAULT 'pending', -- 向量化状态:pending-待处理/processing-处理中/completed-完成/failed-失败
|
||||
@@ -59,25 +63,30 @@ CREATE TABLE knowledge.tb_knowledge_document (
|
||||
chunk_count INTEGER DEFAULT 0, -- 切片数量
|
||||
metadata JSONB DEFAULT NULL, -- 文档元数据(JSON格式)
|
||||
source_url VARCHAR(500), -- 来源URL
|
||||
service_type VARCHAR(50), -- 服务类型(继承自知识库)
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active', -- 状态:active-激活/inactive-停用/archived-归档
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (doc_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (kb_id) REFERENCES knowledge.tb_knowledge_base(kb_id)
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_doc_kb ON knowledge.tb_knowledge_document(kb_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_kb ON knowledge.tb_knowledge_document(knowledge_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_service ON knowledge.tb_knowledge_document(service_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_category ON knowledge.tb_knowledge_document(category) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_embedding_status ON knowledge.tb_knowledge_document(embedding_status) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_tags ON knowledge.tb_knowledge_document USING GIN(tags) WHERE deleted = false;
|
||||
CREATE INDEX idx_doc_root ON knowledge.tb_knowledge_document(root_doc_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_document IS '知识文档表';
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_document IS '知识文档表(文档级元数据,版本控制在chunk级别)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_document.service_type IS '服务类型(从知识库继承,用于服务间隔离)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_document.version IS '文档版本号(仅做记录,实际版本控制在chunk级别)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_document.root_doc_id IS '根文档ID(用于文档整体版本管理,可选)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_document.embedding_status IS '向量化状态:pending/processing/completed/failed';
|
||||
|
||||
-- 知识文档片段表(用于RAG检索)
|
||||
@@ -86,39 +95,45 @@ CREATE TABLE knowledge.tb_knowledge_chunk (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
chunk_id VARCHAR(50) NOT NULL, -- 片段ID
|
||||
doc_id VARCHAR(50) NOT NULL, -- 所属文档ID
|
||||
kb_id VARCHAR(50) NOT NULL, -- 所属知识库ID
|
||||
knowledge_id VARCHAR(50) NOT NULL, -- 所属知识库ID
|
||||
chunk_index INTEGER NOT NULL, -- 片段索引(在文档中的顺序)
|
||||
content TEXT NOT NULL, -- 片段内容
|
||||
content_length INTEGER, -- 内容长度
|
||||
embedding vector(1536), -- 向量嵌入(假设使用OpenAI 1536维)
|
||||
chunk_type VARCHAR(20) DEFAULT 'text', -- 片段类型:text-文本/table-表格/image-图片
|
||||
version INTEGER DEFAULT 1, -- chunk版本号(每次修改自动+1)
|
||||
root_chunk_id VARCHAR(50), -- 根chunk ID(同一chunk的不同版本共享此ID)
|
||||
is_current BOOLEAN DEFAULT true, -- 是否当前使用的版本
|
||||
position_info JSONB, -- 位置信息(页码、坐标等)
|
||||
metadata JSONB, -- 片段元数据
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (chunk_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (doc_id) REFERENCES knowledge.tb_knowledge_document(doc_id),
|
||||
FOREIGN KEY (kb_id) REFERENCES knowledge.tb_knowledge_base(kb_id)
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_chunk_doc ON knowledge.tb_knowledge_chunk(doc_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_chunk_kb ON knowledge.tb_knowledge_chunk(kb_id) WHERE deleted = false;
|
||||
-- 向量检索索引(需要安装pgvector扩展)
|
||||
-- CREATE INDEX idx_chunk_embedding ON knowledge.tb_knowledge_chunk USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
|
||||
CREATE INDEX idx_chunk_kb ON knowledge.tb_knowledge_chunk(knowledge_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_chunk_root_current ON knowledge.tb_knowledge_chunk(root_chunk_id, is_current) WHERE deleted = false;
|
||||
CREATE INDEX idx_chunk_current ON knowledge.tb_knowledge_chunk(is_current) WHERE deleted = false AND is_current = true;
|
||||
-- 向量检索索引(需要安装pgvector扩展,建议只索引当前版本)
|
||||
-- CREATE INDEX idx_chunk_embedding ON knowledge.tb_knowledge_chunk USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100) WHERE deleted = false AND is_current = true;
|
||||
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_chunk IS '知识文档片段表(RAG检索)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.embedding IS '向量嵌入(需要pgvector扩展)';
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_chunk IS '知识文档片段表(RAG检索基本单位,支持chunk级版本控制)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.version IS 'chunk版本号(整数,每次修改自动+1)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.root_chunk_id IS '根chunk ID(同一chunk的所有版本共享此ID,首次创建时等于chunk_id)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.is_current IS '是否当前使用的版本(每个root_chunk_id只有一个is_current=true,RAG检索时只使用当前版本)';
|
||||
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.embedding IS '向量嵌入(需要pgvector扩展,建议只为is_current=true的chunk生成)';
|
||||
|
||||
-- 知识访问日志表
|
||||
DROP TABLE IF EXISTS knowledge.tb_knowledge_access_log CASCADE;
|
||||
CREATE TABLE knowledge.tb_knowledge_access_log (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
kb_id VARCHAR(50), -- 知识库ID
|
||||
knowledge_id VARCHAR(50), -- 知识库ID
|
||||
doc_id VARCHAR(50), -- 文档ID
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
access_type VARCHAR(20) NOT NULL, -- 访问类型:view-查看/download-下载/search-搜索/edit-编辑
|
||||
@@ -127,12 +142,12 @@ CREATE TABLE knowledge.tb_knowledge_access_log (
|
||||
ip_address VARCHAR(45), -- IP地址
|
||||
user_agent TEXT, -- 用户代理
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
PRIMARY KEY (log_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_access_log_user ON knowledge.tb_knowledge_access_log(user_id, create_time DESC);
|
||||
CREATE INDEX idx_access_log_kb ON knowledge.tb_knowledge_access_log(kb_id, create_time DESC);
|
||||
CREATE INDEX idx_access_log_kb ON knowledge.tb_knowledge_access_log(knowledge_id, create_time DESC);
|
||||
|
||||
COMMENT ON TABLE knowledge.tb_knowledge_access_log IS '知识访问日志表';
|
||||
|
||||
@@ -6,18 +6,19 @@ CREATE TABLE log.tb_sys_log (
|
||||
type VARCHAR(50) NOT NULL, -- 日志类型
|
||||
level VARCHAR(50) NOT NULL, -- 日志级别
|
||||
module VARCHAR(50) NOT NULL, -- 日志模块
|
||||
ip_address varchar(45), -- IP地址
|
||||
ip_source varchar(100), -- IP来源
|
||||
browser varchar(100), -- 浏览器
|
||||
os varchar(100), -- 操作系统
|
||||
ip_address VARCHAR(45), -- IP地址
|
||||
ip_source VARCHAR(100), -- IP来源
|
||||
browser VARCHAR(100), -- 浏览器
|
||||
os VARCHAR(100), -- 操作系统
|
||||
message VARCHAR(255) NOT NULL, -- 日志消息
|
||||
data JSONB DEFAULT NULL, -- 日志数据
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
service_type VARCHAR(50) NOT NULL, -- 服务类型
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 日志创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 日志更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 日志删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 日志创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 日志更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 日志删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (log_id),
|
||||
UNIQUE (optsn)
|
||||
@@ -31,6 +32,7 @@ COMMENT ON COLUMN log.tb_sys_log.module IS '日志模块';
|
||||
COMMENT ON COLUMN log.tb_sys_log.message IS '日志消息';
|
||||
COMMENT ON COLUMN log.tb_sys_log.data IS '日志数据';
|
||||
COMMENT ON COLUMN log.tb_sys_log.creator IS '创建者';
|
||||
COMMENT ON COLUMN log.tb_sys_log.service_type IS '服务类型';
|
||||
COMMENT ON COLUMN log.tb_sys_log.dept_path IS '部门全路径';
|
||||
COMMENT ON COLUMN log.tb_sys_log.updater IS '更新者';
|
||||
COMMENT ON COLUMN log.tb_sys_log.create_time IS '日志创建时间';
|
||||
|
||||
@@ -8,12 +8,13 @@ CREATE TABLE message.tb_message (
|
||||
content VARCHAR(255) NOT NULL, -- 消息内容
|
||||
type VARCHAR(50) NOT NULL, -- 消息类型
|
||||
status VARCHAR(50) NOT NULL, -- 消息状态
|
||||
service_type VARCHAR(50) NOT NULL, -- 服务类型
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(隔离)
|
||||
creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
delete_time timestamptz DEFAULT NULL,
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL,
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (message_id),
|
||||
UNIQUE (optsn)
|
||||
@@ -26,6 +27,7 @@ COMMENT ON COLUMN message.tb_message.title IS '消息标题';
|
||||
COMMENT ON COLUMN message.tb_message.content IS '消息内容';
|
||||
COMMENT ON COLUMN message.tb_message.type IS '消息类型';
|
||||
COMMENT ON COLUMN message.tb_message.status IS '消息状态';
|
||||
COMMENT ON COLUMN message.tb_message.service_type IS '服务类型';
|
||||
COMMENT ON COLUMN message.tb_message.dept_path IS '部门全路径';
|
||||
COMMENT ON COLUMN message.tb_message.creator IS '创建者';
|
||||
COMMENT ON COLUMN message.tb_message.updater IS '更新者';
|
||||
@@ -42,13 +44,13 @@ CREATE TABLE message.tb_message_range (
|
||||
message_id VARCHAR(50) NOT NULL, -- 消息ID
|
||||
target_type VARCHAR(20) NOT NULL, -- 目标类型:user/dept/role/all
|
||||
target_id VARCHAR(50) DEFAULT NULL, -- 目标ID(用户、部门、角色ID等,all类型时为空)
|
||||
channel VARCHAR(20) NOT NULL DEFAULT 'app', -- 发送渠道:app/sms/email/wechat等
|
||||
channel VARCHAR(20) NOT NULL DEFAULT 'app', -- 发送渠道:app/sms/email/wechat_official_account/wechat_applet等
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径,支持like递归(如/1/2/3/)
|
||||
creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (optsn),
|
||||
UNIQUE (message_id, target_type, target_id, channel)
|
||||
@@ -59,7 +61,7 @@ COMMENT ON COLUMN message.tb_message_range.optsn IS '流水号';
|
||||
COMMENT ON COLUMN message.tb_message_range.message_id IS '消息ID';
|
||||
COMMENT ON COLUMN message.tb_message_range.target_type IS '目标类型:user-指定用户/dept-部门/role-角色/all-全员';
|
||||
COMMENT ON COLUMN message.tb_message_range.target_id IS '目标ID(用户、部门、角色ID等,all类型时为空)';
|
||||
COMMENT ON COLUMN message.tb_message_range.channel IS '发送渠道:app/sms/email/wechat等';
|
||||
COMMENT ON COLUMN message.tb_message_range.channel IS '发送渠道:app/sms/email/wechat_official_account/wechat_applet等';
|
||||
COMMENT ON COLUMN message.tb_message_range.dept_path IS '部门全路径';
|
||||
COMMENT ON COLUMN message.tb_message_range.creator IS '创建者';
|
||||
COMMENT ON COLUMN message.tb_message_range.updater IS '更新者';
|
||||
@@ -77,14 +79,14 @@ CREATE TABLE message.tb_message_receiver (
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
channel VARCHAR(20) DEFAULT 'app', -- 接收渠道:app/sms/email/wechat等
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'unread', -- 消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除
|
||||
read_time timestamptz DEFAULT NULL, -- 阅读时间
|
||||
handle_time timestamptz DEFAULT NULL, -- 处理时间
|
||||
read_time TIMESTAMPTZ DEFAULT NULL, -- 阅读时间
|
||||
handle_time TIMESTAMPTZ DEFAULT NULL, -- 处理时间
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离)
|
||||
creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间(接收时间)
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(接收时间)
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (optsn),
|
||||
UNIQUE (message_id, user_id, channel)
|
||||
@@ -116,18 +118,18 @@ DROP TABLE IF EXISTS message.tb_message_channel CASCADE;
|
||||
CREATE TABLE message.tb_message_channel (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
channel_id VARCHAR(50) NOT NULL, -- 渠道ID
|
||||
channel_code VARCHAR(20) NOT NULL, -- 渠道编码:app/sms/email/wechat/dingtalk等
|
||||
channel_code VARCHAR(50) NOT NULL, -- 渠道编码:app/sms/email/wechat/dingtalk等
|
||||
channel_name VARCHAR(100) NOT NULL, -- 渠道名称
|
||||
channel_desc VARCHAR(255) DEFAULT NULL, -- 渠道描述
|
||||
config TEXT DEFAULT NULL, -- 渠道配置(JSON格式,如API密钥、服务器地址等)
|
||||
config JSON DEFAULT NULL, -- 渠道配置(如API密钥、服务器地址等)
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'enabled', -- 渠道状态:enabled-启用/disabled-禁用/maintenance-维护中
|
||||
priority INTEGER DEFAULT 0, -- 优先级(数字越大优先级越高)
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离)
|
||||
creator VARCHAR(50) NOT NULL DEFAULT 'system',-- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (channel_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -151,11 +153,48 @@ COMMENT ON COLUMN message.tb_message_channel.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN message.tb_message_channel.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN message.tb_message_channel.deleted IS '是否删除';
|
||||
|
||||
-- 插入默认渠道配置
|
||||
INSERT INTO message.tb_message_channel (optsn, channel_id, channel_code, channel_name, channel_desc, status, priority)
|
||||
VALUES
|
||||
('CHANNEL_APP_001', 'CH_APP', 'app', '应用内消息', '系统内部消息推送', 'enabled', 100),
|
||||
('CHANNEL_SMS_001', 'CH_SMS', 'sms', '短信通知', '手机短信推送', 'disabled', 80),
|
||||
('CHANNEL_EMAIL_001', 'CH_EMAIL', 'email', '邮件通知', '电子邮件推送', 'disabled', 60),
|
||||
('CHANNEL_WECHAT_001', 'CH_WECHAT', 'wechat', '微信通知', '微信公众号/企业微信推送', 'disabled', 70),
|
||||
('CHANNEL_DINGTALK_001', 'CH_DINGTALK', 'dingtalk', '钉钉通知', '钉钉工作通知推送', 'disabled', 70);
|
||||
-- =============================
|
||||
-- 消息模板表
|
||||
-- =============================
|
||||
DROP TABLE IF EXISTS message.tb_message_template CASCADE;
|
||||
CREATE TABLE message.tb_message_template (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
template_id VARCHAR(50) NOT NULL,
|
||||
template_code VARCHAR(100) NOT NULL, -- 模板编码
|
||||
template_name VARCHAR(255) NOT NULL, -- 模板名称
|
||||
template_type VARCHAR(30) NOT NULL, -- 模板类型:system-系统/business-业务
|
||||
title_template TEXT, -- 标题模板(支持变量)
|
||||
content_template TEXT NOT NULL, -- 内容模板(支持变量)
|
||||
variables JSONB, -- 模板变量定义
|
||||
service_type VARCHAR(50) NOT NULL, -- 服务类型
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (template_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (template_code)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE message.tb_message_template IS '消息模板表';
|
||||
COMMENT ON COLUMN message.tb_message_template.optsn IS '流水号';
|
||||
COMMENT ON COLUMN message.tb_message_template.template_id IS '模板ID';
|
||||
COMMENT ON COLUMN message.tb_message_template.template_code IS '模板编码';
|
||||
COMMENT ON COLUMN message.tb_message_template.template_name IS '模板名称';
|
||||
COMMENT ON COLUMN message.tb_message_template.template_type IS '模板类型:system-系统/business-业务';
|
||||
COMMENT ON COLUMN message.tb_message_template.title_template IS '标题模板(支持变量)';
|
||||
COMMENT ON COLUMN message.tb_message_template.content_template IS '内容模板(支持变量)';
|
||||
COMMENT ON COLUMN message.tb_message_template.variables IS '模板变量定义';
|
||||
COMMENT ON COLUMN message.tb_message_template.service_type IS '服务类型';
|
||||
COMMENT ON COLUMN message.tb_message_template.dept_path IS '部门全路径';
|
||||
COMMENT ON COLUMN message.tb_message_template.creator IS '创建者';
|
||||
COMMENT ON COLUMN message.tb_message_template.updater IS '更新者';
|
||||
COMMENT ON COLUMN message.tb_message_template.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN message.tb_message_template.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN message.tb_message_template.delete_time IS '删除时间';
|
||||
COMMENT ON COLUMN message.tb_message_template.deleted IS '是否删除';
|
||||
|
||||
CREATE INDEX idx_template_type ON message.tb_message_template(template_type) WHERE deleted = false;
|
||||
|
||||
@@ -20,10 +20,10 @@ CREATE TABLE sys.tb_sys_dept (
|
||||
description VARCHAR(255) DEFAULT NULL, -- 部门描述
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (dept_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -54,12 +54,12 @@ CREATE TABLE sys.tb_sys_role (
|
||||
owner_dept_id VARCHAR(50) DEFAULT NULL, -- 当scope=dept时,所属部门ID
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL,
|
||||
status boolean NOT NULL DEFAULT false, -- 部门全路径
|
||||
status BOOLEAN NOT NULL DEFAULT false, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (role_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -99,10 +99,10 @@ CREATE TABLE sys.tb_sys_dept_role (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (dept_id, role_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -124,13 +124,14 @@ CREATE TABLE sys.tb_sys_user_role (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
role_id VARCHAR(50) NOT NULL, -- 角色ID
|
||||
dept_id VARCHAR(50) NOT NULL, -- 部门ID
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -138,6 +139,7 @@ COMMENT ON TABLE sys.tb_sys_user_role IS '用户角色关联表';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.optsn IS '流水号';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.role_id IS '角色ID';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.dept_path IS '部门全路径';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.creator IS '创建者';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_role.updater IS '更新者';
|
||||
@@ -156,17 +158,17 @@ CREATE TABLE sys.tb_sys_view (
|
||||
url VARCHAR(255) DEFAULT NULL, -- 视图URL
|
||||
component VARCHAR(255) DEFAULT NULL, -- 视图组件
|
||||
icon VARCHAR(100) DEFAULT NULL, -- 视图图标
|
||||
type integer DEFAULT 0, -- 视图类型
|
||||
type INTEGER DEFAULT 0, -- 视图类型
|
||||
layout VARCHAR(100) DEFAULT NULL, -- 布局组件路径名称
|
||||
order_num integer DEFAULT 0, -- 视图排序号
|
||||
order_num INTEGER DEFAULT 0, -- 视图排序号
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
description VARCHAR(255) DEFAULT NULL, -- 视图描述
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (view_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -201,10 +203,10 @@ CREATE TABLE sys.tb_sys_module (
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (module_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -232,12 +234,12 @@ CREATE TABLE sys.tb_sys_permission (
|
||||
module_id VARCHAR(50) DEFAULT NULL, -- 所属模块ID
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL,
|
||||
status boolean NOT NULL DEFAULT false, -- 部门全路径
|
||||
status BOOLEAN NOT NULL DEFAULT false, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (permission_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -266,10 +268,10 @@ CREATE TABLE sys.tb_sys_role_permission (
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (role_id, permission_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -294,10 +296,10 @@ CREATE TABLE sys.tb_sys_view_permission (
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (view_id, permission_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -393,10 +395,10 @@ CREATE TABLE sys.tb_sys_acl (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径(数据隔离)
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (acl_id),
|
||||
UNIQUE (object_type, object_id, principal_type, principal_id, principal_dept_id, deleted),
|
||||
UNIQUE (optsn)
|
||||
@@ -442,10 +444,10 @@ CREATE TABLE sys.tb_sys_acl_policy (
|
||||
apply_to_children BOOLEAN DEFAULT true, -- 是否默认应用到子级
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
updater VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
delete_time timestamptz DEFAULT NULL,
|
||||
deleted boolean NOT NULL DEFAULT false,
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
update_time TIMESTAMPTZ DEFAULT NULL,
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (policy_id),
|
||||
UNIQUE (object_type, deleted),
|
||||
UNIQUE (optsn)
|
||||
|
||||
@@ -5,22 +5,25 @@ CREATE SCHEMA IF NOT EXISTS sys;
|
||||
-- 用户表
|
||||
DROP TABLE IF EXISTS sys.tb_sys_user CASCADE;
|
||||
CREATE TABLE sys.tb_sys_user (
|
||||
optsn varchar(50) NOT NULL, -- 流水号
|
||||
user_id varchar(50) NOT NULL, -- 用户ID
|
||||
password varchar(128) NOT NULL, -- 密码(建议存储 bcrypt/argon2 哈希)
|
||||
email varchar(100), -- 电子邮件
|
||||
phone varchar(20), -- 电话号码
|
||||
wechat_id varchar(50), -- 微信ID
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间(使用带时区时间)
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除(使用 boolean)
|
||||
status integer NOT NULL DEFAULT 1, -- 状态
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
usercode VARCHAR(100) DEFAULT NULL, -- 用户code。sso同步数据获取
|
||||
password VARCHAR(128) NOT NULL, -- 密码(建议存储 bcrypt/argon2 哈希)
|
||||
email VARCHAR(100), -- 电子邮件
|
||||
phone VARCHAR(500), -- 电话号码
|
||||
phone_hash VARCHAR(200), -- 电话hash
|
||||
wechat_id VARCHAR(50), -- 微信ID
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(使用带时区时间)
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(由触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除(使用 BOOLEAN)
|
||||
status INTEGER NOT NULL DEFAULT 1, -- 状态
|
||||
PRIMARY KEY (user_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (email),
|
||||
UNIQUE (phone),
|
||||
UNIQUE (wechat_id)
|
||||
UNIQUE (wechat_id),
|
||||
UNIQUE (usercode)
|
||||
);
|
||||
CREATE INDEX idx_tb_sys_user_phone ON sys.tb_sys_user USING btree (phone);
|
||||
|
||||
@@ -48,20 +51,19 @@ COMMENT ON COLUMN sys.tb_sys_user.status IS '状态';
|
||||
-- 用户信息表
|
||||
DROP TABLE IF EXISTS sys.tb_sys_user_info CASCADE;
|
||||
CREATE TABLE sys.tb_sys_user_info (
|
||||
optsn varchar(50) NOT NULL, -- 流水号
|
||||
user_id varchar(50) NOT NULL, -- 用户ID
|
||||
avatar varchar(255), -- 头像
|
||||
gender integer DEFAULT 0, -- 性别
|
||||
family_name varchar(50), -- 姓
|
||||
given_name varchar(50), -- 名
|
||||
full_name varchar(100), -- 全名
|
||||
level integer DEFAULT 1, -- 等级
|
||||
id_card varchar(50), -- 身份证号
|
||||
address varchar(255), -- 地址
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间(触发器维护)
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
deleted boolean NOT NULL DEFAULT false, -- 是否删除
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
avatar VARCHAR(255), -- 头像
|
||||
gender INTEGER DEFAULT 0, -- 性别
|
||||
username VARCHAR(100) NOT NULL, -- 用户名
|
||||
level INTEGER DEFAULT 1, -- 等级
|
||||
id_card VARCHAR(50), -- 身份证号
|
||||
address VARCHAR(255), -- 地址
|
||||
remark VARCHAR(500) DEFAULT NULL, -- 备注
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间(触发器维护)
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (user_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
@@ -70,12 +72,11 @@ COMMENT ON COLUMN sys.tb_sys_user_info.optsn IS '流水号';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.avatar IS '头像';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.gender IS '性别';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.family_name IS '姓';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.given_name IS '名';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.full_name IS '全名';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.username IS '用户名';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.level IS '等级';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.id_card IS '身份证号';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.address IS '地址';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.remark IS '备注';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_info.delete_time IS '删除时间';
|
||||
@@ -84,19 +85,19 @@ COMMENT ON COLUMN sys.tb_sys_user_info.deleted IS '是否删除';
|
||||
-- 登录日志表
|
||||
DROP TABLE IF EXISTS sys.tb_sys_login_log CASCADE;
|
||||
CREATE TABLE sys.tb_sys_login_log (
|
||||
optsn varchar(50) NOT NULL, -- 流水号(作为主键)
|
||||
user_id varchar(50) NOT NULL, -- 用户ID
|
||||
username varchar(50) NOT NULL, -- 用户名
|
||||
ip_address varchar(45), -- IP地址
|
||||
ip_source varchar(100), -- IP来源
|
||||
browser varchar(100), -- 浏览器
|
||||
os varchar(100), -- 操作系统
|
||||
password varchar(128), -- 密码(建议存储 bcrypt/argon2 哈希)
|
||||
login_time timestamptz DEFAULT now(), -- 登录时间
|
||||
status integer DEFAULT 1, -- 登录状态(0失败 1成功)
|
||||
error_count integer DEFAULT 0, -- 错误次数
|
||||
message varchar(255), -- 登录消息
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号(作为主键)
|
||||
user_id VARCHAR(50) NOT NULL, -- 用户ID
|
||||
username VARCHAR(50) NOT NULL, -- 用户名
|
||||
ip_address VARCHAR(45), -- IP地址
|
||||
ip_source VARCHAR(100), -- IP来源
|
||||
browser VARCHAR(100), -- 浏览器
|
||||
os VARCHAR(100), -- 操作系统
|
||||
password VARCHAR(128), -- 密码(建议存储 bcrypt/argon2 哈希)
|
||||
login_time TIMESTAMPTZ DEFAULT now(), -- 登录时间
|
||||
status INTEGER DEFAULT 1, -- 登录状态(0失败 1成功)
|
||||
error_count INTEGER DEFAULT 0, -- 错误次数
|
||||
message VARCHAR(255), -- 登录消息
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
PRIMARY KEY (optsn)
|
||||
);
|
||||
-- B-tree 索引(显式指定 USING btree,Postgres 默认即为 btree)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
-- =============================
|
||||
-- 智能客服系统业务模块
|
||||
-- 智能客服系统业务模块(工单系统)
|
||||
-- 支持:微信小程序客户咨询、智能问答、工单管理、CRM集成
|
||||
-- =============================
|
||||
CREATE SCHEMA IF NOT EXISTS customer_service;
|
||||
CREATE SCHEMA IF NOT EXISTS workcase;
|
||||
|
||||
-- 客户信息表
|
||||
DROP TABLE IF EXISTS customer_service.tb_customer CASCADE;
|
||||
CREATE TABLE customer_service.tb_customer (
|
||||
DROP TABLE IF EXISTS workcase.tb_customer CASCADE;
|
||||
CREATE TABLE workcase.tb_customer (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
customer_id VARCHAR(50) NOT NULL, -- 客户ID
|
||||
customer_no VARCHAR(100), -- 客户编号
|
||||
@@ -25,7 +25,7 @@ CREATE TABLE customer_service.tb_customer (
|
||||
tags TEXT[], -- 客户标签数组
|
||||
notes TEXT, -- 备注
|
||||
crm_customer_id VARCHAR(50), -- CRM系统客户ID(外部系统)
|
||||
last_contact_time timestamptz, -- 最后联系时间
|
||||
last_contact_time TIMESTAMPTZ, -- 最后联系时间
|
||||
total_consultations INTEGER DEFAULT 0, -- 咨询总次数
|
||||
total_orders INTEGER DEFAULT 0, -- 订单总数
|
||||
total_amount DECIMAL(18,2) DEFAULT 0, -- 总消费金额
|
||||
@@ -34,9 +34,9 @@ CREATE TABLE customer_service.tb_customer (
|
||||
status VARCHAR(20) DEFAULT 'active', -- 状态:active-活跃/inactive-非活跃/blacklist-黑名单
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (customer_id),
|
||||
UNIQUE (optsn),
|
||||
@@ -45,16 +45,16 @@ CREATE TABLE customer_service.tb_customer (
|
||||
UNIQUE (email)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_customer_type ON customer_service.tb_customer(customer_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_customer_level ON customer_service.tb_customer(customer_level) WHERE deleted = false;
|
||||
CREATE INDEX idx_customer_wechat ON customer_service.tb_customer(wechat_openid) WHERE deleted = false;
|
||||
CREATE INDEX idx_customer_type ON workcase.tb_customer(customer_type) WHERE deleted = false;
|
||||
CREATE INDEX idx_customer_level ON workcase.tb_customer(customer_level) WHERE deleted = false;
|
||||
CREATE INDEX idx_customer_wechat ON workcase.tb_customer(wechat_openid) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_customer IS '客户信息表';
|
||||
COMMENT ON COLUMN customer_service.tb_customer.customer_level IS '客户等级:vip/important/normal/potential';
|
||||
COMMENT ON TABLE workcase.tb_customer IS '客户信息表';
|
||||
COMMENT ON COLUMN workcase.tb_customer.customer_level IS '客户等级:vip/important/normal/potential';
|
||||
|
||||
-- 会话表
|
||||
DROP TABLE IF EXISTS customer_service.tb_conversation CASCADE;
|
||||
CREATE TABLE customer_service.tb_conversation (
|
||||
DROP TABLE IF EXISTS workcase.tb_conversation CASCADE;
|
||||
CREATE TABLE workcase.tb_conversation (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
conversation_id VARCHAR(50) NOT NULL, -- 会话ID
|
||||
customer_id VARCHAR(50) NOT NULL, -- 客户ID
|
||||
@@ -62,8 +62,8 @@ CREATE TABLE customer_service.tb_conversation (
|
||||
channel VARCHAR(20) DEFAULT 'wechat', -- 渠道:wechat-微信/web-网页/app-应用/phone-电话
|
||||
agent_id VARCHAR(50), -- 智能体ID或客服人员ID
|
||||
agent_type VARCHAR(20) DEFAULT 'ai', -- 座席类型:ai-AI/human-人工
|
||||
session_start_time timestamptz DEFAULT now(), -- 会话开始时间
|
||||
session_end_time timestamptz, -- 会话结束时间
|
||||
session_start_time TIMESTAMPTZ DEFAULT now(), -- 会话开始时间
|
||||
session_end_time TIMESTAMPTZ, -- 会话结束时间
|
||||
duration_seconds INTEGER, -- 会话时长(秒)
|
||||
message_count INTEGER DEFAULT 0, -- 消息数量
|
||||
conversation_status VARCHAR(20) DEFAULT 'active', -- 会话状态:active-进行中/closed-已结束/transferred-已转接/timeout-超时
|
||||
@@ -75,25 +75,25 @@ CREATE TABLE customer_service.tb_conversation (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (conversation_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (customer_id) REFERENCES customer_service.tb_customer(customer_id)
|
||||
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_conv_customer ON customer_service.tb_conversation(customer_id, session_start_time DESC) WHERE deleted = false;
|
||||
CREATE INDEX idx_conv_status ON customer_service.tb_conversation(conversation_status) WHERE deleted = false;
|
||||
CREATE INDEX idx_conv_agent ON customer_service.tb_conversation(agent_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_conv_customer ON workcase.tb_conversation(customer_id, session_start_time DESC) WHERE deleted = false;
|
||||
CREATE INDEX idx_conv_status ON workcase.tb_conversation(conversation_status) WHERE deleted = false;
|
||||
CREATE INDEX idx_conv_agent ON workcase.tb_conversation(agent_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_conversation IS '会话表';
|
||||
COMMENT ON COLUMN customer_service.tb_conversation.conversation_type IS '会话类型:ai/human/transfer';
|
||||
COMMENT ON TABLE workcase.tb_conversation IS '会话表';
|
||||
COMMENT ON COLUMN workcase.tb_conversation.conversation_type IS '会话类型:ai/human/transfer';
|
||||
|
||||
-- 会话消息表
|
||||
DROP TABLE IF EXISTS customer_service.tb_conversation_message CASCADE;
|
||||
CREATE TABLE customer_service.tb_conversation_message (
|
||||
DROP TABLE IF EXISTS workcase.tb_conversation_message CASCADE;
|
||||
CREATE TABLE workcase.tb_conversation_message (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
message_id VARCHAR(50) NOT NULL, -- 消息ID
|
||||
conversation_id VARCHAR(50) NOT NULL, -- 所属会话ID
|
||||
@@ -110,25 +110,25 @@ CREATE TABLE customer_service.tb_conversation_message (
|
||||
intent VARCHAR(100), -- 意图识别结果
|
||||
is_sensitive BOOLEAN DEFAULT false, -- 是否敏感信息
|
||||
read_status BOOLEAN DEFAULT false, -- 已读状态
|
||||
read_time timestamptz, -- 阅读时间
|
||||
read_time TIMESTAMPTZ, -- 阅读时间
|
||||
metadata JSONB, -- 消息元数据
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间(发送时间)
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间(发送时间)
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (message_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (conversation_id) REFERENCES customer_service.tb_conversation(conversation_id)
|
||||
FOREIGN KEY (conversation_id) REFERENCES workcase.tb_conversation(conversation_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_msg_conversation ON customer_service.tb_conversation_message(conversation_id, create_time) WHERE deleted = false;
|
||||
CREATE INDEX idx_msg_sender ON customer_service.tb_conversation_message(sender_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_msg_conversation ON workcase.tb_conversation_message(conversation_id, create_time) WHERE deleted = false;
|
||||
CREATE INDEX idx_msg_sender ON workcase.tb_conversation_message(sender_id) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_conversation_message IS '会话消息表';
|
||||
COMMENT ON COLUMN customer_service.tb_conversation_message.sentiment IS '情感分析:positive/neutral/negative';
|
||||
COMMENT ON TABLE workcase.tb_conversation_message IS '会话消息表';
|
||||
COMMENT ON COLUMN workcase.tb_conversation_message.sentiment IS '情感分析:positive/neutral/negative';
|
||||
|
||||
-- 工单表
|
||||
DROP TABLE IF EXISTS customer_service.tb_ticket CASCADE;
|
||||
CREATE TABLE customer_service.tb_ticket (
|
||||
DROP TABLE IF EXISTS workcase.tb_ticket CASCADE;
|
||||
CREATE TABLE workcase.tb_ticket (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
ticket_id VARCHAR(50) NOT NULL, -- 工单ID
|
||||
ticket_no VARCHAR(100) NOT NULL, -- 工单编号
|
||||
@@ -145,10 +145,10 @@ CREATE TABLE customer_service.tb_ticket (
|
||||
assigned_dept VARCHAR(50), -- 分配部门
|
||||
ticket_status VARCHAR(30) DEFAULT 'pending', -- 工单状态:pending-待处理/processing-处理中/resolved-已解决/closed-已关闭/cancelled-已取消
|
||||
resolution TEXT, -- 解决方案
|
||||
resolution_time timestamptz, -- 解决时间
|
||||
close_time timestamptz, -- 关闭时间
|
||||
response_time timestamptz, -- 首次响应时间
|
||||
sla_deadline timestamptz, -- SLA截止时间
|
||||
resolution_time TIMESTAMPTZ, -- 解决时间
|
||||
close_time TIMESTAMPTZ, -- 关闭时间
|
||||
response_time TIMESTAMPTZ, -- 首次响应时间
|
||||
sla_deadline TIMESTAMPTZ, -- SLA截止时间
|
||||
is_overdue BOOLEAN DEFAULT false, -- 是否逾期
|
||||
customer_rating INTEGER, -- 客户评分(1-5星)
|
||||
customer_feedback TEXT, -- 客户反馈
|
||||
@@ -159,28 +159,28 @@ CREATE TABLE customer_service.tb_ticket (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (ticket_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (ticket_no),
|
||||
FOREIGN KEY (customer_id) REFERENCES customer_service.tb_customer(customer_id)
|
||||
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ticket_customer ON customer_service.tb_ticket(customer_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_status ON customer_service.tb_ticket(ticket_status) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_assigned ON customer_service.tb_ticket(assigned_to) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_priority ON customer_service.tb_ticket(priority) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_sla ON customer_service.tb_ticket(sla_deadline) WHERE deleted = false AND is_overdue = false;
|
||||
CREATE INDEX idx_ticket_customer ON workcase.tb_ticket(customer_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_status ON workcase.tb_ticket(ticket_status) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_assigned ON workcase.tb_ticket(assigned_to) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_priority ON workcase.tb_ticket(priority) WHERE deleted = false;
|
||||
CREATE INDEX idx_ticket_sla ON workcase.tb_ticket(sla_deadline) WHERE deleted = false AND is_overdue = false;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_ticket IS '工单表';
|
||||
COMMENT ON COLUMN customer_service.tb_ticket.ticket_type IS '工单类型:consultation/complaint/suggestion/repair/installation/other';
|
||||
COMMENT ON TABLE workcase.tb_ticket IS '工单表';
|
||||
COMMENT ON COLUMN workcase.tb_ticket.ticket_type IS '工单类型:consultation/complaint/suggestion/repair/installation/other';
|
||||
|
||||
-- 工单处理记录表
|
||||
DROP TABLE IF EXISTS customer_service.tb_ticket_log CASCADE;
|
||||
CREATE TABLE customer_service.tb_ticket_log (
|
||||
DROP TABLE IF EXISTS workcase.tb_ticket_log CASCADE;
|
||||
CREATE TABLE workcase.tb_ticket_log (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
log_id VARCHAR(50) NOT NULL, -- 日志ID
|
||||
ticket_id VARCHAR(50) NOT NULL, -- 工单ID
|
||||
@@ -192,22 +192,22 @@ CREATE TABLE customer_service.tb_ticket_log (
|
||||
operator_name VARCHAR(100), -- 操作人姓名
|
||||
attachments VARCHAR(50)[], -- 附件ID数组
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
PRIMARY KEY (log_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (ticket_id) REFERENCES customer_service.tb_ticket(ticket_id)
|
||||
FOREIGN KEY (ticket_id) REFERENCES workcase.tb_ticket(ticket_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ticket_log_ticket ON customer_service.tb_ticket_log(ticket_id, create_time DESC);
|
||||
CREATE INDEX idx_ticket_log_ticket ON workcase.tb_ticket_log(ticket_id, create_time DESC);
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_ticket_log IS '工单处理记录表';
|
||||
COMMENT ON TABLE workcase.tb_ticket_log IS '工单处理记录表';
|
||||
|
||||
-- FAQ表(常见问题)
|
||||
DROP TABLE IF EXISTS customer_service.tb_faq CASCADE;
|
||||
CREATE TABLE customer_service.tb_faq (
|
||||
DROP TABLE IF EXISTS workcase.tb_faq CASCADE;
|
||||
CREATE TABLE workcase.tb_faq (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
faq_id VARCHAR(50) NOT NULL, -- FAQ ID
|
||||
kb_id VARCHAR(50), -- 关联知识库ID
|
||||
knowledge_id VARCHAR(50), -- 关联知识库ID
|
||||
category VARCHAR(100) NOT NULL, -- 分类
|
||||
question TEXT NOT NULL, -- 问题
|
||||
answer TEXT NOT NULL, -- 答案
|
||||
@@ -221,22 +221,22 @@ CREATE TABLE customer_service.tb_faq (
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (faq_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_faq_category ON customer_service.tb_faq(category) WHERE deleted = false;
|
||||
CREATE INDEX idx_faq_published ON customer_service.tb_faq(is_published) WHERE deleted = false AND is_published = true;
|
||||
CREATE INDEX idx_faq_category ON workcase.tb_faq(category) WHERE deleted = false;
|
||||
CREATE INDEX idx_faq_published ON workcase.tb_faq(is_published) WHERE deleted = false AND is_published = true;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_faq IS 'FAQ常见问题表';
|
||||
COMMENT ON TABLE workcase.tb_faq IS 'FAQ常见问题表';
|
||||
|
||||
-- 客服评价表
|
||||
DROP TABLE IF EXISTS customer_service.tb_service_evaluation CASCADE;
|
||||
CREATE TABLE customer_service.tb_service_evaluation (
|
||||
DROP TABLE IF EXISTS workcase.tb_service_evaluation CASCADE;
|
||||
CREATE TABLE workcase.tb_service_evaluation (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
evaluation_id VARCHAR(50) NOT NULL, -- 评价ID
|
||||
customer_id VARCHAR(50) NOT NULL, -- 客户ID
|
||||
@@ -249,21 +249,21 @@ CREATE TABLE customer_service.tb_service_evaluation (
|
||||
tags TEXT[], -- 评价标签
|
||||
is_anonymous BOOLEAN DEFAULT false, -- 是否匿名
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (evaluation_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (customer_id) REFERENCES customer_service.tb_customer(customer_id)
|
||||
FOREIGN KEY (customer_id) REFERENCES workcase.tb_customer(customer_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_eval_customer ON customer_service.tb_service_evaluation(customer_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_eval_rating ON customer_service.tb_service_evaluation(rating) WHERE deleted = false;
|
||||
CREATE INDEX idx_eval_customer ON workcase.tb_service_evaluation(customer_id) WHERE deleted = false;
|
||||
CREATE INDEX idx_eval_rating ON workcase.tb_service_evaluation(rating) WHERE deleted = false;
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_service_evaluation IS '客服评价表';
|
||||
COMMENT ON TABLE workcase.tb_service_evaluation IS '客服评价表';
|
||||
|
||||
-- CRM集成配置表
|
||||
DROP TABLE IF EXISTS customer_service.tb_crm_config CASCADE;
|
||||
CREATE TABLE customer_service.tb_crm_config (
|
||||
DROP TABLE IF EXISTS workcase.tb_crm_config CASCADE;
|
||||
CREATE TABLE workcase.tb_crm_config (
|
||||
optsn VARCHAR(50) NOT NULL, -- 流水号
|
||||
config_id VARCHAR(50) NOT NULL, -- 配置ID
|
||||
crm_system VARCHAR(50) NOT NULL, -- CRM系统名称
|
||||
@@ -274,16 +274,16 @@ CREATE TABLE customer_service.tb_crm_config (
|
||||
sync_direction VARCHAR(30) DEFAULT 'bidirectional',-- 同步方向:to_crm-单向到CRM/from_crm-单向从CRM/bidirectional-双向
|
||||
field_mapping JSONB, -- 字段映射配置
|
||||
sync_enabled BOOLEAN DEFAULT false, -- 是否启用同步
|
||||
last_sync_time timestamptz, -- 最后同步时间
|
||||
last_sync_time TIMESTAMPTZ, -- 最后同步时间
|
||||
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
|
||||
creator VARCHAR(50) DEFAULT NULL, -- 创建者
|
||||
updater VARCHAR(50) DEFAULT NULL, -- 更新者
|
||||
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time timestamptz DEFAULT NULL, -- 更新时间
|
||||
delete_time timestamptz DEFAULT NULL, -- 删除时间
|
||||
create_time TIMESTAMPTZ NOT NULL DEFAULT now(), -- 创建时间
|
||||
update_time TIMESTAMPTZ DEFAULT NULL, -- 更新时间
|
||||
delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间
|
||||
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
|
||||
PRIMARY KEY (config_id),
|
||||
UNIQUE (optsn)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE customer_service.tb_crm_config IS 'CRM集成配置表';
|
||||
COMMENT ON TABLE workcase.tb_crm_config IS 'CRM集成配置表';
|
||||
@@ -1,11 +1,55 @@
|
||||
-- 按顺序执行初始化
|
||||
\i createDB.sql -- 创建数据库和基础扩展
|
||||
\i createTableUser.sql -- 用户表相关(核心表)
|
||||
\i createTablePermission.sql -- 权限相关(核心表)
|
||||
\i createTableFile.sql -- 文件管理
|
||||
\i createTableMessage.sql -- 消息管理
|
||||
\i createTableConfig.sql -- 配置管理
|
||||
\i createTableLog.sql -- 日志管理
|
||||
-- =============================
|
||||
-- 城市生命线AI数智化平台 - 数据库初始化脚本
|
||||
-- 按顺序执行各模块建表SQL及数据初始化
|
||||
-- =============================
|
||||
|
||||
-- 初始化基础数据(如果有)
|
||||
-- \i initBaseData.sql -- 取消注释如果需要初始化基础数据
|
||||
-- =============================
|
||||
-- 第一阶段:创建数据库和表结构
|
||||
-- =============================
|
||||
\i createDB.sql
|
||||
|
||||
-- 1. 系统基础模块
|
||||
\i createTablePermission.sql
|
||||
\i createTableUser.sql
|
||||
|
||||
-- 2. 文件管理模块
|
||||
\i createTableFile.sql
|
||||
|
||||
-- 3. 消息通知模块
|
||||
\i createTableMessage.sql
|
||||
|
||||
-- 4. 日志模块
|
||||
\i createTableLog.sql
|
||||
|
||||
-- 5. 配置管理模块
|
||||
\i createTableConfig.sql
|
||||
|
||||
-- 6. 知识库管理模块
|
||||
\i createTableKnowledge.sql
|
||||
|
||||
-- 7. 招投标业务模块
|
||||
\i createTableBidding.sql
|
||||
|
||||
-- 8. 智能客服业务模块
|
||||
\i createTableCustomerService.sql
|
||||
|
||||
-- 9. 智能体模块(暂不启用)
|
||||
-- \i createTableAgent.sql
|
||||
|
||||
-- =============================
|
||||
-- 第二阶段:初始化基础数据
|
||||
-- =============================
|
||||
|
||||
-- 1. 初始化权限相关基础数据(部门、角色、权限、视图、模块)
|
||||
\i initDataPermission.sql
|
||||
|
||||
-- 2. 初始化用户数据(管理员账户)
|
||||
\i initDataUser.sql
|
||||
|
||||
-- 3. 初始化消息渠道配置
|
||||
\i initDataMessage.sql
|
||||
|
||||
-- 4. 初始化系统配置
|
||||
\i initDataConfig.sql
|
||||
|
||||
-- 注意:文件、日志、知识库、招投标、客服等业务表无需初始化数据
|
||||
@@ -2,42 +2,56 @@
|
||||
-- 仅插入常用示例,可按需调整 value/remark
|
||||
|
||||
INSERT INTO config.tb_sys_config (
|
||||
optsn, config_id, key, value, type, description, "group", "order", status, remark,
|
||||
optsn, config_id, key, name, value, config_type, render_type, description,
|
||||
re, options, "group", module_id, order_num, status, remark,
|
||||
creator, dept_path, updater, create_time, update_time, delete_time, deleted
|
||||
) VALUES
|
||||
|
||||
-- 站点与品牌
|
||||
('CFG-0001', 'cfg_site_name', 'site.name', 'urban-lifeline 平台', 'string', '站点名称', 'site', 10, 'enabled', '展示在标题/登录/页脚', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0002', 'cfg_site_logo', 'site.logo', '/static/logo.png', 'string', '站点Logo地址', 'site', 20, 'enabled', '相对或绝对URL', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0003', 'cfg_site_icp', 'site.icp', '', 'string', 'ICP备案号', 'site', 30, 'enabled', '页脚展示', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0001', 'cfg_site_name', 'site.name', '站点名称', 'urban-lifeline 平台', 'String', 'input', '站点名称', NULL, NULL, 'site', 'mod_system', 10, 0, '展示在标题/登录/页脚', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0002', 'cfg_site_logo', 'site.logo', '站点Logo', '/static/logo.png', 'String', 'input', '站点Logo地址', NULL, NULL, 'site', 'mod_system', 20, 0, '相对或绝对URL', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0003', 'cfg_site_icp', 'site.icp', 'ICP备案号', '', 'String', 'input', 'ICP备案号', NULL, NULL, 'site', 'mod_system', 30, 0, '页脚展示', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 国际化与时区
|
||||
('CFG-0101', 'cfg_i18n_locale', 'i18n.defaultLocale', 'zh-CN', 'string', '默认语言', 'i18n', 10, 'enabled', '如 zh-CN/en-US', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0102', 'cfg_timezone', 'system.timezone', 'Asia/Shanghai', 'string', '系统默认时区', 'i18n', 20, 'enabled', 'IANA时区名', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0101', 'cfg_i18n_locale', 'i18n.defaultLocale', '默认语言', 'zh-CN', 'String', 'select', '默认语言', NULL, '["zh-CN", "en-US"]'::json, 'i18n', 'mod_system', 10, 0, '如 zh-CN/en-US', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0102', 'cfg_timezone', 'system.timezone', '系统时区', 'Asia/Shanghai', 'String', 'input', '系统默认时区', NULL, NULL, 'i18n', 'mod_system', 20, 0, 'IANA时区名', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 安全与认证
|
||||
('CFG-0201', 'cfg_pwd_policy', 'security.passwordPolicy','{"minLen":8,"upper":1,"lower":1,"digit":1,"special":0}', 'json', '密码策略', 'security', 10, 'enabled', 'JSON结构', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0202', 'cfg_jwt_exp', 'security.jwt.expireSeconds','86400', 'number', 'JWT过期秒数', 'security', 20, 'enabled', '默认24小时', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0203', 'cfg_session_timeout', 'security.session.timeoutMinutes','30', 'number', '会话超时(分钟)', 'security', 30, 'enabled', '空闲登出', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0204', 'cfg_signup_enabled', 'security.signup.enabled','false', 'bool', '是否开放注册', 'security', 40, 'enabled', '生产建议关闭', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0201', 'cfg_pwd_policy', 'security.passwordPolicy','密码策略', '{"minLen":8,"upper":1,"lower":1,"digit":1,"special":0}', 'String', 'textarea', '密码策略', NULL, NULL, 'security', 'mod_system', 10, 0, 'JSON结构', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0202', 'cfg_jwt_exp', 'security.jwt.expireSeconds','JWT过期时间', '86400', 'INTEGER', 'input', 'JWT过期秒数', NULL, NULL, 'security', 'mod_system', 20, 0, '默认24小时', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0203', 'cfg_session_timeout', 'security.session.timeoutMinutes','会话超时', '30', 'INTEGER', 'input', '会话超时(分钟)', NULL, NULL, 'security', 'mod_system', 30, 0, '空闲登出', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0204', 'cfg_signup_enabled', 'security.signup.enabled','开放注册', 'false', 'BOOLEAN', 'switch', '是否开放注册', NULL, NULL, 'security', 'mod_system', 40, 0, '生产建议关闭', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 存储与上传
|
||||
('CFG-0301', 'cfg_upload_max', 'upload.maxSizeMB', '50', 'number', '单文件最大上传(MB)', 'storage', 10, 'enabled', '前后端需一致校验', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0302', 'cfg_storage_backend', 'storage.backend', 'local', 'string', '存储后端(local/minio/s3)', 'storage', 20, 'enabled', '本地/MinIO/S3等', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0303', 'cfg_storage_base', 'storage.basePath', '/data/urban-lifeline', 'string', '本地存储基路径', 'storage', 30, 'enabled', '当 backend=local', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0301', 'cfg_upload_max', 'upload.maxSizeMB', '最大上传大小', '50', 'INTEGER', 'input', '单文件最大上传(MB)', NULL, NULL, 'storage', 'mod_file', 10, 0, '前后端需一致校验', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0302', 'cfg_storage_backend', 'storage.backend', '存储后端', 'local', 'String', 'select', '存储后端类型', NULL, '["local", "minio", "s3"]'::json, 'storage', 'mod_file', 20, 0, '本地/MinIO/S3等', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0303', 'cfg_storage_base', 'storage.basePath', '存储路径', '/data/urban-lifeline', 'String', 'input', '本地存储基路径', NULL, NULL, 'storage', 'mod_file', 30, 0, '当 backend=local', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 通知(邮件/SMS)
|
||||
('CFG-0401', 'cfg_mail_host', 'mail.smtp.host', '', 'string', 'SMTP主机', 'notify', 10, 'disabled','留空为未配置', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0402', 'cfg_mail_port', 'mail.smtp.port', '465', 'number', 'SMTP端口', 'notify', 20, 'disabled','SSL常用465', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0403', 'cfg_mail_from', 'mail.from', '', 'string', '发件人邮箱', 'notify', 30, 'disabled','如 no-reply@x.com', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0411', 'cfg_sms_provider', 'sms.provider', '', 'string', '短信服务商', 'notify', 40, 'disabled','如 aliyun/tencent', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
-- 邮件配置
|
||||
('CFG-0401', 'cfg_mail_host', 'email.host', 'SMTP服务器地址', 'smtp.qq.com', 'String', 'input', 'SMTP服务器地址', NULL, NULL, 'notify', 'mod_message', 10, 1, '邮件发送服务器地址', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0402', 'cfg_mail_port', 'email.port', 'SMTP端口', '587', 'INTEGER', 'input', 'SMTP服务器端口', NULL, NULL, 'notify', 'mod_message', 20, 1, '常用:25/465/587', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0403', 'cfg_mail_username', 'email.username', '发件人邮箱', '3223905473@qq.com', 'String', 'input', '发件人邮箱地址', NULL, NULL, 'notify', 'mod_message', 30, 1, '用于发送邮件的邮箱账号', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0404', 'cfg_mail_password', 'email.password', '邮箱授权码', 'xmdmxvtjumxocicc', 'String', 'password', '邮箱授权码/密码', NULL, NULL, 'notify', 'mod_message', 40, 1, '邮箱的授权码或密码', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0405', 'cfg_mail_fromname', 'email.fromName', '发件人名称', 'urban-lifeline平台', 'String', 'input', '发件人显示名称', NULL, NULL, 'notify', 'mod_message', 50, 1, '邮件中显示的发件人名称', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0406', 'cfg_mail_ssl', 'email.ssl.enable', '启用SSL', 'true', 'BOOLEAN', 'switch', '是否启用SSL', NULL, NULL, 'notify', 'mod_message', 60, 1, 'SSL加密连接', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0407', 'cfg_mail_timeout', 'email.timeout', '连接超时时间', '30000', 'INTEGER', 'input', '连接超时时间(毫秒)', NULL, NULL, 'notify', 'mod_message', 70, 1, 'SMTP连接超时时间(5000-60000)', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 短信配置
|
||||
('CFG-0411', 'cfg_sms_provider', 'sms.provider', '短信服务商', 'aliyun', 'String', 'select', '短信服务提供商', NULL, '["aliyun", "tencent"]'::json, 'notify', 'mod_message', 80, 1, '短信服务提供商类型', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0412', 'cfg_sms_keyid', 'sms.accessKeyId', 'AccessKey ID', 'LTAI5t68do3qVXx5Rufugt3X', 'String', 'input', '短信服务AccessKey ID', NULL, NULL, 'notify', 'mod_message', 90, 1, '云服务商的AccessKey ID', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0413', 'cfg_sms_secret', 'sms.accessKeySecret', 'AccessKey Secret', '2vD9ToIff49Vph4JQXsn0Cy8nXQfzA', 'String', 'password', '短信服务AccessKey Secret', NULL, NULL, 'notify', 'mod_message', 100, 1, '云服务商的AccessKey Secret', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0414', 'cfg_sms_sign', 'sms.signName', '短信签名', 'urban-lifeline', 'String', 'input', '短信签名', NULL, NULL, 'notify', 'mod_message', 110, 1, '发送短信使用的签名', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0415', 'cfg_sms_tpl_login', 'sms.templateCode.login', '登录验证码模板', 'SMS_491985030', 'String', 'input', '登录验证码模板编码', NULL, NULL, 'notify', 'mod_message', 120, 1, '登录验证码短信模板', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0416', 'cfg_sms_tpl_register', 'sms.templateCode.register','注册验证码模板', 'SMS_491985030', 'String', 'input', '注册验证码模板编码', NULL, NULL, 'notify', 'mod_message', 130, 1, '注册验证码短信模板', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0417', 'cfg_sms_timeout', 'sms.timeout', '请求超时时间', '30000', 'INTEGER', 'input', '请求超时时间(毫秒)', NULL, NULL, 'notify', 'mod_message', 140, 1, 'API请求超时时间(5000-60000)', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 日志与审计
|
||||
('CFG-0501', 'cfg_log_level', 'log.level', 'INFO', 'string', '系统日志级别', 'log', 10, 'enabled', 'DEBUG/INFO/WARN/ERROR', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0502', 'cfg_audit_retention', 'audit.retentionDays', '90', 'number', '审计日志保留天数', 'log', 20, 'enabled', '合规按需调整', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0501', 'cfg_log_level', 'log.level', '日志级别', 'INFO', 'String', 'select', '系统日志级别', NULL, '["DEBUG", "INFO", "WARN", "ERROR"]'::json, 'log', 'mod_system', 10, 0, 'DEBUG/INFO/WARN/ERROR', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0502', 'cfg_audit_retention', 'audit.retentionDays', '审计日志保留', '90', 'INTEGER', 'input', '审计日志保留天数', NULL, NULL, 'log', 'mod_system', 20, 0, '合规按需调整', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
|
||||
-- 平台特性
|
||||
('CFG-0601', 'cfg_maintenance', 'platform.maintenance', 'false', 'bool', '维护模式开关', 'platform', 10, 'enabled', 'true时仅管理员可用', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0602', 'cfg_feature_acl_policy', 'feature.acl.policy', 'enabled', 'string', 'ACL策略开关', 'platform', 20, 'enabled', 'enabled/disabled', 'system', NULL, NULL, now(), NULL, NULL, false);
|
||||
('CFG-0601', 'cfg_maintenance', 'platform.maintenance', '维护模式', 'false', 'BOOLEAN', 'switch', '维护模式开关', NULL, NULL, 'platform', 'mod_system', 10, 0, 'true时仅管理员可用', 'system', NULL, NULL, now(), NULL, NULL, false),
|
||||
('CFG-0602', 'cfg_feature_acl_policy','feature.acl.policy', 'ACL策略', 'enabled', 'String', 'select', 'ACL策略开关', NULL, '["enabled", "disabled"]'::json, 'platform', 'mod_system', 20, 0, 'enabled/disabled', 'system', NULL, NULL, now(), NULL, NULL, false);
|
||||
|
||||
|
||||
|
||||
118
urbanLifelineServ/.bin/database/postgres/sql/initDataMessage.sql
Normal file
118
urbanLifelineServ/.bin/database/postgres/sql/initDataMessage.sql
Normal file
@@ -0,0 +1,118 @@
|
||||
-- 初始化消息渠道配置(与 message schema 对应)
|
||||
-- 配置常用消息发送渠道
|
||||
|
||||
-- =============================
|
||||
-- 1. 初始化消息渠道
|
||||
-- =============================
|
||||
INSERT INTO message.tb_message_channel (
|
||||
optsn, channel_id, channel_code, channel_name, channel_desc,
|
||||
config, status, priority, creator, create_time, deleted
|
||||
) VALUES
|
||||
-- 应用内消息(默认渠道,优先级最高)
|
||||
('CH-0001', 'channel_app', 'app', '应用内消息', '系统内部消息通知',
|
||||
'{"enabled": true, "realtime": true}'::json,
|
||||
'enabled', 100, 'system', now(), false),
|
||||
|
||||
-- 短信通知
|
||||
('CH-0002', 'channel_sms', 'sms', '短信通知', '短信发送服务',
|
||||
'{
|
||||
"enabled": false,
|
||||
"provider": "",
|
||||
"apiKey": "",
|
||||
"apiSecret": "",
|
||||
"signName": "",
|
||||
"templateCode": ""
|
||||
}'::json,
|
||||
'disabled', 80, 'system', now(), false),
|
||||
|
||||
-- 邮件通知
|
||||
('CH-0003', 'channel_email', 'email', '邮件通知', '电子邮件发送服务',
|
||||
'{
|
||||
"enabled": false,
|
||||
"smtpHost": "",
|
||||
"smtpPort": 465,
|
||||
"username": "",
|
||||
"password": "",
|
||||
"fromAddress": "",
|
||||
"useSsl": true
|
||||
}'::json,
|
||||
'disabled', 70, 'system', now(), false),
|
||||
|
||||
-- 微信公众号
|
||||
('CH-0004', 'channel_wechat_mp', 'wechat_official_account', '微信公众号', '微信公众号模板消息',
|
||||
'{
|
||||
"enabled": false,
|
||||
"appId": "",
|
||||
"appSecret": "",
|
||||
"templateId": ""
|
||||
}'::json,
|
||||
'disabled', 60, 'system', now(), false),
|
||||
|
||||
-- 微信小程序
|
||||
('CH-0005', 'channel_wechat_mini', 'wechat_applet', '微信小程序', '微信小程序订阅消息',
|
||||
'{
|
||||
"enabled": false,
|
||||
"appId": "",
|
||||
"appSecret": "",
|
||||
"templateId": ""
|
||||
}'::json,
|
||||
'disabled', 50, 'system', now(), false),
|
||||
|
||||
-- 钉钉通知
|
||||
('CH-0006', 'channel_dingtalk', 'dingtalk', '钉钉通知', '钉钉工作通知',
|
||||
'{
|
||||
"enabled": false,
|
||||
"agentId": "",
|
||||
"appKey": "",
|
||||
"appSecret": "",
|
||||
"robotToken": ""
|
||||
}'::json,
|
||||
'disabled', 40, 'system', now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 2. 初始化消息模板(系统通用模板)
|
||||
-- =============================
|
||||
INSERT INTO message.tb_message_template (
|
||||
optsn, template_id, template_code, template_name, template_type,
|
||||
title_template, content_template, variables, service_type,
|
||||
creator, create_time, deleted
|
||||
) VALUES
|
||||
-- 用户注册欢迎消息
|
||||
('TPL-0001', 'tpl_user_welcome', 'USER_WELCOME', '用户注册欢迎', 'system',
|
||||
'欢迎加入 {{platformName}}',
|
||||
'您好,{{username}}!\n\n欢迎加入 {{platformName}} 平台。您的账号已成功创建。\n\n账号信息:\n- 用户名:{{usercode}}\n- 邮箱:{{email}}\n- 注册时间:{{registerTime}}\n\n祝您使用愉快!',
|
||||
'["platformName", "username", "usercode", "email", "registerTime"]'::jsonb,
|
||||
'system',
|
||||
'system', now(), false),
|
||||
|
||||
-- 密码重置通知
|
||||
('TPL-0002', 'tpl_password_reset', 'PASSWORD_RESET', '密码重置通知', 'system',
|
||||
'密码重置验证码',
|
||||
'您好,{{username}}!\n\n您正在重置密码,验证码为:{{code}}\n\n验证码有效期为 {{expireMinutes}} 分钟,请尽快完成操作。\n\n如非本人操作,请忽略此消息。',
|
||||
'["username", "code", "expireMinutes"]'::jsonb,
|
||||
'system',
|
||||
'system', now(), false),
|
||||
|
||||
-- 系统维护通知
|
||||
('TPL-0003', 'tpl_system_maintenance', 'SYSTEM_MAINTENANCE', '系统维护通知', 'system',
|
||||
'系统维护通知',
|
||||
'尊敬的用户:\n\n系统将于 {{startTime}} 至 {{endTime}} 进行维护升级。\n\n维护内容:{{content}}\n\n维护期间系统将暂停服务,请您提前做好相关安排。\n\n给您带来不便,敬请谅解!',
|
||||
'["startTime", "endTime", "content"]'::jsonb,
|
||||
'system',
|
||||
'system', now(), false),
|
||||
|
||||
-- 工单创建通知
|
||||
('TPL-0101', 'tpl_ticket_created', 'TICKET_CREATED', '工单创建通知', 'business',
|
||||
'新工单通知',
|
||||
'您好,{{username}}!\n\n您有一条新的工单需要处理:\n\n工单编号:{{ticketNo}}\n工单标题:{{title}}\n优先级:{{priority}}\n创建时间:{{createTime}}\n\n请及时登录系统查看处理。',
|
||||
'["username", "ticketNo", "title", "priority", "createTime"]'::jsonb,
|
||||
'customer_service',
|
||||
'system', now(), false),
|
||||
|
||||
-- 招标公告发布通知
|
||||
('TPL-0201', 'tpl_bidding_published', 'BIDDING_PUBLISHED', '招标公告发布', 'business',
|
||||
'招标公告发布通知',
|
||||
'您好!\n\n新的招标项目已发布:\n\n项目名称:{{projectName}}\n项目编号:{{projectNo}}\n发布时间:{{publishTime}}\n截止时间:{{deadlineTime}}\n\n详情请登录系统查看。',
|
||||
'["projectName", "projectNo", "publishTime", "deadlineTime"]'::jsonb,
|
||||
'bidding',
|
||||
'system', now(), false);
|
||||
@@ -0,0 +1,286 @@
|
||||
-- 初始化权限相关基础数据(与 sys schema 对应)
|
||||
-- 包含:部门、角色、模块、权限、视图及其关联关系
|
||||
|
||||
-- =============================
|
||||
-- 1. 初始化根部门
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_dept (
|
||||
optsn, dept_id, name, parent_id, dept_path, description,
|
||||
creator, create_time, deleted
|
||||
) VALUES
|
||||
('DEPT-0001', 'dept_root', '根部门', NULL, '/dept_root/', '系统根部门',
|
||||
'system', now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 2. 初始化全局角色
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_role (
|
||||
optsn, role_id, name, description, scope, owner_dept_id,
|
||||
status, creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
-- 超级管理员(全局)
|
||||
('ROLE-0001', 'role_super_admin', '超级管理员', '拥有系统所有权限的最高管理员',
|
||||
'global', NULL, true, 'system', NULL, now(), false),
|
||||
|
||||
-- 系统管理员(全局)
|
||||
('ROLE-0002', 'role_system_admin', '系统管理员', '负责系统配置和用户管理',
|
||||
'global', NULL, true, 'system', NULL, now(), false),
|
||||
|
||||
-- 普通用户(全局)
|
||||
('ROLE-0003', 'role_user', '普通用户', '系统普通用户角色',
|
||||
'global', NULL, true, 'system', NULL, now(), false),
|
||||
|
||||
-- 访客(全局)
|
||||
('ROLE-0004', 'role_guest', '访客', '系统访客角色,仅限查看基础信息',
|
||||
'global', NULL, true, 'system', NULL, now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 3. 初始化系统模块
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_module (
|
||||
optsn, module_id, name, description,
|
||||
creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
('MODULE-0001', 'module_system', '系统管理', '用户、角色、权限、部门管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0002', 'module_file', '文件管理', '文件上传、下载、关联管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0003', 'module_message', '消息通知', '消息发送、接收、模板管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0004', 'module_config', '配置管理', '系统配置参数管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0005', 'module_knowledge', '知识库', '知识文档管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0006', 'module_bidding', '招投标', '招投标业务管理',
|
||||
'system', NULL, now(), false),
|
||||
|
||||
('MODULE-0007', 'module_customer_service', '智能客服', '客服工单管理',
|
||||
'system', NULL, now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 4. 初始化系统权限
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_permission (
|
||||
optsn, permission_id, name, code, description, module_id,
|
||||
status, creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
-- 系统管理模块权限
|
||||
('PERM-0001', 'perm_user_view', '用户查看', 'system:user:view', '查看用户列表和详情', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0002', 'perm_user_create', '用户创建', 'system:user:create', '创建新用户', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0003', 'perm_user_edit', '用户编辑', 'system:user:edit', '编辑用户信息', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0004', 'perm_user_delete', '用户删除', 'system:user:delete', '删除用户', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
('PERM-0011', 'perm_role_view', '角色查看', 'system:role:view', '查看角色列表和详情', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0012', 'perm_role_create', '角色创建', 'system:role:create', '创建新角色', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0013', 'perm_role_edit', '角色编辑', 'system:role:edit', '编辑角色信息', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0014', 'perm_role_delete', '角色删除', 'system:role:delete', '删除角色', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
('PERM-0021', 'perm_dept_view', '部门查看', 'system:dept:view', '查看部门列表和详情', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0022', 'perm_dept_create', '部门创建', 'system:dept:create', '创建新部门', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0023', 'perm_dept_edit', '部门编辑', 'system:dept:edit', '编辑部门信息', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0024', 'perm_dept_delete', '部门删除', 'system:dept:delete', '删除部门', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
('PERM-0031', 'perm_permission_view', '权限查看', 'system:permission:view', '查看权限列表', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0032', 'perm_permission_manage', '权限管理', 'system:permission:manage', '管理权限配置', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
-- 系统管理模块导出权限
|
||||
('PERM-0041', 'perm_user_export', '用户导出', 'system:user:export', '导出用户数据', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0042', 'perm_role_export', '角色导出', 'system:role:export', '导出角色数据', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0043', 'perm_dept_export', '部门导出', 'system:dept:export', '导出部门数据', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
-- 文件管理模块权限
|
||||
('PERM-0101', 'perm_file_view', '文件查看', 'file:file:view', '查看文件列表', 'module_file',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0102', 'perm_file_upload', '文件上传', 'file:file:upload', '上传文件', 'module_file',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0103', 'perm_file_download', '文件下载', 'file:file:download', '下载文件', 'module_file',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0104', 'perm_file_delete', '文件删除', 'file:file:delete', '删除文件', 'module_file',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0105', 'perm_file_export', '文件导出', 'file:file:export', '导出文件列表数据', 'module_file',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
-- 消息通知模块权限
|
||||
('PERM-0201', 'perm_message_view', '消息查看', 'message:message:view', '查看消息列表', 'module_message',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0202', 'perm_message_send', '消息发送', 'message:message:send', '发送消息通知', 'module_message',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0203', 'perm_message_manage', '消息管理', 'message:message:manage', '管理消息模板和配置', 'module_message',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0204', 'perm_message_export', '消息导出', 'message:message:export', '导出消息数据', 'module_message',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
-- 配置管理模块权限
|
||||
('PERM-0301', 'perm_config_view', '配置查看', 'config:config:view', '查看系统配置', 'module_config',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0302', 'perm_config_edit', '配置编辑', 'config:config:edit', '修改系统配置', 'module_config',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0303', 'perm_config_export', '配置导出', 'config:config:export', '导出系统配置数据', 'module_config',
|
||||
true, 'system', NULL, now(), false),
|
||||
|
||||
-- 日志模块权限
|
||||
('PERM-0401', 'perm_log_view', '日志查看', 'log:log:view', '查看系统日志', 'module_system',
|
||||
true, 'system', NULL, now(), false),
|
||||
('PERM-0402', 'perm_log_export', '日志导出', 'log:log:export', '导出系统日志数据', 'module_system',
|
||||
true, 'system', NULL, now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 5. 初始化视图(菜单)
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_view (
|
||||
optsn, view_id, name, parent_id, url, component, icon, type,
|
||||
layout, order_num, description, creator, create_time, deleted
|
||||
) VALUES
|
||||
-- 一级菜单
|
||||
('VIEW-0001', 'view_system', '系统管理', NULL, '/system', NULL, 'Settings', 0,
|
||||
'MainLayout', 100, '系统管理菜单', 'system', now(), false),
|
||||
|
||||
('VIEW-0002', 'view_business', '业务管理', NULL, '/business', NULL, 'Briefcase', 0,
|
||||
'MainLayout', 200, '业务管理菜单', 'system', now(), false),
|
||||
|
||||
-- 系统管理子菜单
|
||||
('VIEW-0101', 'view_user', '用户管理', 'view_system', '/system/user', 'system/UserList', 'Users', 1,
|
||||
'MainLayout', 10, '用户管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0102', 'view_role', '角色管理', 'view_system', '/system/role', 'system/RoleList', 'Shield', 1,
|
||||
'MainLayout', 20, '角色管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0103', 'view_dept', '部门管理', 'view_system', '/system/dept', 'system/DeptList', 'Building', 1,
|
||||
'MainLayout', 30, '部门管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0104', 'view_permission', '权限管理', 'view_system', '/system/permission', 'system/PermissionList', 'Lock', 1,
|
||||
'MainLayout', 40, '权限管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0105', 'view_config', '配置管理', 'view_system', '/system/config', 'system/ConfigList', 'Settings', 1,
|
||||
'MainLayout', 50, '配置管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0106', 'view_file', '文件管理', 'view_system', '/system/file', 'system/FileList', 'FileText', 1,
|
||||
'MainLayout', 60, '文件管理页面', 'system', now(), false),
|
||||
|
||||
('VIEW-0107', 'view_message', '消息管理', 'view_system', '/system/message', 'system/MessageList', 'Mail', 1,
|
||||
'MainLayout', 70, '消息管理页面', 'system', now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 6. 角色权限关联(超级管理员拥有所有权限)
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_role_permission (
|
||||
optsn, role_id, permission_id, creator, dept_path, create_time, deleted
|
||||
)
|
||||
SELECT
|
||||
'RP-' || LPAD(ROW_NUMBER() OVER (ORDER BY permission_id)::TEXT, 4, '0'),
|
||||
'role_super_admin',
|
||||
permission_id,
|
||||
'system',
|
||||
NULL,
|
||||
now(),
|
||||
false
|
||||
FROM sys.tb_sys_permission
|
||||
WHERE deleted = false;
|
||||
|
||||
-- 系统管理员权限(除了用户删除外的系统管理权限)
|
||||
INSERT INTO sys.tb_sys_role_permission (
|
||||
optsn, role_id, permission_id, creator, dept_path, create_time, deleted
|
||||
)
|
||||
SELECT
|
||||
'RP-SA-' || LPAD(ROW_NUMBER() OVER (ORDER BY permission_id)::TEXT, 4, '0'),
|
||||
'role_system_admin',
|
||||
permission_id,
|
||||
'system',
|
||||
NULL,
|
||||
now(),
|
||||
false
|
||||
FROM sys.tb_sys_permission
|
||||
WHERE deleted = false
|
||||
AND code NOT IN ('system:user:delete', 'system:role:delete', 'system:dept:delete')
|
||||
AND module_id IN ('module_system', 'module_file', 'module_message', 'module_config');
|
||||
|
||||
-- 普通用户权限(基础查看和文件操作)
|
||||
INSERT INTO sys.tb_sys_role_permission (
|
||||
optsn, role_id, permission_id, creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
('RP-U-0001', 'role_user', 'perm_user_view', 'system', NULL, now(), false),
|
||||
('RP-U-0002', 'role_user', 'perm_file_view', 'system', NULL, now(), false),
|
||||
('RP-U-0003', 'role_user', 'perm_file_upload', 'system', NULL, now(), false),
|
||||
('RP-U-0004', 'role_user', 'perm_file_download', 'system', NULL, now(), false),
|
||||
('RP-U-0005', 'role_user', 'perm_message_view', 'system', NULL, now(), false),
|
||||
('RP-U-0006', 'role_user', 'perm_config_view', 'system', NULL, now(), false);
|
||||
|
||||
-- 访客权限(仅查看)
|
||||
INSERT INTO sys.tb_sys_role_permission (
|
||||
optsn, role_id, permission_id, creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
('RP-G-0001', 'role_guest', 'perm_user_view', 'system', NULL, now(), false),
|
||||
('RP-G-0002', 'role_guest', 'perm_file_view', 'system', NULL, now(), false),
|
||||
('RP-G-0003', 'role_guest', 'perm_message_view', 'system', NULL, now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 7. 视图权限关联
|
||||
-- =============================
|
||||
-- 将视图与对应模块的权限关联
|
||||
INSERT INTO sys.tb_sys_view_permission (
|
||||
optsn, view_id, permission_id, creator, dept_path, create_time, deleted
|
||||
) VALUES
|
||||
-- 用户管理视图关联用户权限
|
||||
('VP-0001', 'view_user', 'perm_user_view', 'system', NULL, now(), false),
|
||||
('VP-0002', 'view_user', 'perm_user_create', 'system', NULL, now(), false),
|
||||
('VP-0003', 'view_user', 'perm_user_edit', 'system', NULL, now(), false),
|
||||
('VP-0004', 'view_user', 'perm_user_delete', 'system', NULL, now(), false),
|
||||
('VP-0005', 'view_user', 'perm_user_export', 'system', NULL, now(), false),
|
||||
|
||||
-- 角色管理视图关联角色权限
|
||||
('VP-0011', 'view_role', 'perm_role_view', 'system', NULL, now(), false),
|
||||
('VP-0012', 'view_role', 'perm_role_create', 'system', NULL, now(), false),
|
||||
('VP-0013', 'view_role', 'perm_role_edit', 'system', NULL, now(), false),
|
||||
('VP-0014', 'view_role', 'perm_role_delete', 'system', NULL, now(), false),
|
||||
('VP-0015', 'view_role', 'perm_role_export', 'system', NULL, now(), false),
|
||||
|
||||
-- 部门管理视图关联部门权限
|
||||
('VP-0021', 'view_dept', 'perm_dept_view', 'system', NULL, now(), false),
|
||||
('VP-0022', 'view_dept', 'perm_dept_create', 'system', NULL, now(), false),
|
||||
('VP-0023', 'view_dept', 'perm_dept_edit', 'system', NULL, now(), false),
|
||||
('VP-0024', 'view_dept', 'perm_dept_delete', 'system', NULL, now(), false),
|
||||
('VP-0025', 'view_dept', 'perm_dept_export', 'system', NULL, now(), false),
|
||||
|
||||
-- 权限管理视图关联权限管理权限
|
||||
('VP-0031', 'view_permission', 'perm_permission_view', 'system', NULL, now(), false),
|
||||
('VP-0032', 'view_permission', 'perm_permission_manage', 'system', NULL, now(), false),
|
||||
|
||||
-- 配置管理视图关联配置权限
|
||||
('VP-0041', 'view_config', 'perm_config_view', 'system', NULL, now(), false),
|
||||
('VP-0042', 'view_config', 'perm_config_edit', 'system', NULL, now(), false),
|
||||
('VP-0043', 'view_config', 'perm_config_export', 'system', NULL, now(), false),
|
||||
|
||||
-- 文件管理视图关联文件权限
|
||||
('VP-0051', 'view_file', 'perm_file_view', 'system', NULL, now(), false),
|
||||
('VP-0052', 'view_file', 'perm_file_upload', 'system', NULL, now(), false),
|
||||
('VP-0053', 'view_file', 'perm_file_download', 'system', NULL, now(), false),
|
||||
('VP-0054', 'view_file', 'perm_file_delete', 'system', NULL, now(), false),
|
||||
('VP-0055', 'view_file', 'perm_file_export', 'system', NULL, now(), false),
|
||||
|
||||
-- 消息管理视图关联消息权限
|
||||
('VP-0061', 'view_message', 'perm_message_view', 'system', NULL, now(), false),
|
||||
('VP-0062', 'view_message', 'perm_message_send', 'system', NULL, now(), false),
|
||||
('VP-0063', 'view_message', 'perm_message_manage', 'system', NULL, now(), false),
|
||||
('VP-0064', 'view_message', 'perm_message_export', 'system', NULL, now(), false);
|
||||
@@ -0,0 +1,64 @@
|
||||
-- 初始化用户数据(与 sys schema 对应)
|
||||
-- 创建系统管理员账户和示例用户
|
||||
|
||||
-- =============================
|
||||
-- 1. 创建超级管理员用户
|
||||
-- =============================
|
||||
-- 注意:密码需要使用 bcrypt 加密,这里使用的是 'admin123' 的 bcrypt hash
|
||||
-- 实际部署时应该修改为安全的密码
|
||||
INSERT INTO sys.tb_sys_user (
|
||||
optsn, user_id, usercode, password, email, phone,
|
||||
create_time, status, deleted
|
||||
) VALUES
|
||||
('USER-0001', 'user_admin', 'admin',
|
||||
'$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7q0TP/Hza', -- admin123
|
||||
'admin@urbanlifeline.com', '13800138000',
|
||||
now(), 1, false);
|
||||
|
||||
-- 超级管理员用户信息
|
||||
INSERT INTO sys.tb_sys_user_info (
|
||||
optsn, user_id, username, avatar, gender, level, remark,
|
||||
create_time, deleted
|
||||
) VALUES
|
||||
('UINFO-0001', 'user_admin', '系统管理员',
|
||||
'/static/avatar/admin.png', 1, 10, '系统超级管理员账户',
|
||||
now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 2. 关联超级管理员角色
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_user_role (
|
||||
optsn, user_id, role_id, dept_id, dept_path,
|
||||
creator, create_time, deleted
|
||||
) VALUES
|
||||
('UR-0001', 'user_admin', 'role_super_admin', 'dept_root', '/dept_root/',
|
||||
'system', now(), false);
|
||||
|
||||
-- =============================
|
||||
-- 3. 创建示例普通用户(可选)
|
||||
-- =============================
|
||||
INSERT INTO sys.tb_sys_user (
|
||||
optsn, user_id, usercode, password, email, phone,
|
||||
create_time, status, deleted
|
||||
) VALUES
|
||||
('USER-0002', 'user_demo', 'demo',
|
||||
'$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7q0TP/Hza', -- admin123
|
||||
'demo@urbanlifeline.com', '13800138001',
|
||||
now(), 1, false);
|
||||
|
||||
-- 示例用户信息
|
||||
INSERT INTO sys.tb_sys_user_info (
|
||||
optsn, user_id, username, avatar, gender, level, remark,
|
||||
create_time, deleted
|
||||
) VALUES
|
||||
('UINFO-0002', 'user_demo', '演示用户',
|
||||
'/static/avatar/demo.png', 0, 1, '系统演示账户',
|
||||
now(), false);
|
||||
|
||||
-- 关联普通用户角色
|
||||
INSERT INTO sys.tb_sys_user_role (
|
||||
optsn, user_id, role_id, dept_id, dept_path,
|
||||
creator, create_time, deleted
|
||||
) VALUES
|
||||
('UR-0002', 'user_demo', 'role_user', 'dept_root', '/dept_root/',
|
||||
'system', now(), false);
|
||||
@@ -1,549 +0,0 @@
|
||||
-- =============================
|
||||
-- 数据库优化补丁脚本
|
||||
-- 基于现有表结构的增强和修改
|
||||
-- =============================
|
||||
|
||||
-- =============================
|
||||
-- 1. 用户模块优化
|
||||
-- =============================
|
||||
|
||||
-- 1.1 移除登录日志表中的敏感密码字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'sys'
|
||||
AND table_name = 'tb_sys_login_log'
|
||||
AND column_name = 'password'
|
||||
) THEN
|
||||
ALTER TABLE sys.tb_sys_login_log DROP COLUMN password;
|
||||
RAISE NOTICE '已移除登录日志表的密码字段';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 1.2 创建用户部门关联表
|
||||
CREATE TABLE IF NOT EXISTS sys.tb_sys_user_dept (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
user_id VARCHAR(50) NOT NULL,
|
||||
dept_id VARCHAR(50) NOT NULL,
|
||||
is_primary BOOLEAN DEFAULT false,
|
||||
position VARCHAR(100),
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
updater VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
delete_time timestamptz DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (user_id, dept_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (user_id) REFERENCES sys.tb_sys_user(user_id),
|
||||
FOREIGN KEY (dept_id) REFERENCES sys.tb_sys_dept(dept_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE sys.tb_sys_user_dept IS '用户部门关联表';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_dept.is_primary IS '是否主部门';
|
||||
COMMENT ON COLUMN sys.tb_sys_user_dept.position IS '职位';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_dept_user ON sys.tb_sys_user_dept(user_id) WHERE deleted = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_user_dept_dept ON sys.tb_sys_user_dept(dept_id) WHERE deleted = false;
|
||||
|
||||
-- 1.3 用户表添加主部门字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'sys'
|
||||
AND table_name = 'tb_sys_user'
|
||||
AND column_name = 'primary_dept_id'
|
||||
) THEN
|
||||
ALTER TABLE sys.tb_sys_user ADD COLUMN primary_dept_id VARCHAR(50);
|
||||
COMMENT ON COLUMN sys.tb_sys_user.primary_dept_id IS '主部门ID';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- =============================
|
||||
-- 2. 权限模块优化
|
||||
-- =============================
|
||||
|
||||
-- 2.1 角色表添加排序字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'sys'
|
||||
AND table_name = 'tb_sys_role'
|
||||
AND column_name = 'order_num'
|
||||
) THEN
|
||||
ALTER TABLE sys.tb_sys_role ADD COLUMN order_num INTEGER DEFAULT 0;
|
||||
COMMENT ON COLUMN sys.tb_sys_role.order_num IS '排序号';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 2.2 权限表添加权限类型字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'sys'
|
||||
AND table_name = 'tb_sys_permission'
|
||||
AND column_name = 'permission_type'
|
||||
) THEN
|
||||
ALTER TABLE sys.tb_sys_permission ADD COLUMN permission_type VARCHAR(20) DEFAULT 'action';
|
||||
COMMENT ON COLUMN sys.tb_sys_permission.permission_type IS '权限类型:action-操作权限/data-数据权限/menu-菜单权限';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- =============================
|
||||
-- 3. 文件模块扩展
|
||||
-- =============================
|
||||
|
||||
-- 3.1 文件表添加版本管理字段
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'file'
|
||||
AND table_name = 'tb_sys_file'
|
||||
AND column_name = 'version'
|
||||
) THEN
|
||||
ALTER TABLE file.tb_sys_file
|
||||
ADD COLUMN version VARCHAR(20) DEFAULT '1.0',
|
||||
ADD COLUMN parent_file_id VARCHAR(50),
|
||||
ADD COLUMN is_latest BOOLEAN DEFAULT true;
|
||||
|
||||
COMMENT ON COLUMN file.tb_sys_file.version IS '文件版本号';
|
||||
COMMENT ON COLUMN file.tb_sys_file.parent_file_id IS '父文件ID(版本链)';
|
||||
COMMENT ON COLUMN file.tb_sys_file.is_latest IS '是否最新版本';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3.2 文件表添加分类和标签
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'file'
|
||||
AND table_name = 'tb_sys_file'
|
||||
AND column_name = 'category'
|
||||
) THEN
|
||||
ALTER TABLE file.tb_sys_file
|
||||
ADD COLUMN category VARCHAR(100),
|
||||
ADD COLUMN tags TEXT[],
|
||||
ADD COLUMN metadata JSONB;
|
||||
|
||||
COMMENT ON COLUMN file.tb_sys_file.category IS '文件分类';
|
||||
COMMENT ON COLUMN file.tb_sys_file.tags IS '文件标签数组';
|
||||
COMMENT ON COLUMN file.tb_sys_file.metadata IS '文件元数据';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3.3 创建文件关联表
|
||||
CREATE TABLE IF NOT EXISTS file.tb_file_relation (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
relation_id VARCHAR(50) NOT NULL,
|
||||
file_id VARCHAR(50) NOT NULL,
|
||||
object_type VARCHAR(50) NOT NULL,
|
||||
object_id VARCHAR(50) NOT NULL,
|
||||
relation_type VARCHAR(30) DEFAULT 'attachment',
|
||||
order_num INTEGER DEFAULT 0,
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
updater VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
delete_time timestamptz DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (relation_id),
|
||||
UNIQUE (optsn),
|
||||
FOREIGN KEY (file_id) REFERENCES file.tb_sys_file(file_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE file.tb_file_relation IS '文件关联表';
|
||||
COMMENT ON COLUMN file.tb_file_relation.object_type IS '对象类型:bidding_project/ticket/document等';
|
||||
COMMENT ON COLUMN file.tb_file_relation.object_id IS '对象ID';
|
||||
COMMENT ON COLUMN file.tb_file_relation.relation_type IS '关联类型:attachment-附件/avatar-头像/banner-横幅';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_file_relation_object
|
||||
ON file.tb_file_relation(object_type, object_id) WHERE deleted = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_file_relation_file
|
||||
ON file.tb_file_relation(file_id) WHERE deleted = false;
|
||||
|
||||
-- =============================
|
||||
-- 4. 消息模块增强
|
||||
-- =============================
|
||||
|
||||
-- 4.1 创建消息模板表
|
||||
CREATE TABLE IF NOT EXISTS message.tb_message_template (
|
||||
optsn VARCHAR(50) NOT NULL,
|
||||
template_id VARCHAR(50) NOT NULL,
|
||||
template_code VARCHAR(100) NOT NULL,
|
||||
template_name VARCHAR(255) NOT NULL,
|
||||
template_type VARCHAR(30) NOT NULL,
|
||||
title_template TEXT,
|
||||
content_template TEXT NOT NULL,
|
||||
variables JSONB,
|
||||
dept_path VARCHAR(255) DEFAULT NULL,
|
||||
creator VARCHAR(50) DEFAULT NULL,
|
||||
updater VARCHAR(50) DEFAULT NULL,
|
||||
create_time timestamptz NOT NULL DEFAULT now(),
|
||||
update_time timestamptz DEFAULT NULL,
|
||||
delete_time timestamptz DEFAULT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (template_id),
|
||||
UNIQUE (optsn),
|
||||
UNIQUE (template_code)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE message.tb_message_template IS '消息模板表';
|
||||
COMMENT ON COLUMN message.tb_message_template.template_type IS '模板类型:system-系统/business-业务';
|
||||
COMMENT ON COLUMN message.tb_message_template.variables IS '模板变量定义';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_template_type
|
||||
ON message.tb_message_template(template_type) WHERE deleted = false;
|
||||
|
||||
-- =============================
|
||||
-- 5. 日志模块优化
|
||||
-- =============================
|
||||
|
||||
-- 5.1 日志表添加trace_id用于链路追踪
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'log'
|
||||
AND table_name = 'tb_sys_log'
|
||||
AND column_name = 'trace_id'
|
||||
) THEN
|
||||
ALTER TABLE log.tb_sys_log
|
||||
ADD COLUMN trace_id VARCHAR(50),
|
||||
ADD COLUMN span_id VARCHAR(50),
|
||||
ADD COLUMN parent_span_id VARCHAR(50);
|
||||
|
||||
COMMENT ON COLUMN log.tb_sys_log.trace_id IS '追踪ID(用于分布式追踪)';
|
||||
COMMENT ON COLUMN log.tb_sys_log.span_id IS '跨度ID';
|
||||
COMMENT ON COLUMN log.tb_sys_log.parent_span_id IS '父跨度ID';
|
||||
|
||||
CREATE INDEX idx_log_trace ON log.tb_sys_log(trace_id) WHERE trace_id IS NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- =============================
|
||||
-- 6. 全文搜索索引
|
||||
-- =============================
|
||||
|
||||
-- 6.1 为知识文档标题创建全文搜索索引
|
||||
CREATE INDEX IF NOT EXISTS idx_knowledge_doc_title_trgm
|
||||
ON knowledge.tb_knowledge_document USING gin(title gin_trgm_ops)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- 6.2 为招标项目名称创建全文搜索索引
|
||||
CREATE INDEX IF NOT EXISTS idx_project_name_trgm
|
||||
ON bidding.tb_bidding_project USING gin(project_name gin_trgm_ops)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- 6.3 为客户姓名创建全文搜索索引
|
||||
CREATE INDEX IF NOT EXISTS idx_customer_name_trgm
|
||||
ON customer_service.tb_customer USING gin(customer_name gin_trgm_ops)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- =============================
|
||||
-- 7. JSONB字段优化索引
|
||||
-- =============================
|
||||
|
||||
-- 7.1 智能体配置JSONB索引
|
||||
CREATE INDEX IF NOT EXISTS idx_agent_model_config_gin
|
||||
ON agent.tb_agent USING gin(model_config)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- 7.2 工单元数据JSONB索引
|
||||
CREATE INDEX IF NOT EXISTS idx_ticket_metadata_gin
|
||||
ON customer_service.tb_ticket USING gin(metadata)
|
||||
WHERE deleted = false;
|
||||
|
||||
-- =============================
|
||||
-- 8. 性能优化视图
|
||||
-- =============================
|
||||
|
||||
-- 8.1 用户完整权限视图(包含ACL)
|
||||
CREATE OR REPLACE VIEW sys.v_user_full_permissions AS
|
||||
WITH user_roles AS (
|
||||
-- 用户直接拥有的角色权限
|
||||
SELECT DISTINCT
|
||||
ur.user_id,
|
||||
p.permission_id,
|
||||
p.code AS permission_code,
|
||||
p.name AS permission_name,
|
||||
'role' AS source_type,
|
||||
r.role_id AS source_id
|
||||
FROM sys.tb_sys_user_role ur
|
||||
JOIN sys.tb_sys_role r ON ur.role_id = r.role_id
|
||||
JOIN sys.tb_sys_role_permission rp ON r.role_id = rp.role_id
|
||||
JOIN sys.tb_sys_permission p ON rp.permission_id = p.permission_id
|
||||
WHERE ur.deleted = false
|
||||
AND r.deleted = false
|
||||
AND rp.deleted = false
|
||||
AND p.deleted = false
|
||||
),
|
||||
user_acls AS (
|
||||
-- 用户的ACL权限
|
||||
SELECT DISTINCT
|
||||
principal_id AS user_id,
|
||||
object_type || ':' || object_id AS permission_id,
|
||||
object_type || '_' ||
|
||||
CASE
|
||||
WHEN (permission & 1) = 1 THEN 'read'
|
||||
WHEN (permission & 2) = 2 THEN 'write'
|
||||
WHEN (permission & 4) = 4 THEN 'exec'
|
||||
END AS permission_code,
|
||||
'ACL permission on ' || object_type AS permission_name,
|
||||
'acl' AS source_type,
|
||||
acl_id AS source_id
|
||||
FROM sys.tb_sys_acl
|
||||
WHERE principal_type = 'user'
|
||||
AND allow = true
|
||||
AND deleted = false
|
||||
)
|
||||
SELECT * FROM user_roles
|
||||
UNION ALL
|
||||
SELECT * FROM user_acls;
|
||||
|
||||
COMMENT ON VIEW sys.v_user_full_permissions IS '用户完整权限视图(包含角色权限和ACL权限)';
|
||||
|
||||
-- 8.2 智能体实时状态视图
|
||||
CREATE OR REPLACE VIEW agent.v_agent_realtime_status AS
|
||||
SELECT
|
||||
a.agent_id,
|
||||
a.agent_name,
|
||||
a.agent_type,
|
||||
a.status,
|
||||
COUNT(DISTINCT s.session_id) FILTER (WHERE s.session_status = 'active') AS active_sessions,
|
||||
COUNT(DISTINCT s.user_id) FILTER (WHERE s.start_time > now() - interval '24 hours') AS daily_users,
|
||||
COALESCE(SUM(s.message_count) FILTER (WHERE s.start_time > now() - interval '1 hour'), 0) AS hourly_messages,
|
||||
COALESCE(AVG(r.rating) FILTER (WHERE r.create_time > now() - interval '7 days'), 0) AS weekly_avg_rating
|
||||
FROM agent.tb_agent a
|
||||
LEFT JOIN agent.tb_agent_session s ON a.agent_id = s.agent_id AND s.deleted = false
|
||||
LEFT JOIN agent.tb_agent_rating r ON a.agent_id = r.agent_id AND r.deleted = false
|
||||
WHERE a.deleted = false
|
||||
GROUP BY a.agent_id, a.agent_name, a.agent_type, a.status;
|
||||
|
||||
COMMENT ON VIEW agent.v_agent_realtime_status IS '智能体实时状态视图';
|
||||
|
||||
-- 8.3 工单处理效率视图
|
||||
CREATE OR REPLACE VIEW customer_service.v_ticket_efficiency AS
|
||||
SELECT
|
||||
DATE(t.create_time) AS stat_date,
|
||||
t.ticket_type,
|
||||
t.priority,
|
||||
COUNT(*) AS total_tickets,
|
||||
COUNT(*) FILTER (WHERE t.ticket_status = 'resolved') AS resolved_tickets,
|
||||
COUNT(*) FILTER (WHERE t.is_overdue) AS overdue_tickets,
|
||||
AVG(EXTRACT(EPOCH FROM (t.response_time - t.create_time))/60) AS avg_response_minutes,
|
||||
AVG(EXTRACT(EPOCH FROM (t.resolution_time - t.create_time))/3600) FILTER (WHERE t.resolution_time IS NOT NULL) AS avg_resolution_hours,
|
||||
AVG(t.customer_rating) FILTER (WHERE t.customer_rating IS NOT NULL) AS avg_rating
|
||||
FROM customer_service.tb_ticket t
|
||||
WHERE t.deleted = false
|
||||
AND t.create_time > now() - interval '90 days'
|
||||
GROUP BY DATE(t.create_time), t.ticket_type, t.priority;
|
||||
|
||||
COMMENT ON VIEW customer_service.v_ticket_efficiency IS '工单处理效率统计视图';
|
||||
|
||||
-- =============================
|
||||
-- 9. 审计触发器增强
|
||||
-- =============================
|
||||
|
||||
-- 9.1 创建审计日志函数
|
||||
CREATE OR REPLACE FUNCTION public.audit_trigger_func()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
audit_data JSONB;
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
audit_data := jsonb_build_object(
|
||||
'operation', 'DELETE',
|
||||
'table', TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'old_data', row_to_json(OLD)
|
||||
);
|
||||
|
||||
INSERT INTO log.tb_sys_log (
|
||||
optsn, log_id, type, level, module, message, data, creator
|
||||
) VALUES (
|
||||
'AUDIT_' || gen_random_uuid()::text,
|
||||
gen_random_uuid()::text,
|
||||
'audit',
|
||||
'info',
|
||||
TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'Record deleted',
|
||||
audit_data,
|
||||
COALESCE(current_setting('app.current_user_id', true), 'system')
|
||||
);
|
||||
RETURN OLD;
|
||||
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
audit_data := jsonb_build_object(
|
||||
'operation', 'UPDATE',
|
||||
'table', TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'old_data', row_to_json(OLD),
|
||||
'new_data', row_to_json(NEW)
|
||||
);
|
||||
|
||||
INSERT INTO log.tb_sys_log (
|
||||
optsn, log_id, type, level, module, message, data, creator
|
||||
) VALUES (
|
||||
'AUDIT_' || gen_random_uuid()::text,
|
||||
gen_random_uuid()::text,
|
||||
'audit',
|
||||
'info',
|
||||
TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'Record updated',
|
||||
audit_data,
|
||||
COALESCE(current_setting('app.current_user_id', true), 'system')
|
||||
);
|
||||
RETURN NEW;
|
||||
|
||||
ELSIF (TG_OP = 'INSERT') THEN
|
||||
audit_data := jsonb_build_object(
|
||||
'operation', 'INSERT',
|
||||
'table', TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'new_data', row_to_json(NEW)
|
||||
);
|
||||
|
||||
INSERT INTO log.tb_sys_log (
|
||||
optsn, log_id, type, level, module, message, data, creator
|
||||
) VALUES (
|
||||
'AUDIT_' || gen_random_uuid()::text,
|
||||
gen_random_uuid()::text,
|
||||
'audit',
|
||||
'info',
|
||||
TG_TABLE_SCHEMA || '.' || TG_TABLE_NAME,
|
||||
'Record created',
|
||||
audit_data,
|
||||
COALESCE(current_setting('app.current_user_id', true), 'system')
|
||||
);
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION public.audit_trigger_func() IS '审计日志触发器函数';
|
||||
|
||||
-- =============================
|
||||
-- 10. 数据归档函数
|
||||
-- =============================
|
||||
|
||||
-- 10.1 创建日志归档函数
|
||||
CREATE OR REPLACE FUNCTION public.archive_old_logs(
|
||||
p_months_to_keep INTEGER DEFAULT 6
|
||||
)
|
||||
RETURNS TABLE(
|
||||
archived_count INTEGER,
|
||||
deleted_count INTEGER
|
||||
) AS $$
|
||||
DECLARE
|
||||
v_cutoff_date TIMESTAMPTZ;
|
||||
v_archived INTEGER := 0;
|
||||
v_deleted INTEGER := 0;
|
||||
BEGIN
|
||||
v_cutoff_date := now() - (p_months_to_keep || ' months')::INTERVAL;
|
||||
|
||||
-- 归档系统日志
|
||||
CREATE TABLE IF NOT EXISTS log.tb_sys_log_archived (LIKE log.tb_sys_log INCLUDING ALL);
|
||||
|
||||
WITH moved_rows AS (
|
||||
INSERT INTO log.tb_sys_log_archived
|
||||
SELECT * FROM log.tb_sys_log
|
||||
WHERE create_time < v_cutoff_date
|
||||
RETURNING *
|
||||
)
|
||||
SELECT COUNT(*) INTO v_archived FROM moved_rows;
|
||||
|
||||
DELETE FROM log.tb_sys_log
|
||||
WHERE create_time < v_cutoff_date;
|
||||
|
||||
GET DIAGNOSTICS v_deleted = ROW_COUNT;
|
||||
|
||||
RETURN QUERY SELECT v_archived, v_deleted;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION public.archive_old_logs IS '归档旧日志数据';
|
||||
|
||||
-- 10.2 创建API调用日志归档函数
|
||||
CREATE OR REPLACE FUNCTION agent.archive_api_logs(
|
||||
p_months_to_keep INTEGER DEFAULT 3
|
||||
)
|
||||
RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
v_cutoff_date TIMESTAMPTZ;
|
||||
v_archived INTEGER;
|
||||
BEGIN
|
||||
v_cutoff_date := now() - (p_months_to_keep || ' months')::INTERVAL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agent.tb_api_call_log_archived (LIKE agent.tb_api_call_log INCLUDING ALL);
|
||||
|
||||
WITH moved_rows AS (
|
||||
INSERT INTO agent.tb_api_call_log_archived
|
||||
SELECT * FROM agent.tb_api_call_log
|
||||
WHERE create_time < v_cutoff_date
|
||||
RETURNING *
|
||||
)
|
||||
SELECT COUNT(*) INTO v_archived FROM moved_rows;
|
||||
|
||||
DELETE FROM agent.tb_api_call_log
|
||||
WHERE create_time < v_cutoff_date;
|
||||
|
||||
RETURN v_archived;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION agent.archive_api_logs IS '归档旧API调用日志';
|
||||
|
||||
-- =============================
|
||||
-- 11. 性能监控函数
|
||||
-- =============================
|
||||
|
||||
-- 11.1 表膨胀检查函数
|
||||
CREATE OR REPLACE FUNCTION public.check_table_bloat()
|
||||
RETURNS TABLE(
|
||||
schemaname TEXT,
|
||||
tablename TEXT,
|
||||
table_size_mb NUMERIC,
|
||||
bloat_size_mb NUMERIC,
|
||||
bloat_ratio NUMERIC
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
s.schemaname::TEXT,
|
||||
s.tablename::TEXT,
|
||||
ROUND(pg_total_relation_size(s.schemaname || '.' || s.tablename)::NUMERIC / 1024 / 1024, 2) AS table_size_mb,
|
||||
ROUND((pg_total_relation_size(s.schemaname || '.' || s.tablename) - pg_relation_size(s.schemaname || '.' || s.tablename))::NUMERIC / 1024 / 1024, 2) AS bloat_size_mb,
|
||||
ROUND(((pg_total_relation_size(s.schemaname || '.' || s.tablename) - pg_relation_size(s.schemaname || '.' || s.tablename))::NUMERIC / NULLIF(pg_total_relation_size(s.schemaname || '.' || s.tablename), 0) * 100), 2) AS bloat_ratio
|
||||
FROM pg_tables s
|
||||
WHERE s.schemaname IN ('sys', 'file', 'message', 'log', 'config', 'knowledge', 'bidding', 'customer_service', 'agent')
|
||||
ORDER BY pg_total_relation_size(s.schemaname || '.' || s.tablename) DESC;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION public.check_table_bloat IS '检查表膨胀情况';
|
||||
|
||||
-- =============================
|
||||
-- 执行完成提示
|
||||
-- =============================
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE '==============================';
|
||||
RAISE NOTICE '数据库优化补丁执行完成!';
|
||||
RAISE NOTICE '==============================';
|
||||
RAISE NOTICE '已完成以下优化:';
|
||||
RAISE NOTICE '1. 用户模块:移除敏感字段、添加部门关联';
|
||||
RAISE NOTICE '2. 权限模块:添加排序和类型字段';
|
||||
RAISE NOTICE '3. 文件模块:版本管理、分类标签、关联表';
|
||||
RAISE NOTICE '4. 消息模块:消息模板表';
|
||||
RAISE NOTICE '5. 日志模块:链路追踪支持';
|
||||
RAISE NOTICE '6. 全文搜索:添加GIN索引';
|
||||
RAISE NOTICE '7. JSONB优化:添加GIN索引';
|
||||
RAISE NOTICE '8. 性能视图:用户权限、智能体状态、工单效率';
|
||||
RAISE NOTICE '9. 审计增强:完整审计触发器';
|
||||
RAISE NOTICE '10. 数据归档:日志和API调用归档函数';
|
||||
RAISE NOTICE '11. 监控工具:表膨胀检查函数';
|
||||
RAISE NOTICE '==============================';
|
||||
END $$;
|
||||
@@ -22,22 +22,22 @@ USE `nacos_config`;
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
|
||||
`data_id` VARCHAR(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` VARCHAR(128) DEFAULT NULL COMMENT 'group_id',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
|
||||
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
|
||||
`effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',
|
||||
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
|
||||
`src_ip` VARCHAR(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` VARCHAR(128) DEFAULT '' COMMENT '租户字段',
|
||||
`c_desc` VARCHAR(256) DEFAULT NULL COMMENT 'configuration description',
|
||||
`c_use` VARCHAR(64) DEFAULT NULL COMMENT 'configuration usage',
|
||||
`effect` VARCHAR(64) DEFAULT NULL COMMENT '配置生效的描述',
|
||||
`type` VARCHAR(64) DEFAULT NULL COMMENT '配置的类型',
|
||||
`c_schema` text COMMENT '配置的模式',
|
||||
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
`encrypted_data_key` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
|
||||
@@ -47,19 +47,19 @@ CREATE TABLE `config_info` (
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info_gray` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`data_id` VARCHAR(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` VARCHAR(128) NOT NULL COMMENT 'group_id',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5',
|
||||
`src_user` text COMMENT 'src_user',
|
||||
`src_ip` varchar(100) DEFAULT NULL COMMENT 'src_ip',
|
||||
`src_ip` VARCHAR(100) DEFAULT NULL COMMENT 'src_ip',
|
||||
`gmt_create` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_create',
|
||||
`gmt_modified` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_modified',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`gray_name` varchar(128) NOT NULL COMMENT 'gray_name',
|
||||
`app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` VARCHAR(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`gray_name` VARCHAR(128) NOT NULL COMMENT 'gray_name',
|
||||
`gray_rule` text NOT NULL COMMENT 'gray_rule',
|
||||
`encrypted_data_key` varchar(256) NOT NULL DEFAULT '' COMMENT 'encrypted_data_key',
|
||||
`encrypted_data_key` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'encrypted_data_key',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfogray_datagrouptenantgray` (`data_id`,`group_id`,`tenant_id`,`gray_name`),
|
||||
KEY `idx_dataid_gmt_modified` (`data_id`,`gmt_modified`),
|
||||
@@ -71,11 +71,11 @@ CREATE TABLE `config_info_gray` (
|
||||
/******************************************/
|
||||
CREATE TABLE `config_tags_relation` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'id',
|
||||
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
|
||||
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`tag_name` VARCHAR(128) NOT NULL COMMENT 'tag_name',
|
||||
`tag_type` VARCHAR(64) DEFAULT NULL COMMENT 'tag_type',
|
||||
`data_id` VARCHAR(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` VARCHAR(128) NOT NULL COMMENT 'group_id',
|
||||
`tenant_id` VARCHAR(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',
|
||||
PRIMARY KEY (`nid`),
|
||||
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
|
||||
@@ -87,7 +87,7 @@ CREATE TABLE `config_tags_relation` (
|
||||
/******************************************/
|
||||
CREATE TABLE `group_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
|
||||
`group_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
@@ -106,20 +106,20 @@ CREATE TABLE `group_capacity` (
|
||||
CREATE TABLE `his_config_info` (
|
||||
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`data_id` VARCHAR(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` VARCHAR(128) NOT NULL COMMENT 'group_id',
|
||||
`app_name` VARCHAR(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`md5` VARCHAR(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`src_ip` VARCHAR(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
`publish_type` varchar(50) DEFAULT 'formal' COMMENT 'publish type gray or formal',
|
||||
`gray_name` varchar(50) DEFAULT NULL COMMENT 'gray name',
|
||||
`tenant_id` VARCHAR(128) DEFAULT '' COMMENT '租户字段',
|
||||
`encrypted_data_key` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
`publish_type` VARCHAR(50) DEFAULT 'formal' COMMENT 'publish type gray or formal',
|
||||
`gray_name` VARCHAR(50) DEFAULT NULL COMMENT 'gray name',
|
||||
`ext_info` longtext DEFAULT NULL COMMENT 'ext info',
|
||||
PRIMARY KEY (`nid`),
|
||||
KEY `idx_gmt_create` (`gmt_create`),
|
||||
@@ -133,7 +133,7 @@ CREATE TABLE `his_config_info` (
|
||||
/******************************************/
|
||||
CREATE TABLE `tenant_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
|
||||
`tenant_id` VARCHAR(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
@@ -149,11 +149,11 @@ CREATE TABLE `tenant_capacity` (
|
||||
|
||||
CREATE TABLE `tenant_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`kp` varchar(128) NOT NULL COMMENT 'kp',
|
||||
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
|
||||
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
|
||||
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
|
||||
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
|
||||
`kp` VARCHAR(128) NOT NULL COMMENT 'kp',
|
||||
`tenant_id` VARCHAR(128) default '' COMMENT 'tenant_id',
|
||||
`tenant_name` VARCHAR(128) default '' COMMENT 'tenant_name',
|
||||
`tenant_desc` VARCHAR(256) DEFAULT NULL COMMENT 'tenant_desc',
|
||||
`create_source` VARCHAR(32) DEFAULT NULL COMMENT 'create_source',
|
||||
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
@@ -162,21 +162,21 @@ CREATE TABLE `tenant_info` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
|
||||
`password` varchar(500) NOT NULL COMMENT 'password',
|
||||
`enabled` boolean NOT NULL COMMENT 'enabled'
|
||||
`username` VARCHAR(50) NOT NULL PRIMARY KEY COMMENT 'username',
|
||||
`password` VARCHAR(500) NOT NULL COMMENT 'password',
|
||||
`enabled` BOOLEAN NOT NULL COMMENT 'enabled'
|
||||
);
|
||||
|
||||
CREATE TABLE `roles` (
|
||||
`username` varchar(50) NOT NULL COMMENT 'username',
|
||||
`role` varchar(50) NOT NULL COMMENT 'role',
|
||||
`username` VARCHAR(50) NOT NULL COMMENT 'username',
|
||||
`role` VARCHAR(50) NOT NULL COMMENT 'role',
|
||||
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
|
||||
);
|
||||
|
||||
CREATE TABLE `permissions` (
|
||||
`role` varchar(50) NOT NULL COMMENT 'role',
|
||||
`resource` varchar(128) NOT NULL COMMENT 'resource',
|
||||
`action` varchar(8) NOT NULL COMMENT 'action',
|
||||
`role` VARCHAR(50) NOT NULL COMMENT 'role',
|
||||
`resource` VARCHAR(128) NOT NULL COMMENT 'resource',
|
||||
`action` VARCHAR(8) NOT NULL COMMENT 'action',
|
||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||
);
|
||||
|
||||
|
||||
1
urbanLifelineServ/.pids/auth.pid
Normal file
1
urbanLifelineServ/.pids/auth.pid
Normal file
@@ -0,0 +1 @@
|
||||
1028
|
||||
1
urbanLifelineServ/.pids/gateway.pid
Normal file
1
urbanLifelineServ/.pids/gateway.pid
Normal file
@@ -0,0 +1 @@
|
||||
1003
|
||||
1
urbanLifelineServ/.pids/system.pid
Normal file
1
urbanLifelineServ/.pids/system.pid
Normal file
@@ -0,0 +1 @@
|
||||
1053
|
||||
163
urbanLifelineServ/.vscode/launch.json
vendored
163
urbanLifelineServ/.vscode/launch.json
vendored
@@ -3,21 +3,162 @@
|
||||
"configurations": [
|
||||
{
|
||||
"type": "java",
|
||||
"name": "SystemApp",
|
||||
"name": "Gateway (8180)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.SystemApp",
|
||||
"mainClass": "org.xyzh.gateway.GatewayApplication",
|
||||
"projectName": "gateway",
|
||||
"cwd": "${workspaceFolder}/gateway",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8180"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Auth (8181)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.auth.AuthApp",
|
||||
"projectName": "auth",
|
||||
"cwd": "${workspaceFolder}/auth",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8181"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "System (8182)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.system.SystemApp",
|
||||
"projectName": "system",
|
||||
"cwd": "${workspaceFolder}/system",
|
||||
"args": [
|
||||
"--spring.profiles.active=dev"
|
||||
],
|
||||
"vmArgs": [
|
||||
"-Dspring.profiles.active=dev"
|
||||
],
|
||||
"env": {
|
||||
"SPRING_PROFILES_ACTIVE": "dev"
|
||||
},
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8182"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Log (8183)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.log.LogApp",
|
||||
"projectName": "log",
|
||||
"cwd": "${workspaceFolder}/log",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8183"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "File (8184)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.file.FileApp",
|
||||
"projectName": "file",
|
||||
"cwd": "${workspaceFolder}/file",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8184"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Message (8185)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.message.MessageApp",
|
||||
"projectName": "message",
|
||||
"cwd": "${workspaceFolder}/message",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8185"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Bidding (8186)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.bidding.BiddingApp",
|
||||
"projectName": "bidding",
|
||||
"cwd": "${workspaceFolder}/bidding",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8186"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Platform (8187)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.platform.PlatformApp",
|
||||
"projectName": "platform",
|
||||
"cwd": "${workspaceFolder}/platform",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8187"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Workcase (8188)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.workcase.WorkcaseApp",
|
||||
"projectName": "workcase",
|
||||
"cwd": "${workspaceFolder}/workcase",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8188"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Crontab (8189)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.crontab.CrontabApp",
|
||||
"projectName": "crontab",
|
||||
"cwd": "${workspaceFolder}/crontab",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8189"],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Agent (8190)",
|
||||
"request": "launch",
|
||||
"mainClass": "org.xyzh.agent.AgentApp",
|
||||
"projectName": "agent",
|
||||
"cwd": "${workspaceFolder}/agent",
|
||||
"args": ["--spring.profiles.active=dev"],
|
||||
"vmArgs": ["-Dserver.port=8190"],
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Core Services (Gateway + Auth + System)",
|
||||
"configurations": [
|
||||
"Gateway (8180)",
|
||||
"Auth (8181)",
|
||||
"System (8182)"
|
||||
],
|
||||
"stopAll": true,
|
||||
"presentation": {
|
||||
"hidden": false,
|
||||
"group": "服务组合",
|
||||
"order": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "All Services",
|
||||
"configurations": [
|
||||
"Gateway (8180)",
|
||||
"Auth (8181)",
|
||||
"System (8182)",
|
||||
"Log (8183)",
|
||||
"File (8184)",
|
||||
"Message (8185)",
|
||||
"Bidding (8186)",
|
||||
"Platform (8187)",
|
||||
"Workcase (8188)",
|
||||
"Crontab (8189)",
|
||||
"Agent (8190)"
|
||||
],
|
||||
"stopAll": true,
|
||||
"presentation": {
|
||||
"hidden": false,
|
||||
"group": "服务组合",
|
||||
"order": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
" <result column=\"create_time\" property=\"createTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"update_time\" property=\"updateTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"delete_time\" property=\"deleteTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"deleted\" property=\"deleted\" jdbcType=\"BOOLEAN\"/>",
|
||||
" <result column=\"deleted\" property=\"deleted\" jdbcType=\"Boolean\"/>",
|
||||
" </resultMap>",
|
||||
"",
|
||||
" <!-- 基础列 -->",
|
||||
@@ -154,7 +154,7 @@
|
||||
" <result column=\"create_time\" property=\"createTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"update_time\" property=\"updateTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"delete_time\" property=\"deleteTime\" jdbcType=\"TIMESTAMP\"/>",
|
||||
" <result column=\"deleted\" property=\"deleted\" jdbcType=\"BOOLEAN\"/>",
|
||||
" <result column=\"deleted\" property=\"deleted\" jdbcType=\"Boolean\"/>",
|
||||
" </resultMap>"
|
||||
],
|
||||
"description": "MyBatis ResultMap 映射"
|
||||
|
||||
23
urbanLifelineServ/.vscode/settings.json
vendored
23
urbanLifelineServ/.vscode/settings.json
vendored
@@ -4,12 +4,31 @@
|
||||
"maven.view": "hierarchical",
|
||||
"tabSize": 4,
|
||||
"java.debug.settings.onBuildFailureProceed": true,
|
||||
"java.configuration.maven.userSettings": null,
|
||||
"java.configuration.maven.userSettings": "",
|
||||
"java.import.maven.enabled": true,
|
||||
"java.project.referencedLibraries": [
|
||||
"**/*.jar"
|
||||
],
|
||||
"maven.terminal.useJavaHome": true,
|
||||
"java.configuration.runtimes": [],
|
||||
"Codegeex.RepoIndex": true
|
||||
"Codegeex.RepoIndex": true,
|
||||
"terminal.integrated.defaultProfile.windows": "Command Prompt",
|
||||
"terminal.integrated.profiles.windows": {
|
||||
"PowerShell": {
|
||||
"source": "PowerShell",
|
||||
"args": ["-NoExit", "-Command", "chcp 65001"]
|
||||
},
|
||||
"Command Prompt": {
|
||||
"path": "cmd.exe",
|
||||
"args": ["/k", "chcp 65001"]
|
||||
},
|
||||
"Git Bash": {
|
||||
"path": "F:\\Environment\\Git\\bin\\bash.exe",
|
||||
"args": ["-i"],
|
||||
"env": {
|
||||
"LANG": "zh_CN.UTF-8",
|
||||
"LC_ALL": "zh_CN.UTF-8"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
247
urbanLifelineServ/Makefile
Normal file
247
urbanLifelineServ/Makefile
Normal file
@@ -0,0 +1,247 @@
|
||||
# ================================================
|
||||
# Urban Lifeline 微服务管理 Makefile
|
||||
# ================================================
|
||||
|
||||
# 项目根目录
|
||||
PROJECT_ROOT := $(shell pwd)
|
||||
|
||||
# Maven 命令
|
||||
MAVEN := mvn
|
||||
MAVEN_OPTS := -Dmaven.test.skip=true
|
||||
|
||||
# 服务列表
|
||||
SERVICES := gateway auth system log file message bidding platform workcase crontab agent
|
||||
|
||||
# 服务端口映射
|
||||
PORT_gateway := 8080
|
||||
PORT_auth := 8081
|
||||
PORT_system := 8082
|
||||
PORT_log := 8083
|
||||
PORT_file := 8084
|
||||
PORT_message := 8085
|
||||
PORT_bidding := 8086
|
||||
PORT_platform := 8087
|
||||
PORT_workcase := 8088
|
||||
PORT_crontab := 8089
|
||||
PORT_agent := 8090
|
||||
|
||||
# 服务主类映射
|
||||
MAINCLASS_gateway := org.xyzh.gateway.GatewayApplication
|
||||
MAINCLASS_auth := org.xyzh.auth.AuthApp
|
||||
MAINCLASS_system := org.xyzh.system.SystemApp
|
||||
MAINCLASS_log := org.xyzh.log.LogApp
|
||||
MAINCLASS_file := org.xyzh.file.FileApp
|
||||
MAINCLASS_message := org.xyzh.message.MessageApp
|
||||
MAINCLASS_bidding := org.xyzh.bidding.BiddingApp
|
||||
MAINCLASS_platform := org.xyzh.platform.PlatformApp
|
||||
MAINCLASS_workcase := org.xyzh.workcase.WorkcaseApp
|
||||
MAINCLASS_crontab := org.xyzh.crontab.CrontabApp
|
||||
MAINCLASS_agent := org.xyzh.agent.AgentApp
|
||||
|
||||
# PID 文件目录
|
||||
PID_DIR := $(PROJECT_ROOT)/.pids
|
||||
LOG_DIR := $(PROJECT_ROOT)/.logs
|
||||
|
||||
# 颜色定义
|
||||
COLOR_RESET := \033[0m
|
||||
COLOR_GREEN := \033[0;32m
|
||||
COLOR_YELLOW := \033[0;33m
|
||||
COLOR_BLUE := \033[0;34m
|
||||
COLOR_RED := \033[0;31m
|
||||
|
||||
# ================================================
|
||||
# 帮助信息
|
||||
# ================================================
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)"
|
||||
@echo "$(COLOR_BLUE) Urban Lifeline 微服务管理工具$(COLOR_RESET)"
|
||||
@echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)构建命令:$(COLOR_RESET)"
|
||||
@echo " make build - 构建所有服务"
|
||||
@echo " make build-<service> - 构建指定服务 (如: make build-system)"
|
||||
@echo " make clean - 清理所有服务"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)启动命令:$(COLOR_RESET)"
|
||||
@echo " make start - 启动所有服务"
|
||||
@echo " make start-<service> - 启动指定服务 (如: make start-system)"
|
||||
@echo " make start-core - 启动核心服务 (gateway, auth, system)"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)停止命令:$(COLOR_RESET)"
|
||||
@echo " make stop - 停止所有服务"
|
||||
@echo " make stop-<service> - 停止指定服务 (如: make stop-system)"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)重启命令:$(COLOR_RESET)"
|
||||
@echo " make restart - 重启所有服务"
|
||||
@echo " make restart-<service> - 重启指定服务 (如: make restart-system)"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)状态查看:$(COLOR_RESET)"
|
||||
@echo " make status - 查看所有服务状态"
|
||||
@echo " make status-<service> - 查看指定服务状态"
|
||||
@echo " make logs-<service> - 查看指定服务日志"
|
||||
@echo ""
|
||||
@echo "$(COLOR_GREEN)可用服务:$(COLOR_RESET)"
|
||||
@echo " $(SERVICES)"
|
||||
@echo ""
|
||||
|
||||
# ================================================
|
||||
# 初始化目录
|
||||
# ================================================
|
||||
.PHONY: init-dirs
|
||||
init-dirs:
|
||||
@mkdir -p $(PID_DIR)
|
||||
@mkdir -p $(LOG_DIR)
|
||||
|
||||
# ================================================
|
||||
# 构建相关
|
||||
# ================================================
|
||||
.PHONY: build
|
||||
build: init-dirs
|
||||
@echo "$(COLOR_YELLOW)开始构建所有服务...$(COLOR_RESET)"
|
||||
@$(MAVEN) clean install $(MAVEN_OPTS)
|
||||
@echo "$(COLOR_GREEN)✓ 所有服务构建完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: $(addprefix build-,$(SERVICES))
|
||||
$(addprefix build-,$(SERVICES)): build-%:
|
||||
@echo "$(COLOR_YELLOW)开始构建 $* 服务...$(COLOR_RESET)"
|
||||
@cd $(PROJECT_ROOT)/$* && $(MAVEN) clean install $(MAVEN_OPTS)
|
||||
@echo "$(COLOR_GREEN)✓ $* 服务构建完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "$(COLOR_YELLOW)开始清理所有服务...$(COLOR_RESET)"
|
||||
@$(MAVEN) clean
|
||||
@rm -rf $(PID_DIR)
|
||||
@rm -rf $(LOG_DIR)
|
||||
@echo "$(COLOR_GREEN)✓ 清理完成$(COLOR_RESET)"
|
||||
|
||||
# ================================================
|
||||
# 启动服务
|
||||
# ================================================
|
||||
.PHONY: start
|
||||
start: init-dirs $(addprefix start-,$(SERVICES))
|
||||
@echo "$(COLOR_GREEN)✓ 所有服务启动完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: start-core
|
||||
start-core: init-dirs start-gateway start-auth start-system
|
||||
@echo "$(COLOR_GREEN)✓ 核心服务启动完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: $(addprefix start-,$(SERVICES))
|
||||
$(addprefix start-,$(SERVICES)): start-%:
|
||||
@if [ -f "$(PID_DIR)/$*.pid" ] && kill -0 $$(cat $(PID_DIR)/$*.pid) 2>/dev/null; then \
|
||||
echo "$(COLOR_YELLOW)⚠ $* 服务已在运行中 (PID: $$(cat $(PID_DIR)/$*.pid))$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_BLUE)启动 $* 服务...$(COLOR_RESET)"; \
|
||||
nohup $(MAVEN) -pl $* spring-boot:run > $(LOG_DIR)/$*.log 2>&1 & \
|
||||
echo $$! > $(PID_DIR)/$*.pid; \
|
||||
sleep 2; \
|
||||
if kill -0 $$(cat $(PID_DIR)/$*.pid) 2>/dev/null; then \
|
||||
echo "$(COLOR_GREEN)✓ $* 服务启动成功 (PID: $$(cat $(PID_DIR)/$*.pid), Port: $(PORT_$*))$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_RED)✗ $* 服务启动失败$(COLOR_RESET)"; \
|
||||
rm -f $(PID_DIR)/$*.pid; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
# ================================================
|
||||
# 停止服务
|
||||
# ================================================
|
||||
.PHONY: stop
|
||||
stop: $(addprefix stop-,$(SERVICES))
|
||||
@echo "$(COLOR_GREEN)✓ 所有服务停止完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: $(addprefix stop-,$(SERVICES))
|
||||
$(addprefix stop-,$(SERVICES)): stop-%:
|
||||
@if [ -f "$(PID_DIR)/$*.pid" ]; then \
|
||||
PID=$$(cat $(PID_DIR)/$*.pid); \
|
||||
if kill -0 $$PID 2>/dev/null; then \
|
||||
echo "$(COLOR_YELLOW)停止 $* 服务 (PID: $$PID)...$(COLOR_RESET)"; \
|
||||
kill $$PID; \
|
||||
sleep 2; \
|
||||
if kill -0 $$PID 2>/dev/null; then \
|
||||
echo "$(COLOR_RED)强制停止 $* 服务...$(COLOR_RESET)"; \
|
||||
kill -9 $$PID; \
|
||||
fi; \
|
||||
rm -f $(PID_DIR)/$*.pid; \
|
||||
echo "$(COLOR_GREEN)✓ $* 服务已停止$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_YELLOW)⚠ $* 服务未运行$(COLOR_RESET)"; \
|
||||
rm -f $(PID_DIR)/$*.pid; \
|
||||
fi; \
|
||||
else \
|
||||
echo "$(COLOR_YELLOW)⚠ $* 服务未运行$(COLOR_RESET)"; \
|
||||
fi
|
||||
|
||||
# ================================================
|
||||
# 重启服务
|
||||
# ================================================
|
||||
.PHONY: restart
|
||||
restart: stop start
|
||||
@echo "$(COLOR_GREEN)✓ 所有服务重启完成$(COLOR_RESET)"
|
||||
|
||||
.PHONY: $(addprefix restart-,$(SERVICES))
|
||||
$(addprefix restart-,$(SERVICES)): restart-%: stop-% start-%
|
||||
@echo "$(COLOR_GREEN)✓ $* 服务重启完成$(COLOR_RESET)"
|
||||
|
||||
# ================================================
|
||||
# 查看状态
|
||||
# ================================================
|
||||
.PHONY: status
|
||||
status:
|
||||
@echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)"
|
||||
@echo "$(COLOR_BLUE) 服务运行状态$(COLOR_RESET)"
|
||||
@echo "$(COLOR_BLUE)=============================================$(COLOR_RESET)"
|
||||
@for service in $(SERVICES); do \
|
||||
printf "%-15s" "$$service:"; \
|
||||
if [ -f "$(PID_DIR)/$$service.pid" ]; then \
|
||||
PID=$$(cat $(PID_DIR)/$$service.pid); \
|
||||
if kill -0 $$PID 2>/dev/null; then \
|
||||
echo "$(COLOR_GREEN)✓ Running (PID: $$PID)$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_RED)✗ Stopped$(COLOR_RESET)"; \
|
||||
rm -f $(PID_DIR)/$$service.pid; \
|
||||
fi; \
|
||||
else \
|
||||
echo "$(COLOR_YELLOW)○ Not Started$(COLOR_RESET)"; \
|
||||
fi; \
|
||||
done
|
||||
@echo ""
|
||||
|
||||
.PHONY: $(addprefix status-,$(SERVICES))
|
||||
$(addprefix status-,$(SERVICES)): status-%:
|
||||
@if [ -f "$(PID_DIR)/$*.pid" ]; then \
|
||||
PID=$$(cat $(PID_DIR)/$*.pid); \
|
||||
if kill -0 $$PID 2>/dev/null; then \
|
||||
echo "$(COLOR_GREEN)✓ $* 服务运行中 (PID: $$PID, Port: $(PORT_$*))$(COLOR_RESET)"; \
|
||||
else \
|
||||
echo "$(COLOR_RED)✗ $* 服务已停止$(COLOR_RESET)"; \
|
||||
fi; \
|
||||
else \
|
||||
echo "$(COLOR_YELLOW)○ $* 服务未启动$(COLOR_RESET)"; \
|
||||
fi
|
||||
|
||||
# ================================================
|
||||
# 查看日志
|
||||
# ================================================
|
||||
.PHONY: $(addprefix logs-,$(SERVICES))
|
||||
$(addprefix logs-,$(SERVICES)): logs-%:
|
||||
@if [ -f "$(LOG_DIR)/$*.log" ]; then \
|
||||
tail -f $(LOG_DIR)/$*.log; \
|
||||
else \
|
||||
echo "$(COLOR_YELLOW)⚠ $* 服务日志文件不存在$(COLOR_RESET)"; \
|
||||
fi
|
||||
|
||||
# ================================================
|
||||
# 快捷命令
|
||||
# ================================================
|
||||
.PHONY: dev
|
||||
dev: start-core
|
||||
@echo "$(COLOR_GREEN)✓ 开发环境启动完成 (gateway, auth, system)$(COLOR_RESET)"
|
||||
|
||||
.PHONY: prod
|
||||
prod: start
|
||||
@echo "$(COLOR_GREEN)✓ 生产环境启动完成$(COLOR_RESET)"
|
||||
|
||||
# 默认目标
|
||||
.DEFAULT_GOAL := help
|
||||
21
urbanLifelineServ/agent/pom.xml
Normal file
21
urbanLifelineServ/agent/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>urban-lifeline</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>agent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.xyzh.agent;
|
||||
|
||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDubbo // 启用 Dubbo 服务
|
||||
@ComponentScan(basePackages = {
|
||||
"org.xyzh.agent", // 当前agent模块
|
||||
"org.xyzh.common" // 公共模块
|
||||
})
|
||||
public class AgentApp {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AgentApp.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
logger.info("======================== AgentApp 启动中 =========================");
|
||||
SpringApplication.run(AgentApp.class, args);
|
||||
logger.info("======================== AgentApp 启动成功 =========================");
|
||||
}
|
||||
}
|
||||
89
urbanLifelineServ/agent/src/main/resources/application.yml
Normal file
89
urbanLifelineServ/agent/src/main/resources/application.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
# ================== Server ==================
|
||||
server:
|
||||
port: 8190
|
||||
servlet:
|
||||
context-path: /urban-lifeline/agent
|
||||
|
||||
# ================== Auth ====================
|
||||
urban-lifeline:
|
||||
auth:
|
||||
enabled: true
|
||||
whitelist:
|
||||
- /swagger-ui/**
|
||||
- /swagger-ui.html
|
||||
- /v3/api-docs/**
|
||||
- /webjars/**
|
||||
- /favicon.ico
|
||||
- /error
|
||||
- /actuator/health
|
||||
- /actuator/info
|
||||
|
||||
security:
|
||||
aes:
|
||||
secret-key: 1234567890qwer
|
||||
|
||||
# ================== Spring ==================
|
||||
spring:
|
||||
application:
|
||||
name: agent-service
|
||||
|
||||
# ================== Spring Cloud Nacos ==================
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
namespace: dev
|
||||
group: DEFAULT_GROUP
|
||||
|
||||
# ================== DataSource ==================
|
||||
datasource:
|
||||
url: jdbc:postgresql://127.0.0.1:5432/urban_lifeline
|
||||
username: postgres
|
||||
password: postgres
|
||||
driver-class-name: org.postgresql.Driver
|
||||
|
||||
# ================== Redis ==================
|
||||
data:
|
||||
redis:
|
||||
host: 127.0.0.1 # 如果是 docker 跑的 redis,按实际 host / 端口改
|
||||
port: 6379
|
||||
database: 0
|
||||
password: 123456 # 如果有密码就填上,没密码可以去掉这一行
|
||||
|
||||
# ================== SpringDoc ==================
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: true
|
||||
path: /v3/api-docs
|
||||
swagger-ui:
|
||||
enabled: true
|
||||
path: /swagger-ui.html
|
||||
group-configs:
|
||||
- group: 'default'
|
||||
display-name: 'AI代理服务 API'
|
||||
paths-to-match: '/**'
|
||||
|
||||
# ================== Dubbo + Nacos ==================
|
||||
dubbo:
|
||||
application:
|
||||
name: urban-lifeline-agent
|
||||
qos-enable: false
|
||||
protocol:
|
||||
name: dubbo
|
||||
port: -1
|
||||
registry:
|
||||
address: nacos://127.0.0.1:8848
|
||||
scan:
|
||||
base-packages: org.xyzh.agent.service.impl
|
||||
|
||||
# ================== MyBatis ==================
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath:mapper/**/*.xml
|
||||
type-aliases-package: org.xyzh.common.dto, org.xyzh.api
|
||||
|
||||
# ================== Logging ==================
|
||||
logging:
|
||||
config: classpath:log4j2.xml
|
||||
charset:
|
||||
console: UTF-8
|
||||
file: UTF-8
|
||||
85
urbanLifelineServ/agent/src/main/resources/log4j2.xml
Normal file
85
urbanLifelineServ/agent/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration status="WARN" monitorInterval="30">
|
||||
<Properties>
|
||||
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
|
||||
<property name="FILE_PATH" value="./logs" />
|
||||
<property name="FILE_NAME" value="agent-service" />
|
||||
<property name="file.encoding" value="UTF-8" />
|
||||
<property name="console.encoding" value="UTF-8" />
|
||||
</Properties>
|
||||
|
||||
<appenders>
|
||||
<console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</console>
|
||||
|
||||
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/${FILE_NAME}-info.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
|
||||
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/${FILE_NAME}-warn.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
|
||||
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/${FILE_NAME}-error.log"
|
||||
filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
|
||||
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy interval="1"/>
|
||||
<SizeBasedTriggeringPolicy size="100MB"/>
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="30"/>
|
||||
</RollingFile>
|
||||
</appenders>
|
||||
|
||||
<loggers>
|
||||
<logger name="com.alibaba.nacos" level="info" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.mybatis" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</logger>
|
||||
|
||||
<Logger name="org.springframework" level="info" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Logger>
|
||||
|
||||
<Logger name="org.xyzh.agent" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="RollingFileInfo"/>
|
||||
<AppenderRef ref="RollingFileWarn"/>
|
||||
<AppenderRef ref="RollingFileError"/>
|
||||
</Logger>
|
||||
|
||||
<Logger name="org.xyzh.common" level="debug" additivity="false">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="RollingFileInfo"/>
|
||||
<AppenderRef ref="RollingFileWarn"/>
|
||||
<AppenderRef ref="RollingFileError"/>
|
||||
</Logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="Console"/>
|
||||
<appender-ref ref="RollingFileInfo"/>
|
||||
<appender-ref ref="RollingFileWarn"/>
|
||||
<appender-ref ref="RollingFileError"/>
|
||||
</root>
|
||||
</loggers>
|
||||
</configuration>
|
||||
21
urbanLifelineServ/apis/api-agent/pom.xml
Normal file
21
urbanLifelineServ/apis/api-agent/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>apis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-agent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.xyzh.api.agent;
|
||||
|
||||
/**
|
||||
* Agent服务接口
|
||||
* 用于知识库和文档管理
|
||||
*/
|
||||
public interface AgentService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.xyzh.api.agent.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* 知识库DTO
|
||||
* 用于创建和更新知识库
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识库DTO")
|
||||
public class KnowledgeBaseDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "知识库ID(更新时需要)")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "智能体ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "知识库名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库类型:bidding-招投标/customer_service-客服/internal-内部协同")
|
||||
private String kbType;
|
||||
|
||||
@Schema(description = "访问级别:public-公开/private-私有/internal-内部")
|
||||
private String accessLevel;
|
||||
|
||||
@Schema(description = "知识库描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "存储路径")
|
||||
private String storagePath;
|
||||
|
||||
@Schema(description = "当前版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "知识库配置")
|
||||
private JsonNode config;
|
||||
|
||||
@Schema(description = "服务类型")
|
||||
private String serviceType;
|
||||
|
||||
@Schema(description = "状态:active-激活/inactive-停用/archived-归档")
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.xyzh.api.agent.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* 知识文档片段DTO
|
||||
* 用于创建和更新知识文档片段
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识文档片段DTO")
|
||||
public class KnowledgeChunkDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "片段ID(更新时需要)")
|
||||
private String chunkId;
|
||||
|
||||
@Schema(description = "所属文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "所属知识库ID")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "片段索引")
|
||||
private Integer chunkIndex;
|
||||
|
||||
@Schema(description = "片段内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "片段类型:text-文本/table-表格/image-图片")
|
||||
private String chunkType;
|
||||
|
||||
@Schema(description = "根chunk ID")
|
||||
private String rootChunkId;
|
||||
|
||||
@Schema(description = "是否当前版本", defaultValue = "true")
|
||||
private Boolean isCurrent;
|
||||
|
||||
@Schema(description = "位置信息")
|
||||
private JsonNode positionInfo;
|
||||
|
||||
@Schema(description = "片段元数据")
|
||||
private JsonNode metadata;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.xyzh.api.agent.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识文档DTO
|
||||
* 用于创建和更新知识文档
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识文档DTO")
|
||||
public class KnowledgeDocumentDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档ID(更新时需要)")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "所属知识库ID")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "文档标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "文档类型:text-文本/pdf/word/excel/image/video")
|
||||
private String docType;
|
||||
|
||||
@Schema(description = "文档分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "文档内容(文本类型)")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "关联文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "MIME类型")
|
||||
private String mimeType;
|
||||
|
||||
@Schema(description = "根文档ID")
|
||||
private String rootDocId;
|
||||
|
||||
@Schema(description = "文档标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "来源URL")
|
||||
private String sourceUrl;
|
||||
|
||||
@Schema(description = "服务类型")
|
||||
private String serviceType;
|
||||
|
||||
@Schema(description = "文档元数据")
|
||||
private JsonNode metadata;
|
||||
|
||||
@Schema(description = "状态:active-激活/inactive-停用/archived-归档")
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.xyzh.api.agent.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 知识库VO
|
||||
* 用于前端展示知识库信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识库VO")
|
||||
public class KnowledgeBaseVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "知识库ID")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "智能体ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "智能体名称")
|
||||
private String agentName;
|
||||
|
||||
@Schema(description = "知识库名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库类型")
|
||||
private String kbType;
|
||||
|
||||
@Schema(description = "知识库类型名称")
|
||||
private String kbTypeName;
|
||||
|
||||
@Schema(description = "访问级别")
|
||||
private String accessLevel;
|
||||
|
||||
@Schema(description = "访问级别名称")
|
||||
private String accessLevelName;
|
||||
|
||||
@Schema(description = "知识库描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "存储路径")
|
||||
private String storagePath;
|
||||
|
||||
@Schema(description = "当前版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "知识库配置")
|
||||
private JsonNode config;
|
||||
|
||||
@Schema(description = "服务类型")
|
||||
private String serviceType;
|
||||
|
||||
@Schema(description = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "文档总数")
|
||||
private Long documentCount;
|
||||
|
||||
@Schema(description = "已向量化文档数")
|
||||
private Long embeddedDocCount;
|
||||
|
||||
@Schema(description = "chunk总数")
|
||||
private Long chunkCount;
|
||||
|
||||
@Schema(description = "总存储大小(字节)")
|
||||
private Long totalSize;
|
||||
|
||||
@Schema(description = "总存储大小格式化显示")
|
||||
private String totalSizeFormatted;
|
||||
|
||||
@Schema(description = "最后同步时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastSyncTime;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.xyzh.api.agent.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 知识文档片段VO
|
||||
* 用于前端展示知识文档片段信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识文档片段VO")
|
||||
public class KnowledgeChunkVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "片段ID")
|
||||
private String chunkId;
|
||||
|
||||
@Schema(description = "所属文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "文档标题")
|
||||
private String docTitle;
|
||||
|
||||
@Schema(description = "所属知识库ID")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "知识库名称")
|
||||
private String knowledgeName;
|
||||
|
||||
@Schema(description = "片段索引")
|
||||
private Integer chunkIndex;
|
||||
|
||||
@Schema(description = "片段内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "内容长度")
|
||||
private Integer contentLength;
|
||||
|
||||
@Schema(description = "片段类型")
|
||||
private String chunkType;
|
||||
|
||||
@Schema(description = "片段类型名称")
|
||||
private String chunkTypeName;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private Integer version;
|
||||
|
||||
@Schema(description = "根chunk ID")
|
||||
private String rootChunkId;
|
||||
|
||||
@Schema(description = "是否当前版本", defaultValue = "false")
|
||||
private Boolean isCurrent;
|
||||
|
||||
@Schema(description = "位置信息")
|
||||
private JsonNode positionInfo;
|
||||
|
||||
@Schema(description = "片段元数据")
|
||||
private JsonNode metadata;
|
||||
|
||||
@Schema(description = "部门名称")
|
||||
private String deptName;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.xyzh.api.agent.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识文档VO
|
||||
* 用于前端展示知识文档信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "知识文档VO")
|
||||
public class KnowledgeDocumentVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "所属知识库ID")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "知识库名称")
|
||||
private String knowledgeName;
|
||||
|
||||
@Schema(description = "文档标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "文档类型")
|
||||
private String docType;
|
||||
|
||||
@Schema(description = "文档类型名称")
|
||||
private String docTypeName;
|
||||
|
||||
@Schema(description = "文档分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "文档内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "内容摘要")
|
||||
private String contentSummary;
|
||||
|
||||
@Schema(description = "关联文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件下载URL")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "文件大小格式化显示")
|
||||
private String fileSizeFormatted;
|
||||
|
||||
@Schema(description = "MIME类型")
|
||||
private String mimeType;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private Integer version;
|
||||
|
||||
@Schema(description = "根文档ID")
|
||||
private String rootDocId;
|
||||
|
||||
@Schema(description = "文档标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "关键词")
|
||||
private List<String> keywords;
|
||||
|
||||
@Schema(description = "向量化状态")
|
||||
private String embeddingStatus;
|
||||
|
||||
@Schema(description = "向量化状态名称")
|
||||
private String embeddingStatusName;
|
||||
|
||||
@Schema(description = "使用的向量化模型")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "切片数量")
|
||||
private Integer chunkCount;
|
||||
|
||||
@Schema(description = "文档元数据")
|
||||
private JsonNode metadata;
|
||||
|
||||
@Schema(description = "来源URL")
|
||||
private String sourceUrl;
|
||||
|
||||
@Schema(description = "服务类型")
|
||||
private String serviceType;
|
||||
|
||||
@Schema(description = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
21
urbanLifelineServ/apis/api-bidding/pom.xml
Normal file
21
urbanLifelineServ/apis/api-bidding/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>apis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-bidding</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.xyzh.api.bidding;
|
||||
|
||||
public interface BiddingService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.xyzh.api.bidding.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 投标文件DTO
|
||||
* 用于创建和更新投标文件
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "投标文件DTO")
|
||||
public class BidResponseDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "响应文件ID(更新时需要)")
|
||||
private String responseId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "响应类型:technical-技术标/commercial-商务标/comprehensive-综合标")
|
||||
private String responseType;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "文档大纲")
|
||||
private String outline;
|
||||
|
||||
@Schema(description = "文档内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "生成方式:ai-AI生成/template-模板生成/manual-人工编写")
|
||||
private String generationMethod;
|
||||
|
||||
@Schema(description = "使用的模板ID")
|
||||
private String templateId;
|
||||
|
||||
@Schema(description = "使用的AI模型")
|
||||
private String aiModel;
|
||||
|
||||
@Schema(description = "生成状态:draft-草稿/reviewing-审核中/approved-已批准/rejected-已拒绝/submitted-已提交")
|
||||
private String generationStatus;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "父版本ID")
|
||||
private String parentVersionId;
|
||||
|
||||
@Schema(description = "审核意见")
|
||||
private String reviewComments;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.xyzh.api.bidding.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 招标文档DTO
|
||||
* 用于创建和更新招标文档
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标文档DTO")
|
||||
public class BiddingDocumentDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档ID(更新时需要)")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "文档类型:tender-招标文件/technical-技术标/commercial-商务标/clarification-澄清文件/other-其他")
|
||||
private String docType;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "关联文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "MIME类型")
|
||||
private String mimeType;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "语言")
|
||||
private String language;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package org.xyzh.api.bidding.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 招标项目DTO
|
||||
* 用于创建和更新招标项目
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标项目DTO")
|
||||
public class BiddingProjectDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "项目ID(更新时需要)")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目编号")
|
||||
private String projectNo;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "项目类型:public-公开招标/invitation-邀请招标/competitive_negotiation-竞争性谈判")
|
||||
private String projectType;
|
||||
|
||||
@Schema(description = "所属行业")
|
||||
private String industry;
|
||||
|
||||
@Schema(description = "来源平台")
|
||||
private String sourcePlatform;
|
||||
|
||||
@Schema(description = "来源URL")
|
||||
private String sourceUrl;
|
||||
|
||||
@Schema(description = "发布日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date publishDate;
|
||||
|
||||
@Schema(description = "投标截止日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deadline;
|
||||
|
||||
@Schema(description = "开标日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date openingDate;
|
||||
|
||||
@Schema(description = "预算金额")
|
||||
private BigDecimal budgetAmount;
|
||||
|
||||
@Schema(description = "货币单位")
|
||||
private String currency;
|
||||
|
||||
@Schema(description = "项目状态")
|
||||
private String projectStatus;
|
||||
|
||||
@Schema(description = "中标状态")
|
||||
private String winningStatus;
|
||||
|
||||
@Schema(description = "中标金额")
|
||||
private BigDecimal winningAmount;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String clientName;
|
||||
|
||||
@Schema(description = "客户联系方式")
|
||||
private String clientContact;
|
||||
|
||||
@Schema(description = "联系人")
|
||||
private String contactPerson;
|
||||
|
||||
@Schema(description = "项目地点")
|
||||
private String projectLocation;
|
||||
|
||||
@Schema(description = "项目描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "关键词")
|
||||
private List<String> keywords;
|
||||
|
||||
@Schema(description = "负责人")
|
||||
private String responsibleUser;
|
||||
|
||||
@Schema(description = "团队成员")
|
||||
private List<String> teamMembers;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.xyzh.api.bidding.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 招标要素DTO
|
||||
* 用于创建和更新招标要素
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标要素DTO")
|
||||
public class BiddingRequirementDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "要素ID(更新时需要)")
|
||||
private String reqId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "来源文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "要素类别:commercial-商务要素/technical-技术参数/veto-否决项/qualification-资质要求/delivery-交付要求/payment-付款条件/scoring-评分标准")
|
||||
private String reqCategory;
|
||||
|
||||
@Schema(description = "要素名称")
|
||||
private String reqName;
|
||||
|
||||
@Schema(description = "要素内容")
|
||||
private String reqContent;
|
||||
|
||||
@Schema(description = "要素值")
|
||||
private String reqValue;
|
||||
|
||||
@Schema(description = "是否必填", defaultValue = "false")
|
||||
private Boolean isMandatory;
|
||||
|
||||
@Schema(description = "是否为否决项", defaultValue = "false")
|
||||
private Boolean isVeto;
|
||||
|
||||
@Schema(description = "优先级")
|
||||
private Integer priority;
|
||||
|
||||
@Schema(description = "提取方式:ai-AI提取/manual-人工录入")
|
||||
private String extractionMethod;
|
||||
|
||||
@Schema(description = "置信度分数")
|
||||
private BigDecimal confidenceScore;
|
||||
|
||||
@Schema(description = "来源位置")
|
||||
private JsonNode sourceLocation;
|
||||
|
||||
@Schema(description = "合规状态:compliant-符合/non_compliant-不符合/pending-待确认")
|
||||
private String complianceStatus;
|
||||
|
||||
@Schema(description = "响应内容")
|
||||
private String responseContent;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String notes;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.xyzh.api.bidding.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目流程节点DTO
|
||||
* 用于创建和更新流程节点
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "项目流程节点DTO")
|
||||
public class ProcessNodeDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "流程节点ID(更新时需要)")
|
||||
private String processId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "节点名称")
|
||||
private String nodeName;
|
||||
|
||||
@Schema(description = "节点类型:collection-文件收集/analysis-需求分析/preparation-文件准备/review-内部审核/submission-投标提交/opening-开标/result-结果通知")
|
||||
private String nodeType;
|
||||
|
||||
@Schema(description = "节点顺序")
|
||||
private Integer nodeOrder;
|
||||
|
||||
@Schema(description = "节点状态:pending-待处理/in_progress-进行中/completed-已完成/skipped-已跳过")
|
||||
private String nodeStatus;
|
||||
|
||||
@Schema(description = "计划开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date plannedStartTime;
|
||||
|
||||
@Schema(description = "计划结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date plannedEndTime;
|
||||
|
||||
@Schema(description = "实际开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualStartTime;
|
||||
|
||||
@Schema(description = "实际结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualEndTime;
|
||||
|
||||
@Schema(description = "负责人")
|
||||
private String responsibleUser;
|
||||
|
||||
@Schema(description = "参与人员")
|
||||
private List<String> participants;
|
||||
|
||||
@Schema(description = "节点备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "附件ID数组")
|
||||
private List<String> attachments;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 投标文件VO
|
||||
* 用于前端展示投标文件信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "投标文件VO")
|
||||
public class BidResponseVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "响应文件ID")
|
||||
private String responseId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "响应类型")
|
||||
private String responseType;
|
||||
|
||||
@Schema(description = "响应类型名称(中文)")
|
||||
private String responseTypeName;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "文档大纲")
|
||||
private String outline;
|
||||
|
||||
@Schema(description = "文档内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "内容字数")
|
||||
private Integer contentWordCount;
|
||||
|
||||
@Schema(description = "生成方式")
|
||||
private String generationMethod;
|
||||
|
||||
@Schema(description = "生成方式名称")
|
||||
private String generationMethodName;
|
||||
|
||||
@Schema(description = "使用的模板ID")
|
||||
private String templateId;
|
||||
|
||||
@Schema(description = "使用的模板名称")
|
||||
private String templateName;
|
||||
|
||||
@Schema(description = "使用的AI模型")
|
||||
private String aiModel;
|
||||
|
||||
@Schema(description = "生成状态")
|
||||
private String generationStatus;
|
||||
|
||||
@Schema(description = "生成状态名称")
|
||||
private String generationStatusName;
|
||||
|
||||
@Schema(description = "生成状态颜色标签")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "关联文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件下载URL")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "父版本ID")
|
||||
private String parentVersionId;
|
||||
|
||||
@Schema(description = "是否有历史版本", defaultValue = "false")
|
||||
private Boolean hasHistory;
|
||||
|
||||
@Schema(description = "审核意见")
|
||||
private String reviewComments;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 招标文档VO
|
||||
* 用于前端展示招标文档信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标文档VO")
|
||||
public class BiddingDocumentVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "文档类型")
|
||||
private String docType;
|
||||
|
||||
@Schema(description = "文档类型名称(中文)")
|
||||
private String docTypeName;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "关联文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件下载URL")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "文件大小格式化显示")
|
||||
private String fileSizeFormatted;
|
||||
|
||||
@Schema(description = "MIME类型")
|
||||
private String mimeType;
|
||||
|
||||
@Schema(description = "文件类型图标")
|
||||
private String fileIcon;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "语言")
|
||||
private String language;
|
||||
|
||||
@Schema(description = "页数")
|
||||
private Integer pageCount;
|
||||
|
||||
@Schema(description = "解析状态")
|
||||
private String parseStatus;
|
||||
|
||||
@Schema(description = "解析状态名称")
|
||||
private String parseStatusName;
|
||||
|
||||
@Schema(description = "解析结果")
|
||||
private JsonNode parseResult;
|
||||
|
||||
@Schema(description = "提取的结构化数据")
|
||||
private JsonNode extractionData;
|
||||
|
||||
@Schema(description = "AI分析结果")
|
||||
private String aiAnalysis;
|
||||
|
||||
@Schema(description = "上传日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date uploadDate;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 招标项目VO
|
||||
* 用于前端展示招标项目详细信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标项目VO")
|
||||
public class BiddingProjectVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目编号")
|
||||
private String projectNo;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "项目类型")
|
||||
private String projectType;
|
||||
|
||||
@Schema(description = "项目类型名称(中文)")
|
||||
private String projectTypeName;
|
||||
|
||||
@Schema(description = "所属行业")
|
||||
private String industry;
|
||||
|
||||
@Schema(description = "来源平台")
|
||||
private String sourcePlatform;
|
||||
|
||||
@Schema(description = "来源URL")
|
||||
private String sourceUrl;
|
||||
|
||||
@Schema(description = "发布日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date publishDate;
|
||||
|
||||
@Schema(description = "投标截止日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deadline;
|
||||
|
||||
@Schema(description = "开标日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date openingDate;
|
||||
|
||||
@Schema(description = "距离截止日期剩余天数")
|
||||
private Long daysUntilDeadline;
|
||||
|
||||
@Schema(description = "预算金额")
|
||||
private BigDecimal budgetAmount;
|
||||
|
||||
@Schema(description = "货币单位")
|
||||
private String currency;
|
||||
|
||||
@Schema(description = "预算金额格式化显示")
|
||||
private String budgetAmountFormatted;
|
||||
|
||||
@Schema(description = "项目状态")
|
||||
private String projectStatus;
|
||||
|
||||
@Schema(description = "项目状态名称(中文)")
|
||||
private String projectStatusName;
|
||||
|
||||
@Schema(description = "中标状态")
|
||||
private String winningStatus;
|
||||
|
||||
@Schema(description = "中标状态名称(中文)")
|
||||
private String winningStatusName;
|
||||
|
||||
@Schema(description = "中标金额")
|
||||
private BigDecimal winningAmount;
|
||||
|
||||
@Schema(description = "中标金额格式化显示")
|
||||
private String winningAmountFormatted;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String clientName;
|
||||
|
||||
@Schema(description = "客户联系方式")
|
||||
private String clientContact;
|
||||
|
||||
@Schema(description = "联系人")
|
||||
private String contactPerson;
|
||||
|
||||
@Schema(description = "项目地点")
|
||||
private String projectLocation;
|
||||
|
||||
@Schema(description = "项目描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "关键词")
|
||||
private List<String> keywords;
|
||||
|
||||
@Schema(description = "负责人ID")
|
||||
private String responsibleUser;
|
||||
|
||||
@Schema(description = "负责人姓名")
|
||||
private String responsibleUserName;
|
||||
|
||||
@Schema(description = "团队成员")
|
||||
private List<String> teamMembers;
|
||||
|
||||
@Schema(description = "团队成员姓名列表")
|
||||
private List<String> teamMemberNames;
|
||||
|
||||
@Schema(description = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
@Schema(description = "文档数量")
|
||||
private Integer documentCount;
|
||||
|
||||
@Schema(description = "要素数量")
|
||||
private Integer requirementCount;
|
||||
|
||||
@Schema(description = "否决项数量")
|
||||
private Integer vetoCount;
|
||||
|
||||
@Schema(description = "投标文件数量")
|
||||
private Integer responseCount;
|
||||
|
||||
@Schema(description = "完成进度(百分比)")
|
||||
private Integer progressPercentage;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 招标要素VO
|
||||
* 用于前端展示招标要素信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标要素VO")
|
||||
public class BiddingRequirementVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "要素ID")
|
||||
private String reqId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "来源文档ID")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "来源文档名称")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "要素类别")
|
||||
private String reqCategory;
|
||||
|
||||
@Schema(description = "要素类别名称(中文)")
|
||||
private String reqCategoryName;
|
||||
|
||||
@Schema(description = "要素名称")
|
||||
private String reqName;
|
||||
|
||||
@Schema(description = "要素内容")
|
||||
private String reqContent;
|
||||
|
||||
@Schema(description = "要素值")
|
||||
private String reqValue;
|
||||
|
||||
@Schema(description = "是否必填", defaultValue = "false")
|
||||
private Boolean isMandatory;
|
||||
|
||||
@Schema(description = "是否为否决项", defaultValue = "false")
|
||||
private Boolean isVeto;
|
||||
|
||||
@Schema(description = "优先级")
|
||||
private Integer priority;
|
||||
|
||||
@Schema(description = "优先级标签(高/中/低)")
|
||||
private String priorityLabel;
|
||||
|
||||
@Schema(description = "提取方式")
|
||||
private String extractionMethod;
|
||||
|
||||
@Schema(description = "提取方式名称")
|
||||
private String extractionMethodName;
|
||||
|
||||
@Schema(description = "置信度分数")
|
||||
private BigDecimal confidenceScore;
|
||||
|
||||
@Schema(description = "置信度百分比")
|
||||
private Integer confidencePercentage;
|
||||
|
||||
@Schema(description = "来源位置")
|
||||
private JsonNode sourceLocation;
|
||||
|
||||
@Schema(description = "来源位置描述")
|
||||
private String sourceLocationDesc;
|
||||
|
||||
@Schema(description = "合规状态")
|
||||
private String complianceStatus;
|
||||
|
||||
@Schema(description = "合规状态名称")
|
||||
private String complianceStatusName;
|
||||
|
||||
@Schema(description = "合规状态标签颜色")
|
||||
private String complianceStatusColor;
|
||||
|
||||
@Schema(description = "响应内容")
|
||||
private String responseContent;
|
||||
|
||||
@Schema(description = "是否已响应", defaultValue = "false")
|
||||
private Boolean hasResponse;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目流程节点VO
|
||||
* 用于前端展示流程节点信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "项目流程节点VO")
|
||||
public class ProcessNodeVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "流程节点ID")
|
||||
private String processId;
|
||||
|
||||
@Schema(description = "所属项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "节点名称")
|
||||
private String nodeName;
|
||||
|
||||
@Schema(description = "节点类型")
|
||||
private String nodeType;
|
||||
|
||||
@Schema(description = "节点类型名称")
|
||||
private String nodeTypeName;
|
||||
|
||||
@Schema(description = "节点顺序")
|
||||
private Integer nodeOrder;
|
||||
|
||||
@Schema(description = "节点状态")
|
||||
private String nodeStatus;
|
||||
|
||||
@Schema(description = "节点状态名称")
|
||||
private String nodeStatusName;
|
||||
|
||||
@Schema(description = "节点状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "节点图标")
|
||||
private String nodeIcon;
|
||||
|
||||
@Schema(description = "计划开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date plannedStartTime;
|
||||
|
||||
@Schema(description = "计划结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date plannedEndTime;
|
||||
|
||||
@Schema(description = "实际开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualStartTime;
|
||||
|
||||
@Schema(description = "实际结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualEndTime;
|
||||
|
||||
@Schema(description = "计划耗时(天)")
|
||||
private Integer plannedDuration;
|
||||
|
||||
@Schema(description = "实际耗时(天)")
|
||||
private Integer actualDuration;
|
||||
|
||||
@Schema(description = "是否延期", defaultValue = "false")
|
||||
private Boolean isDelayed;
|
||||
|
||||
@Schema(description = "延期天数")
|
||||
private Integer delayedDays;
|
||||
|
||||
@Schema(description = "负责人ID")
|
||||
private String responsibleUser;
|
||||
|
||||
@Schema(description = "负责人姓名")
|
||||
private String responsibleUserName;
|
||||
|
||||
@Schema(description = "参与人员ID列表")
|
||||
private List<String> participants;
|
||||
|
||||
@Schema(description = "参与人员姓名列表")
|
||||
private List<String> participantNames;
|
||||
|
||||
@Schema(description = "节点备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "附件ID数组")
|
||||
private List<String> attachments;
|
||||
|
||||
@Schema(description = "附件数量")
|
||||
private Integer attachmentCount;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 招标项目列表VO(简化版)
|
||||
* 用于前端列表展示
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "招标项目列表VO")
|
||||
public class ProjectListVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "项目编号")
|
||||
private String projectNo;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "项目类型")
|
||||
private String projectType;
|
||||
|
||||
@Schema(description = "项目类型名称")
|
||||
private String projectTypeName;
|
||||
|
||||
@Schema(description = "所属行业")
|
||||
private String industry;
|
||||
|
||||
@Schema(description = "投标截止日期", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deadline;
|
||||
|
||||
@Schema(description = "距离截止日期剩余天数")
|
||||
private Long daysUntilDeadline;
|
||||
|
||||
@Schema(description = "是否即将截止(<3天)", defaultValue = "false")
|
||||
private Boolean isUrgent;
|
||||
|
||||
@Schema(description = "预算金额格式化显示")
|
||||
private String budgetAmountFormatted;
|
||||
|
||||
@Schema(description = "项目状态")
|
||||
private String projectStatus;
|
||||
|
||||
@Schema(description = "项目状态名称")
|
||||
private String projectStatusName;
|
||||
|
||||
@Schema(description = "中标状态")
|
||||
private String winningStatus;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String clientName;
|
||||
|
||||
@Schema(description = "负责人姓名")
|
||||
private String responsibleUserName;
|
||||
|
||||
@Schema(description = "完成进度(百分比)")
|
||||
private Integer progressPercentage;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.xyzh.api.bidding.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 项目统计VO
|
||||
* 用于前端展示项目统计数据
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "项目统计VO")
|
||||
public class ProjectStatisticsVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "总项目数")
|
||||
private Long totalProjects;
|
||||
|
||||
@Schema(description = "进行中的项目数")
|
||||
private Long ongoingProjects;
|
||||
|
||||
@Schema(description = "已提交的项目数")
|
||||
private Long submittedProjects;
|
||||
|
||||
@Schema(description = "已中标的项目数")
|
||||
private Long wonProjects;
|
||||
|
||||
@Schema(description = "未中标的项目数")
|
||||
private Long lostProjects;
|
||||
|
||||
@Schema(description = "中标率(百分比)")
|
||||
private BigDecimal winRate;
|
||||
|
||||
@Schema(description = "即将截止的项目数(<3天)")
|
||||
private Long urgentProjects;
|
||||
|
||||
@Schema(description = "总预算金额")
|
||||
private BigDecimal totalBudget;
|
||||
|
||||
@Schema(description = "总中标金额")
|
||||
private BigDecimal totalWinningAmount;
|
||||
|
||||
@Schema(description = "按状态分组统计")
|
||||
private Map<String, Long> projectsByStatus;
|
||||
|
||||
@Schema(description = "按类型分组统计")
|
||||
private Map<String, Long> projectsByType;
|
||||
|
||||
@Schema(description = "按行业分组统计")
|
||||
private Map<String, Long> projectsByIndustry;
|
||||
|
||||
@Schema(description = "按月份分组统计(最近12个月)")
|
||||
private Map<String, Long> projectsByMonth;
|
||||
|
||||
@Schema(description = "按负责人分组统计")
|
||||
private Map<String, Long> projectsByUser;
|
||||
|
||||
@Schema(description = "平均项目周期(天)")
|
||||
private Integer avgProjectCycle;
|
||||
|
||||
@Schema(description = "最近7天新增项目数")
|
||||
private Long recentNewProjects;
|
||||
}
|
||||
21
urbanLifelineServ/apis/api-crontab/pom.xml
Normal file
21
urbanLifelineServ/apis/api-crontab/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>apis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-crontab</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.xyzh.api.crontab;
|
||||
|
||||
/**
|
||||
* 定时任务服务接口
|
||||
* 用于定时任务管理
|
||||
*/
|
||||
public interface CrontabService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.xyzh.api.crontab.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 定时任务执行日志DTO
|
||||
* 用于记录任务执行情况
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务执行日志DTO")
|
||||
public class TbCrontabLogDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "任务ID")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String taskName;
|
||||
|
||||
@Schema(description = "任务分组")
|
||||
private String taskGroup;
|
||||
|
||||
@Schema(description = "Bean名称")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "方法名称")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "方法参数")
|
||||
private String methodParams;
|
||||
|
||||
@Schema(description = "执行状态:0-失败/1-成功")
|
||||
private Integer executeStatus;
|
||||
|
||||
@Schema(description = "执行结果信息")
|
||||
private String executeMessage;
|
||||
|
||||
@Schema(description = "异常信息")
|
||||
private String exceptionInfo;
|
||||
|
||||
@Schema(description = "开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
@Schema(description = "结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "执行时长(毫秒)")
|
||||
private Integer executeDuration;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.xyzh.api.crontab.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 定时任务DTO
|
||||
* 用于创建和更新定时任务
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务DTO")
|
||||
public class TbCrontabTaskDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "任务ID(更新时需要)")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String taskName;
|
||||
|
||||
@Schema(description = "任务分组", defaultValue = "DEFAULT")
|
||||
private String taskGroup;
|
||||
|
||||
@Schema(description = "任务元数据ID")
|
||||
private String metaId;
|
||||
|
||||
@Schema(description = "是否使用默认接收人", defaultValue = "false")
|
||||
private Boolean defaultRecipient;
|
||||
|
||||
@Schema(description = "Bean名称")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "方法名称")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "方法参数")
|
||||
private String methodParams;
|
||||
|
||||
@Schema(description = "Cron表达式")
|
||||
private String cronExpression;
|
||||
|
||||
@Schema(description = "任务状态:0-暂停/1-运行中", defaultValue = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "任务描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否允许并发执行", defaultValue = "false")
|
||||
private Boolean concurrent;
|
||||
|
||||
@Schema(description = "错过执行策略:1-立即执行/2-执行一次/3-放弃执行", defaultValue = "1")
|
||||
private Integer misfirePolicy;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.xyzh.api.crontab.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 定时任务元数据DTO
|
||||
* 用于创建和更新任务元数据配置
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务元数据DTO")
|
||||
public class TbCrontabTaskMetaDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "元数据ID(更新时需要)")
|
||||
private String metaId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "任务描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "任务分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "Bean名称(执行器类名)")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "执行方法名")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "Python脚本路径")
|
||||
private String scriptPath;
|
||||
|
||||
@Schema(description = "参数模板(JSON格式)")
|
||||
private String paramSchema;
|
||||
|
||||
@Schema(description = "是否自动发布", defaultValue = "false")
|
||||
private Boolean autoPublish;
|
||||
|
||||
@Schema(description = "排序号", defaultValue = "0")
|
||||
private Integer sortOrder;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.xyzh.api.crontab.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 定时任务执行日志VO
|
||||
* 用于前端展示任务执行日志
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务执行日志VO")
|
||||
public class CrontabLogVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "日志ID")
|
||||
private String logId;
|
||||
|
||||
@Schema(description = "任务ID")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String taskName;
|
||||
|
||||
@Schema(description = "任务分组")
|
||||
private String taskGroup;
|
||||
|
||||
@Schema(description = "Bean名称")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "方法名称")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "方法参数")
|
||||
private String methodParams;
|
||||
|
||||
@Schema(description = "执行状态:0-失败/1-成功")
|
||||
private Integer executeStatus;
|
||||
|
||||
@Schema(description = "执行状态名称")
|
||||
private String executeStatusName;
|
||||
|
||||
@Schema(description = "执行状态颜色")
|
||||
private String executeStatusColor;
|
||||
|
||||
@Schema(description = "执行结果信息")
|
||||
private String executeMessage;
|
||||
|
||||
@Schema(description = "异常信息")
|
||||
private String exceptionInfo;
|
||||
|
||||
@Schema(description = "是否有异常", defaultValue = "false")
|
||||
private Boolean hasException;
|
||||
|
||||
@Schema(description = "开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
@Schema(description = "结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "执行时长(毫秒)")
|
||||
private Integer executeDuration;
|
||||
|
||||
@Schema(description = "执行时长格式化显示")
|
||||
private String executeDurationFormatted;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.xyzh.api.crontab.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 定时任务列表VO
|
||||
* 用于前端列表展示(简化版)
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务列表VO")
|
||||
public class CrontabTaskListVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "任务ID")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String taskName;
|
||||
|
||||
@Schema(description = "任务分组")
|
||||
private String taskGroup;
|
||||
|
||||
@Schema(description = "Cron表达式")
|
||||
private String cronExpression;
|
||||
|
||||
@Schema(description = "Cron表达式描述")
|
||||
private String cronDescription;
|
||||
|
||||
@Schema(description = "任务状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "任务状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "下次执行时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date nextExecuteTime;
|
||||
|
||||
@Schema(description = "最后执行时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastExecuteTime;
|
||||
|
||||
@Schema(description = "最后执行状态")
|
||||
private Integer lastExecuteStatus;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.xyzh.api.crontab.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 定时任务元数据VO
|
||||
* 用于前端展示任务元数据信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务元数据VO")
|
||||
public class CrontabTaskMetaVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "元数据ID")
|
||||
private String metaId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "任务描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "任务分类")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "Bean名称(执行器类名)")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "执行方法名")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "Python脚本路径")
|
||||
private String scriptPath;
|
||||
|
||||
@Schema(description = "参数模板(JSON格式)")
|
||||
private String paramSchema;
|
||||
|
||||
@Schema(description = "是否自动发布", defaultValue = "false")
|
||||
private Boolean autoPublish;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Integer sortOrder;
|
||||
|
||||
@Schema(description = "关联的任务数量")
|
||||
private Integer taskCount;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.xyzh.api.crontab.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 定时任务VO
|
||||
* 用于前端展示定时任务信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "定时任务VO")
|
||||
public class CrontabTaskVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "任务ID")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "任务名称")
|
||||
private String taskName;
|
||||
|
||||
@Schema(description = "任务分组")
|
||||
private String taskGroup;
|
||||
|
||||
@Schema(description = "任务元数据ID")
|
||||
private String metaId;
|
||||
|
||||
@Schema(description = "元数据名称")
|
||||
private String metaName;
|
||||
|
||||
@Schema(description = "是否使用默认接收人", defaultValue = "false")
|
||||
private Boolean defaultRecipient;
|
||||
|
||||
@Schema(description = "Bean名称")
|
||||
private String beanName;
|
||||
|
||||
@Schema(description = "方法名称")
|
||||
private String methodName;
|
||||
|
||||
@Schema(description = "方法参数")
|
||||
private String methodParams;
|
||||
|
||||
@Schema(description = "Cron表达式")
|
||||
private String cronExpression;
|
||||
|
||||
@Schema(description = "Cron表达式描述(中文)")
|
||||
private String cronDescription;
|
||||
|
||||
@Schema(description = "任务状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "任务状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "任务描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否允许并发执行", defaultValue = "false")
|
||||
private Boolean concurrent;
|
||||
|
||||
@Schema(description = "错过执行策略")
|
||||
private Integer misfirePolicy;
|
||||
|
||||
@Schema(description = "错过执行策略名称")
|
||||
private String misfirePolicyName;
|
||||
|
||||
@Schema(description = "下次执行时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date nextExecuteTime;
|
||||
|
||||
@Schema(description = "最后执行时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastExecuteTime;
|
||||
|
||||
@Schema(description = "最后执行状态:0-失败/1-成功")
|
||||
private Integer lastExecuteStatus;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
@@ -15,7 +15,19 @@ import org.xyzh.common.core.page.PageParam;
|
||||
*/
|
||||
public interface MessageService {
|
||||
|
||||
// ================ 发送邮件 ==================
|
||||
ResultDomain<String> sendSimpleEmail(String to, String subject, String content);
|
||||
|
||||
ResultDomain<String> sendHtmlEmail(String to, String subject, String content);
|
||||
|
||||
ResultDomain<String> sendEmailVerificationCode(String to, String code);
|
||||
|
||||
// ================ 发送短信 ==================
|
||||
|
||||
//================= 用户查看消息列表 =================
|
||||
ResultDomain<String> sendPhoneVerificationCode(String phone, String code);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description 获取我的消息列表
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.xyzh.api.message.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
|
||||
/**
|
||||
* 用户消息接收记录VO
|
||||
* 用于前端展示用户消息信息
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户消息接收记录VO")
|
||||
public class MessageReceiverVO extends BaseVO {
|
||||
|
||||
@Schema(description = "消息ID")
|
||||
private String messageId;
|
||||
|
||||
@Schema(description = "消息标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "消息内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "消息类型名称")
|
||||
private String typeName;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "用户姓名")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "接收渠道")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "渠道名称")
|
||||
private String channelName;
|
||||
|
||||
@Schema(description = "消息状态:unread-未读/read-已读/handled-已处理/deleted-已删除")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "阅读时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date readTime;
|
||||
|
||||
@Schema(description = "处理时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date handleTime;
|
||||
|
||||
@Schema(description = "服务类型")
|
||||
private String serviceType;
|
||||
}
|
||||
21
urbanLifelineServ/apis/api-platform/pom.xml
Normal file
21
urbanLifelineServ/apis/api-platform/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>apis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-platform</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.xyzh;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.xyzh.api.system.service;
|
||||
|
||||
import org.xyzh.api.system.vo.AclVO;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.sys.TbSysAclDTO;
|
||||
import org.xyzh.common.dto.sys.TbSysAclPolicyDTO;
|
||||
|
||||
/**
|
||||
* @description 访问控制列表服务接口
|
||||
* @filename AclService.java
|
||||
* @author yslg
|
||||
* @copyright yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
public interface AclService {
|
||||
|
||||
// ================= ACL 管理 =================
|
||||
/**
|
||||
* @description 插入访问控制列表
|
||||
* @param aclDTO 访问控制列表DTO
|
||||
* @return ResultDomain<TbSysAclDTO> 插入结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<TbSysAclDTO> insertAcl(TbSysAclDTO aclDTO);
|
||||
|
||||
/**
|
||||
* @description 更新访问控制列表
|
||||
* @param aclDTO 访问控制列表DTO
|
||||
* @return ResultDomain<TbSysAclDTO> 更新结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<TbSysAclDTO> updateAcl(TbSysAclDTO aclDTO);
|
||||
|
||||
/**
|
||||
* @description 删除访问控制列表
|
||||
* @param aclDTO 访问控制列表DTO
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<Boolean> deleteAcl(TbSysAclDTO aclDTO);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询访问控制列表分页数据
|
||||
* @param pageRequest 分页请求
|
||||
* @return ResultDomain<AclVO> 分页结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<AclVO> getAclPage(PageRequest<AclVO> pageRequest);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询访问控制列表
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<AclVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<AclVO> getAclList(AclVO filter);
|
||||
|
||||
/**
|
||||
* @description 根据对象ID查询访问控制列表
|
||||
* @param objectId 对象ID
|
||||
* @return ResultDomain<AclVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<AclVO> getAclByObjectId(String objectId);
|
||||
|
||||
// ================= ACL Policy 管理 =================
|
||||
/**
|
||||
* @description 插入访问控制策略
|
||||
* @param aclPolicyDTO 访问控制策略DTO
|
||||
* @return ResultDomain<TbSysAclPolicyDTO> 插入结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<TbSysAclPolicyDTO> insertAclPolicy(TbSysAclPolicyDTO aclPolicyDTO);
|
||||
|
||||
/**
|
||||
* @description 更新访问控制策略
|
||||
* @param aclPolicyDTO 访问控制策略DTO
|
||||
* @return ResultDomain<TbSysAclPolicyDTO> 更新结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<TbSysAclPolicyDTO> updateAclPolicy(TbSysAclPolicyDTO aclPolicyDTO);
|
||||
|
||||
/**
|
||||
* @description 删除访问控制策略
|
||||
* @param aclPolicyDTO 访问控制策略DTO
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<Boolean> deleteAclPolicy(TbSysAclPolicyDTO aclPolicyDTO);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询访问控制策略分页数据
|
||||
* @param pageRequest 分页请求
|
||||
* @return ResultDomain<AclVO> 分页结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<AclVO> getAclPolicyPage(PageRequest<AclVO> pageRequest);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询访问控制策略列表
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<AclVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-12-05
|
||||
*/
|
||||
ResultDomain<AclVO> getAclPolicyList(AclVO filter);
|
||||
}
|
||||
@@ -154,60 +154,6 @@ public interface DeptRoleService {
|
||||
*/
|
||||
ResultDomain<UserDeptRoleVO> getRoleListByUserId(String userId);
|
||||
|
||||
// ================= 部门角色关联管理 =================
|
||||
/**
|
||||
* @description 插入部门角色关联
|
||||
* @param deptRoleDTO 部门角色DTO
|
||||
* @return ResultDomain<TbSysDeptRoleDTO> 插入结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<TbSysDeptRoleDTO> insertDeptRole(TbSysDeptRoleDTO deptRoleDTO);
|
||||
|
||||
/**
|
||||
* @description 更新部门角色关联
|
||||
* @param deptRoleDTO 部门角色DTO
|
||||
* @return ResultDomain<TbSysDeptRoleDTO> 更新结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<TbSysDeptRoleDTO> updateDeptRole(TbSysDeptRoleDTO deptRoleDTO);
|
||||
|
||||
/**
|
||||
* @description 根据ID删除部门角色关联
|
||||
* @param deptRoleDTO 部门角色DTO
|
||||
* @return ResultDomain<Boolean> 删除结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<Boolean> deleteDeptRole(TbSysDeptRoleDTO deptRoleDTO);
|
||||
|
||||
/**
|
||||
* @description 根据ID查询部门角色关联
|
||||
* @param filter 部门角色VO
|
||||
* @return ResultDomain<UserDeptRoleVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<UserDeptRoleVO> getDeptRole(UserDeptRoleVO filter);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询部门角色关联列表
|
||||
* @param filter 部门角色VO
|
||||
* @return ResultDomain<UserDeptRoleVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<UserDeptRoleVO> getDeptRoleList(UserDeptRoleVO filter);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询部门角色关联分页列表
|
||||
* @param pageRequest 部门角色VO
|
||||
* @return ResultDomain<UserDeptRoleVO> 查询结果
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<UserDeptRoleVO> getDeptRolePage(PageRequest<UserDeptRoleVO> pageRequest);
|
||||
|
||||
// ==================== 角色权限关联 ================================
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.xyzh.api.system.vo.PermissionVO;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.dto.sys.TbSysModuleDTO;
|
||||
import org.xyzh.common.dto.sys.TbSysPermissionDTO;
|
||||
import org.xyzh.common.dto.sys.TbSysRolePermissionDTO;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,43 @@ import org.xyzh.common.dto.sys.TbSysConfigDTO;
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
public interface SysConfigService {
|
||||
// ================== 读取配置 ========================
|
||||
/**
|
||||
* 获取字符串类型配置
|
||||
* @param key 配置键
|
||||
* @return 配置值
|
||||
*/
|
||||
String getStringConfig(String key);
|
||||
|
||||
/**
|
||||
* 获取整数类型配置
|
||||
* @param key 配置键
|
||||
* @return 配置值,如果不存在或解析失败返回null
|
||||
*/
|
||||
Integer getIntConfig(String key);
|
||||
|
||||
/**
|
||||
* 获取布尔类型配置
|
||||
* @param key 配置键
|
||||
* @return 配置值,如果不存在或解析失败返回null
|
||||
*/
|
||||
Boolean getBooleanConfig(String key);
|
||||
|
||||
/**
|
||||
* 获取浮点数类型配置
|
||||
* @param key 配置键
|
||||
* @return 配置值,如果不存在或解析失败返回null
|
||||
*/
|
||||
Double getDoubleConfig(String key);
|
||||
|
||||
/**
|
||||
* 获取长整数类型配置
|
||||
* @param key 配置键
|
||||
* @return 配置值,如果不存在或解析失败返回null
|
||||
*/
|
||||
Long getLongConfig(String key);
|
||||
|
||||
// =====================================================
|
||||
|
||||
/**
|
||||
* @description 插入系统配置
|
||||
|
||||
@@ -18,6 +18,10 @@ import org.xyzh.common.dto.sys.TbSysUserRoleDTO;
|
||||
public interface SysUserService {
|
||||
|
||||
// ================= 用户基本信息管理 =================
|
||||
|
||||
ResultDomain<TbSysUserDTO> registerUser(SysUserVO userVO);
|
||||
|
||||
|
||||
/**
|
||||
* @description 插入用户
|
||||
* @param userVO 用户VO
|
||||
@@ -61,7 +65,7 @@ public interface SysUserService {
|
||||
* @author yslg
|
||||
* @since 2025-11-05
|
||||
*/
|
||||
ResultDomain<SysUserVO> getLoginUser(SysUserVO filter);
|
||||
ResultDomain<TbSysUserDTO> getLoginUser(TbSysUserDTO filter);
|
||||
|
||||
/**
|
||||
* @description 根据条件查询用户列表
|
||||
|
||||
@@ -64,8 +64,8 @@ public class AclVO extends BaseVO {
|
||||
private Integer defaultPermission = 0;
|
||||
|
||||
@Schema(description = "默认是否允许", defaultValue = "true")
|
||||
private boolean defaultAllow = true;
|
||||
private Boolean defaultAllow = true;
|
||||
|
||||
@Schema(description = "是否默认应用到子级", defaultValue = "true")
|
||||
private boolean applyToChildren = true;
|
||||
private Boolean applyToChildren = true;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PermissionVO extends BaseVO {
|
||||
private String roleOwnerDeptId;
|
||||
|
||||
@Schema(description = "角色状态")
|
||||
private boolean roleStatus;
|
||||
private Boolean roleStatus;
|
||||
|
||||
// TbSysModuleDTO对应字段
|
||||
@Schema(description = "模块ID")
|
||||
|
||||
@@ -24,9 +24,6 @@ public class UserDeptRoleVO extends BaseVO {
|
||||
@Schema(description = "用户ID")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
@@ -49,18 +46,12 @@ public class UserDeptRoleVO extends BaseVO {
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private Integer gender;
|
||||
|
||||
@Schema(description = "姓")
|
||||
private String familyName;
|
||||
|
||||
@Schema(description = "名")
|
||||
private String givenName;
|
||||
|
||||
@Schema(description = "全名")
|
||||
private String fullName;
|
||||
|
||||
@Schema(description = "等级")
|
||||
private Integer level;
|
||||
|
||||
@@ -100,7 +91,7 @@ public class UserDeptRoleVO extends BaseVO {
|
||||
private String ownerDeptId;
|
||||
|
||||
@Schema(description = "角色状态")
|
||||
private boolean roleStatus;
|
||||
private Boolean roleStatus;
|
||||
|
||||
|
||||
public static TbSysDeptDTO toDeptDTO(UserDeptRoleVO vo) {
|
||||
@@ -134,7 +125,7 @@ public class UserDeptRoleVO extends BaseVO {
|
||||
dto.setDescription(vo.getRoleDescription());
|
||||
dto.setScope(vo.getScope());
|
||||
dto.setOwnerDeptId(vo.getOwnerDeptId());
|
||||
dto.setStatus(vo.isRoleStatus());
|
||||
dto.setStatus(vo.getRoleStatus());
|
||||
dto.setOptsn(vo.getOptsn());
|
||||
dto.setCreator(vo.getCreator());
|
||||
dto.setUpdater(vo.getUpdater());
|
||||
@@ -180,7 +171,7 @@ public class UserDeptRoleVO extends BaseVO {
|
||||
vo.setRoleDescription(permissionVO.getRoleDescription());
|
||||
vo.setScope(permissionVO.getRoleScope());
|
||||
vo.setOwnerDeptId(permissionVO.getRoleOwnerDeptId());
|
||||
vo.setRoleStatus(permissionVO.isRoleStatus());
|
||||
vo.setRoleStatus(permissionVO.getRoleStatus());
|
||||
vo.setOptsn(permissionVO.getOptsn());
|
||||
vo.setCreator(permissionVO.getCreator());
|
||||
vo.setUpdater(permissionVO.getUpdater());
|
||||
|
||||
21
urbanLifelineServ/apis/api-workcase/pom.xml
Normal file
21
urbanLifelineServ/apis/api-workcase/pom.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>apis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-workcase</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.xyzh;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.xyzh.api.workcase;
|
||||
|
||||
/**
|
||||
* 工单服务接口
|
||||
* 用于客服工单管理
|
||||
*/
|
||||
public interface WorkcaseService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.xyzh.api.workcase.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会话DTO
|
||||
* 用于创建和更新会话
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "会话DTO")
|
||||
public class TbConversationDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "会话ID(更新时需要)")
|
||||
private String conversationId;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "会话类型:ai-AI客服/human-人工客服/transfer-转接", defaultValue = "ai")
|
||||
private String conversationType;
|
||||
|
||||
@Schema(description = "渠道:wechat-微信/web-网页/app-应用/phone-电话", defaultValue = "wechat")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "智能体ID或客服人员ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "座席类型:ai-AI/human-人工", defaultValue = "ai")
|
||||
private String agentType;
|
||||
|
||||
@Schema(description = "会话开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date sessionStartTime;
|
||||
|
||||
@Schema(description = "会话结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date sessionEndTime;
|
||||
|
||||
@Schema(description = "会话时长(秒)")
|
||||
private Integer durationSeconds;
|
||||
|
||||
@Schema(description = "消息数量", defaultValue = "0")
|
||||
private Integer messageCount;
|
||||
|
||||
@Schema(description = "会话状态:active-进行中/closed-已结束/transferred-已转接/timeout-超时", defaultValue = "active")
|
||||
private String conversationStatus;
|
||||
|
||||
@Schema(description = "满意度评分(1-5星)")
|
||||
private Integer satisfactionRating;
|
||||
|
||||
@Schema(description = "满意度反馈")
|
||||
private String satisfactionFeedback;
|
||||
|
||||
@Schema(description = "会话摘要(AI生成)")
|
||||
private String summary;
|
||||
|
||||
@Schema(description = "会话标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "会话元数据")
|
||||
private JsonNode metadata;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.xyzh.api.workcase.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 客户信息DTO
|
||||
* 用于创建和更新客户信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "客户信息DTO")
|
||||
public class TbCustomerDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "客户ID(更新时需要)")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "客户编号")
|
||||
private String customerNo;
|
||||
|
||||
@Schema(description = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "客户类型:individual-个人/enterprise-企业", defaultValue = "individual")
|
||||
private String customerType;
|
||||
|
||||
@Schema(description = "公司名称")
|
||||
private String companyName;
|
||||
|
||||
@Schema(description = "电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "微信OpenID")
|
||||
private String wechatOpenid;
|
||||
|
||||
@Schema(description = "微信UnionID")
|
||||
private String wechatUnionid;
|
||||
|
||||
@Schema(description = "头像URL")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "性别:0-未知/1-男/2-女", defaultValue = "0")
|
||||
private Integer gender;
|
||||
|
||||
@Schema(description = "地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "客户等级:vip/important/normal/potential", defaultValue = "normal")
|
||||
private String customerLevel;
|
||||
|
||||
@Schema(description = "客户来源:wechat-微信/web-网站/phone-电话/referral-推荐")
|
||||
private String customerSource;
|
||||
|
||||
@Schema(description = "客户标签数组")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "CRM系统客户ID")
|
||||
private String crmCustomerId;
|
||||
|
||||
@Schema(description = "最后联系时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastContactTime;
|
||||
|
||||
@Schema(description = "咨询总次数", defaultValue = "0")
|
||||
private Integer totalConsultations;
|
||||
|
||||
@Schema(description = "订单总数", defaultValue = "0")
|
||||
private Integer totalOrders;
|
||||
|
||||
@Schema(description = "总消费金额", defaultValue = "0")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@Schema(description = "满意度评分(1-5)")
|
||||
private BigDecimal satisfactionScore;
|
||||
|
||||
@Schema(description = "状态:active-活跃/inactive-非活跃/blacklist-黑名单", defaultValue = "active")
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.xyzh.api.workcase.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.dto.BaseDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工单DTO
|
||||
* 用于创建和更新工单
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "工单DTO")
|
||||
public class TbTicketDTO extends BaseDTO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "工单ID(更新时需要)")
|
||||
private String ticketId;
|
||||
|
||||
@Schema(description = "工单编号")
|
||||
private String ticketNo;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "关联会话ID")
|
||||
private String conversationId;
|
||||
|
||||
@Schema(description = "工单类型:consultation-咨询/complaint-投诉/suggestion-建议/repair-维修/installation-安装/other-其他")
|
||||
private String ticketType;
|
||||
|
||||
@Schema(description = "工单分类")
|
||||
private String ticketCategory;
|
||||
|
||||
@Schema(description = "优先级:urgent-紧急/high-高/normal-普通/low-低", defaultValue = "normal")
|
||||
private String priority;
|
||||
|
||||
@Schema(description = "工单标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "问题描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "附件ID数组")
|
||||
private List<String> attachments;
|
||||
|
||||
@Schema(description = "工单来源:ai-AI生成/manual-人工创建/system-系统自动", defaultValue = "ai")
|
||||
private String ticketSource;
|
||||
|
||||
@Schema(description = "分配给(处理人)")
|
||||
private String assignedTo;
|
||||
|
||||
@Schema(description = "分配部门")
|
||||
private String assignedDept;
|
||||
|
||||
@Schema(description = "工单状态:pending-待处理/processing-处理中/resolved-已解决/closed-已关闭/cancelled-已取消", defaultValue = "pending")
|
||||
private String ticketStatus;
|
||||
|
||||
@Schema(description = "解决方案")
|
||||
private String resolution;
|
||||
|
||||
@Schema(description = "解决时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date resolutionTime;
|
||||
|
||||
@Schema(description = "关闭时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date closeTime;
|
||||
|
||||
@Schema(description = "首次响应时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date responseTime;
|
||||
|
||||
@Schema(description = "SLA截止时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date slaDeadline;
|
||||
|
||||
@Schema(description = "是否逾期", defaultValue = "false")
|
||||
private Boolean isOverdue;
|
||||
|
||||
@Schema(description = "客户评分(1-5星)")
|
||||
private Integer customerRating;
|
||||
|
||||
@Schema(description = "客户反馈")
|
||||
private String customerFeedback;
|
||||
|
||||
@Schema(description = "CRM系统工单ID")
|
||||
private String crmTicketId;
|
||||
|
||||
@Schema(description = "同步状态:pending-待同步/synced-已同步/failed-失败", defaultValue = "pending")
|
||||
private String syncStatus;
|
||||
|
||||
@Schema(description = "工单标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "工单元数据")
|
||||
private JsonNode metadata;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.xyzh.api.workcase.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会话VO
|
||||
* 用于前端展示会话信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "会话VO")
|
||||
public class ConversationVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "会话ID")
|
||||
private String conversationId;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "客户头像")
|
||||
private String customerAvatar;
|
||||
|
||||
@Schema(description = "会话类型")
|
||||
private String conversationType;
|
||||
|
||||
@Schema(description = "会话类型名称")
|
||||
private String conversationTypeName;
|
||||
|
||||
@Schema(description = "渠道")
|
||||
private String channel;
|
||||
|
||||
@Schema(description = "渠道名称")
|
||||
private String channelName;
|
||||
|
||||
@Schema(description = "智能体ID或客服人员ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "座席名称")
|
||||
private String agentName;
|
||||
|
||||
@Schema(description = "座席类型")
|
||||
private String agentType;
|
||||
|
||||
@Schema(description = "座席类型名称")
|
||||
private String agentTypeName;
|
||||
|
||||
@Schema(description = "会话开始时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date sessionStartTime;
|
||||
|
||||
@Schema(description = "会话结束时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date sessionEndTime;
|
||||
|
||||
@Schema(description = "会话时长(秒)")
|
||||
private Integer durationSeconds;
|
||||
|
||||
@Schema(description = "会话时长格式化显示")
|
||||
private String durationFormatted;
|
||||
|
||||
@Schema(description = "消息数量")
|
||||
private Integer messageCount;
|
||||
|
||||
@Schema(description = "会话状态")
|
||||
private String conversationStatus;
|
||||
|
||||
@Schema(description = "会话状态名称")
|
||||
private String conversationStatusName;
|
||||
|
||||
@Schema(description = "会话状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "满意度评分(1-5星)")
|
||||
private Integer satisfactionRating;
|
||||
|
||||
@Schema(description = "满意度反馈")
|
||||
private String satisfactionFeedback;
|
||||
|
||||
@Schema(description = "会话摘要")
|
||||
private String summary;
|
||||
|
||||
@Schema(description = "会话标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "会话元数据")
|
||||
private JsonNode metadata;
|
||||
|
||||
@Schema(description = "最后一条消息内容")
|
||||
private String lastMessageContent;
|
||||
|
||||
@Schema(description = "最后一条消息时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastMessageTime;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.xyzh.api.workcase.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 客户信息VO
|
||||
* 用于前端展示客户信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "客户信息VO")
|
||||
public class CustomerVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "客户编号")
|
||||
private String customerNo;
|
||||
|
||||
@Schema(description = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "客户类型")
|
||||
private String customerType;
|
||||
|
||||
@Schema(description = "客户类型名称")
|
||||
private String customerTypeName;
|
||||
|
||||
@Schema(description = "公司名称")
|
||||
private String companyName;
|
||||
|
||||
@Schema(description = "电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "微信OpenID")
|
||||
private String wechatOpenid;
|
||||
|
||||
@Schema(description = "头像URL")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private Integer gender;
|
||||
|
||||
@Schema(description = "性别名称")
|
||||
private String genderName;
|
||||
|
||||
@Schema(description = "地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "客户等级")
|
||||
private String customerLevel;
|
||||
|
||||
@Schema(description = "客户等级名称")
|
||||
private String customerLevelName;
|
||||
|
||||
@Schema(description = "客户来源")
|
||||
private String customerSource;
|
||||
|
||||
@Schema(description = "客户来源名称")
|
||||
private String customerSourceName;
|
||||
|
||||
@Schema(description = "客户标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String notes;
|
||||
|
||||
@Schema(description = "CRM系统客户ID")
|
||||
private String crmCustomerId;
|
||||
|
||||
@Schema(description = "最后联系时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date lastContactTime;
|
||||
|
||||
@Schema(description = "咨询总次数")
|
||||
private Integer totalConsultations;
|
||||
|
||||
@Schema(description = "订单总数")
|
||||
private Integer totalOrders;
|
||||
|
||||
@Schema(description = "总消费金额")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@Schema(description = "满意度评分")
|
||||
private BigDecimal satisfactionScore;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
@Schema(description = "状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.xyzh.api.workcase.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 工单列表VO
|
||||
* 用于前端列表展示(简化版)
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "工单列表VO")
|
||||
public class TicketListVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "工单ID")
|
||||
private String ticketId;
|
||||
|
||||
@Schema(description = "工单编号")
|
||||
private String ticketNo;
|
||||
|
||||
@Schema(description = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "工单标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "工单类型名称")
|
||||
private String ticketTypeName;
|
||||
|
||||
@Schema(description = "优先级")
|
||||
private String priority;
|
||||
|
||||
@Schema(description = "优先级名称")
|
||||
private String priorityName;
|
||||
|
||||
@Schema(description = "工单状态")
|
||||
private String ticketStatus;
|
||||
|
||||
@Schema(description = "工单状态名称")
|
||||
private String ticketStatusName;
|
||||
|
||||
@Schema(description = "处理人姓名")
|
||||
private String assignedToName;
|
||||
|
||||
@Schema(description = "SLA截止时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date slaDeadline;
|
||||
|
||||
@Schema(description = "是否逾期", defaultValue = "false")
|
||||
private Boolean isOverdue;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package org.xyzh.api.workcase.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.xyzh.common.vo.BaseVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工单VO
|
||||
* 用于前端展示工单信息
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "工单VO")
|
||||
public class TicketVO extends BaseVO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "工单ID")
|
||||
private String ticketId;
|
||||
|
||||
@Schema(description = "工单编号")
|
||||
private String ticketNo;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private String customerId;
|
||||
|
||||
@Schema(description = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "客户电话")
|
||||
private String customerPhone;
|
||||
|
||||
@Schema(description = "关联会话ID")
|
||||
private String conversationId;
|
||||
|
||||
@Schema(description = "工单类型")
|
||||
private String ticketType;
|
||||
|
||||
@Schema(description = "工单类型名称")
|
||||
private String ticketTypeName;
|
||||
|
||||
@Schema(description = "工单分类")
|
||||
private String ticketCategory;
|
||||
|
||||
@Schema(description = "优先级")
|
||||
private String priority;
|
||||
|
||||
@Schema(description = "优先级名称")
|
||||
private String priorityName;
|
||||
|
||||
@Schema(description = "优先级颜色")
|
||||
private String priorityColor;
|
||||
|
||||
@Schema(description = "工单标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "问题描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "附件ID数组")
|
||||
private List<String> attachments;
|
||||
|
||||
@Schema(description = "附件数量")
|
||||
private Integer attachmentCount;
|
||||
|
||||
@Schema(description = "工单来源")
|
||||
private String ticketSource;
|
||||
|
||||
@Schema(description = "工单来源名称")
|
||||
private String ticketSourceName;
|
||||
|
||||
@Schema(description = "分配给(处理人ID)")
|
||||
private String assignedTo;
|
||||
|
||||
@Schema(description = "处理人姓名")
|
||||
private String assignedToName;
|
||||
|
||||
@Schema(description = "分配部门")
|
||||
private String assignedDept;
|
||||
|
||||
@Schema(description = "分配部门名称")
|
||||
private String assignedDeptName;
|
||||
|
||||
@Schema(description = "工单状态")
|
||||
private String ticketStatus;
|
||||
|
||||
@Schema(description = "工单状态名称")
|
||||
private String ticketStatusName;
|
||||
|
||||
@Schema(description = "工单状态颜色")
|
||||
private String statusColor;
|
||||
|
||||
@Schema(description = "解决方案")
|
||||
private String resolution;
|
||||
|
||||
@Schema(description = "解决时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date resolutionTime;
|
||||
|
||||
@Schema(description = "关闭时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date closeTime;
|
||||
|
||||
@Schema(description = "首次响应时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date responseTime;
|
||||
|
||||
@Schema(description = "SLA截止时间", format = "date-time")
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date slaDeadline;
|
||||
|
||||
@Schema(description = "是否逾期", defaultValue = "false")
|
||||
private Boolean isOverdue;
|
||||
|
||||
@Schema(description = "距离SLA截止的剩余时间(分钟)")
|
||||
private Integer slaRemainingMinutes;
|
||||
|
||||
@Schema(description = "客户评分(1-5星)")
|
||||
private Integer customerRating;
|
||||
|
||||
@Schema(description = "客户反馈")
|
||||
private String customerFeedback;
|
||||
|
||||
@Schema(description = "CRM系统工单ID")
|
||||
private String crmTicketId;
|
||||
|
||||
@Schema(description = "同步状态")
|
||||
private String syncStatus;
|
||||
|
||||
@Schema(description = "同步状态名称")
|
||||
private String syncStatusName;
|
||||
|
||||
@Schema(description = "工单标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "工单元数据")
|
||||
private JsonNode metadata;
|
||||
|
||||
@Schema(description = "处理记录数量")
|
||||
private Integer logCount;
|
||||
|
||||
@Schema(description = "创建者姓名")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "更新者姓名")
|
||||
private String updaterName;
|
||||
}
|
||||
@@ -20,6 +20,11 @@
|
||||
<module>api-message</module>
|
||||
<module>api-log</module>
|
||||
<module>api-system</module>
|
||||
<module>api-crontab</module>
|
||||
<module>api-agent</module>
|
||||
<module>api-bidding</module>
|
||||
<module>api-platform</module>
|
||||
<module>api-workcase</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -23,10 +23,42 @@
|
||||
<groupId>org.xyzh.apis</groupId>
|
||||
<artifactId>api-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.apis</groupId>
|
||||
<artifactId>api-system</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.apis</groupId>
|
||||
<artifactId>api-message</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-utils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Nacos Discovery - 用于 Gateway 路由发现 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-logback-adapter-12</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>logback-adapter</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,433 @@
|
||||
package org.xyzh.auth.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.xyzh.api.auth.service.AuthService;
|
||||
import org.xyzh.api.message.service.MessageService;
|
||||
import org.xyzh.api.system.service.SysUserService;
|
||||
import org.xyzh.api.system.vo.SysUserVO;
|
||||
import org.xyzh.auth.utils.CapcatUtils;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.dto.sys.TbSysUserDTO;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.common.utils.validation.method.PhoneValidateMethod;
|
||||
import org.xyzh.common.redis.service.RedisService;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description AuthController.java文件描述 认证控制器
|
||||
* @filename AuthController.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
|
||||
@DubboReference(version = "1.0.0", group = "system", timeout = 5000, check = false)
|
||||
private SysUserService userService;
|
||||
|
||||
@DubboReference(version = "1.0.0", group = "message", timeout = 5000, check = false)
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
/**
|
||||
* @description 用户登录
|
||||
* @param loginParam 登录参数
|
||||
* @return ResultDomain<LoginDomain> 登录结果
|
||||
* @author yslg
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public ResultDomain<LoginDomain> login(@RequestBody LoginParam loginParam, HttpServletRequest request) {
|
||||
return authService.login(loginParam, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户退出登录
|
||||
* @param loginDomain 登录域对象
|
||||
* @return ResultDomain<String> 退出结果
|
||||
* @author yslg
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public ResultDomain<LoginDomain> logout(HttpServletRequest request) {
|
||||
return authService.logout(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取验证码
|
||||
* @return ResultDomain<String> 验证码
|
||||
* @author yslg
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@GetMapping("/captcha")
|
||||
public ResultDomain<String> getCaptcha() {
|
||||
// TODO: 实现验证码生成逻辑
|
||||
// 生成验证码会话ID,用于验证时匹配
|
||||
String captchaId = IDUtils.generateID();
|
||||
String captchaData = captchaId + ":captcha-placeholder"; // 格式: ID:验证码内容
|
||||
|
||||
return ResultDomain.success("验证码获取成功", captchaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 刷新令牌
|
||||
* @param token 原令牌
|
||||
* @return ResultDomain<String> 新令牌
|
||||
* @author yslg
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@PostMapping("/refresh")
|
||||
public ResultDomain<String> refreshToken(@RequestHeader("Authorization") String token) {
|
||||
// TODO: 实现令牌刷新逻辑
|
||||
// 为新令牌生成唯一ID
|
||||
String newTokenId = IDUtils.generateID();
|
||||
String newToken = "new-token-" + newTokenId; // 临时占位符
|
||||
|
||||
return ResultDomain.success("令牌刷新成功", newToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 健康检查
|
||||
* @return ResultDomain<String> 健康状态
|
||||
* @author yslg
|
||||
* @since 2025-09-28
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResultDomain<String> health() {
|
||||
return ResultDomain.success("认证服务运行正常", "OK");
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 发送邮箱验证码
|
||||
* @param requestBody 包含email字段的请求体
|
||||
* @return ResultDomain<Boolean> 发送结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/send-email-code")
|
||||
public ResultDomain<Map<String, String>> sendEmailCode(@RequestBody Map<String, String> requestBody) {
|
||||
String email = requestBody.get("email");
|
||||
|
||||
// 验证邮箱格式
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
return ResultDomain.failure("邮箱不能为空");
|
||||
}
|
||||
|
||||
String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
|
||||
if (!email.matches(emailRegex)) {
|
||||
return ResultDomain.failure("邮箱格式不正确");
|
||||
}
|
||||
|
||||
// 检查是否频繁发送(60秒内只能发送一次)
|
||||
String rateLimitKey = "email:code:ratelimit:" + email;
|
||||
if (redisService.hasKey(rateLimitKey)) {
|
||||
return ResultDomain.failure("验证码已发送,请勿重复发送");
|
||||
}
|
||||
|
||||
// 生成会话ID(用于绑定验证码和用户)
|
||||
String sessionId = IDUtils.generateID();
|
||||
|
||||
// 生成6位数字验证码
|
||||
String code = CapcatUtils.generateVerificationCode();
|
||||
|
||||
// 发送邮件
|
||||
boolean success = messageService.sendEmailVerificationCode(email, code).getSuccess();
|
||||
|
||||
if (success) {
|
||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
||||
String codeKey = "email:code:" + sessionId;
|
||||
String codeValue = email + ":" + code; // 格式:邮箱:验证码
|
||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||
|
||||
// 设置5分钟的发送频率限制
|
||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
||||
|
||||
// 返回sessionId给前端
|
||||
Map<String, String> data = Map.of(
|
||||
"sessionId", sessionId,
|
||||
"message", "验证码已发送到邮箱"
|
||||
);
|
||||
|
||||
logger.info("邮箱验证码已发送,邮箱: {}, sessionId: {}", email, sessionId);
|
||||
return ResultDomain.success("验证码已发送到邮箱", data);
|
||||
} else {
|
||||
return ResultDomain.failure("验证码发送失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 发送手机验证码
|
||||
* @param requestBody 包含phone字段的请求体
|
||||
* @return ResultDomain<Boolean> 发送结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/send-sms-code")
|
||||
public ResultDomain<Map<String, String>> sendSmsCode(@RequestBody Map<String, String> requestBody) {
|
||||
String phone = requestBody.get("phone");
|
||||
|
||||
// 验证手机号格式
|
||||
if (phone == null || phone.trim().isEmpty()) {
|
||||
return ResultDomain.failure("手机号不能为空");
|
||||
}
|
||||
PhoneValidateMethod validateMethod = new PhoneValidateMethod();
|
||||
if (!validateMethod.validate(phone)) {
|
||||
return ResultDomain.failure("手机号格式不正确");
|
||||
}
|
||||
|
||||
// 检查是否频繁发送(60秒内只能发送一次)
|
||||
String rateLimitKey = "sms:code:ratelimit:" + phone;
|
||||
if (redisService.hasKey(rateLimitKey)) {
|
||||
return ResultDomain.failure("验证码已发送,请勿重复发送");
|
||||
}
|
||||
|
||||
// 生成会话ID(用于绑定验证码和用户)
|
||||
String sessionId = IDUtils.generateID();
|
||||
|
||||
// 生成6位数字验证码
|
||||
String code = CapcatUtils.generateVerificationCode();
|
||||
|
||||
// 发送短信
|
||||
boolean success = messageService.sendPhoneVerificationCode(phone, code).getSuccess();
|
||||
|
||||
if (success) {
|
||||
// 将验证码存储到Redis,绑定sessionId,有效期5分钟
|
||||
String codeKey = "sms:code:" + sessionId;
|
||||
String codeValue = phone + ":" + code; // 格式:手机号:验证码
|
||||
redisService.set(codeKey, codeValue, 5, TimeUnit.MINUTES);
|
||||
|
||||
// 设置5分钟的发送频率限制
|
||||
redisService.set(rateLimitKey, "1", 5, TimeUnit.MINUTES);
|
||||
|
||||
// 返回sessionId给前端
|
||||
Map<String, String> data = Map.of(
|
||||
"sessionId", sessionId,
|
||||
"message", "验证码已发送"
|
||||
);
|
||||
|
||||
logger.info("短信验证码已发送,手机号: {}, sessionId: {}", phone, sessionId);
|
||||
return ResultDomain.success("验证码已发送", data);
|
||||
} else {
|
||||
return ResultDomain.failure("验证码发送失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用户注册
|
||||
* @param requestBody 注册参数
|
||||
* @return ResultDomain<LoginDomain> 注册结果
|
||||
* @author yslg
|
||||
* @since 2025-11-03
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public ResultDomain<LoginDomain> register(@RequestBody Map<String, Object> requestBody, HttpServletRequest request) {
|
||||
try {
|
||||
// 获取注册参数
|
||||
String registerType = (String) requestBody.get("registerType");
|
||||
String username = (String) requestBody.get("username");
|
||||
String phone = (String) requestBody.get("phone");
|
||||
String email = (String) requestBody.get("email");
|
||||
String password = (String) requestBody.get("password");
|
||||
String confirmPassword = (String) requestBody.get("confirmPassword");
|
||||
String smsCode = (String) requestBody.get("smsCode");
|
||||
String emailCode = (String) requestBody.get("emailCode");
|
||||
String smsSessionId = (String) requestBody.get("smsSessionId");
|
||||
String emailSessionId = (String) requestBody.get("emailSessionId");
|
||||
String studentId = (String) requestBody.get("studentId");
|
||||
|
||||
// 1. 参数验证
|
||||
if (password == null || password.trim().isEmpty()) {
|
||||
return ResultDomain.failure("密码不能为空");
|
||||
}
|
||||
|
||||
if (password.length() < 6) {
|
||||
return ResultDomain.failure("密码至少6个字符");
|
||||
}
|
||||
|
||||
if (!password.equals(confirmPassword)) {
|
||||
return ResultDomain.failure("两次输入的密码不一致");
|
||||
}
|
||||
|
||||
// 2. 根据注册类型进行不同的验证
|
||||
SysUserVO user = new SysUserVO();
|
||||
|
||||
switch (registerType) {
|
||||
case "username":
|
||||
// 用户名注册
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
return ResultDomain.failure("用户名不能为空");
|
||||
}
|
||||
if (username.length() < 3 || username.length() > 20) {
|
||||
return ResultDomain.failure("用户名长度为3-20个字符");
|
||||
}
|
||||
if (!username.matches("^[a-zA-Z0-9_]+$")) {
|
||||
return ResultDomain.failure("用户名只能包含字母、数字和下划线");
|
||||
}
|
||||
user.setUsername(username);
|
||||
logger.info("用户名注册: {}", username);
|
||||
break;
|
||||
|
||||
case "phone":
|
||||
// 手机号注册
|
||||
if (phone == null || phone.trim().isEmpty()) {
|
||||
return ResultDomain.failure("手机号不能为空");
|
||||
}
|
||||
if (!phone.matches("^1[3-9]\\d{9}$")) {
|
||||
return ResultDomain.failure("手机号格式不正确");
|
||||
}
|
||||
if (smsCode == null || smsCode.trim().isEmpty()) {
|
||||
return ResultDomain.failure("请输入手机验证码");
|
||||
}
|
||||
if (smsSessionId == null || smsSessionId.trim().isEmpty()) {
|
||||
return ResultDomain.failure("会话已失效,请重新获取验证码");
|
||||
}
|
||||
|
||||
// 通过sessionId验证手机验证码
|
||||
String smsCodeKey = "sms:code:" + smsSessionId;
|
||||
String storedSmsValue = (String) redisService.get(smsCodeKey);
|
||||
if (storedSmsValue == null) {
|
||||
return ResultDomain.failure("验证码已过期,请重新获取");
|
||||
}
|
||||
|
||||
// 解析存储的值:手机号:验证码
|
||||
String[] smsParts = storedSmsValue.split(":");
|
||||
if (smsParts.length != 2) {
|
||||
return ResultDomain.failure("验证码数据异常");
|
||||
}
|
||||
|
||||
String storedPhone = smsParts[0];
|
||||
String storedSmsCode = smsParts[1];
|
||||
|
||||
// 验证手机号和验证码是否匹配
|
||||
if (!storedPhone.equals(phone)) {
|
||||
logger.warn("手机号注册验证失败,提交手机号: {}, 验证码绑定手机号: {}", phone, storedPhone);
|
||||
return ResultDomain.failure("手机号与验证码不匹配");
|
||||
}
|
||||
if (!storedSmsCode.equals(smsCode)) {
|
||||
return ResultDomain.failure("验证码错误");
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(smsCodeKey);
|
||||
|
||||
user.setPhone(phone);
|
||||
user.setUsername(phone); // 使用手机号作为用户名
|
||||
logger.info("手机号注册: {}, sessionId: {}", phone, smsSessionId);
|
||||
break;
|
||||
|
||||
case "email":
|
||||
// 邮箱注册
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
return ResultDomain.failure("邮箱不能为空");
|
||||
}
|
||||
if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
|
||||
return ResultDomain.failure("邮箱格式不正确");
|
||||
}
|
||||
if (emailCode == null || emailCode.trim().isEmpty()) {
|
||||
return ResultDomain.failure("请输入邮箱验证码");
|
||||
}
|
||||
if (emailSessionId == null || emailSessionId.trim().isEmpty()) {
|
||||
return ResultDomain.failure("会话已失效,请重新获取验证码");
|
||||
}
|
||||
|
||||
// 通过sessionId验证邮箱验证码
|
||||
String emailCodeKey = "email:code:" + emailSessionId;
|
||||
String storedEmailValue = (String) redisService.get(emailCodeKey);
|
||||
if (storedEmailValue == null) {
|
||||
return ResultDomain.failure("验证码已过期,请重新获取");
|
||||
}
|
||||
|
||||
// 解析存储的值:邮箱:验证码
|
||||
String[] emailParts = storedEmailValue.split(":");
|
||||
if (emailParts.length != 2) {
|
||||
return ResultDomain.failure("验证码数据异常");
|
||||
}
|
||||
|
||||
String storedEmail = emailParts[0];
|
||||
String storedEmailCode = emailParts[1];
|
||||
|
||||
// 验证邮箱和验证码是否匹配
|
||||
if (!storedEmail.equals(email)) {
|
||||
logger.warn("邮箱注册验证失败,提交邮箱: {}, 验证码绑定邮箱: {}", email, storedEmail);
|
||||
return ResultDomain.failure("邮箱与验证码不匹配");
|
||||
}
|
||||
if (!storedEmailCode.equals(emailCode)) {
|
||||
return ResultDomain.failure("验证码错误");
|
||||
}
|
||||
|
||||
// 验证码使用后删除
|
||||
redisService.delete(emailCodeKey);
|
||||
|
||||
user.setEmail(email);
|
||||
user.setUsername(email.split("@")[0]); // 使用邮箱前缀作为用户名
|
||||
logger.info("邮箱注册: {}, sessionId: {}", email, emailSessionId);
|
||||
break;
|
||||
|
||||
default:
|
||||
return ResultDomain.failure("未知的注册类型");
|
||||
}
|
||||
|
||||
// 3. 设置密码(明文,Service层会加密)
|
||||
user.setPassword(password);
|
||||
|
||||
// 4. 设置用户状态为正常
|
||||
user.setStatus("0");
|
||||
|
||||
// 5. 调用UserService注册用户(Service层会加密密码)
|
||||
ResultDomain<TbSysUserDTO> registerResult = userService.registerUser(user);
|
||||
|
||||
if (!registerResult.getSuccess()) {
|
||||
return ResultDomain.failure(registerResult.getMessage());
|
||||
}
|
||||
|
||||
logger.info("用户注册成功: {}", user.getUsername());
|
||||
|
||||
// 6. 注册成功后自动登录
|
||||
LoginParam loginParam = new LoginParam();
|
||||
loginParam.setUsername(user.getUsername());
|
||||
loginParam.setPassword(password);
|
||||
loginParam.setLoginType("password");
|
||||
|
||||
if (phone != null && !phone.trim().isEmpty()) {
|
||||
loginParam.setPhone(phone);
|
||||
}
|
||||
if (email != null && !email.trim().isEmpty()) {
|
||||
loginParam.setEmail(email);
|
||||
}
|
||||
|
||||
ResultDomain<LoginDomain> loginResult = authService.login(loginParam, request);
|
||||
|
||||
if (loginResult.getSuccess()) {
|
||||
return ResultDomain.success("注册成功", loginResult.getData());
|
||||
} else {
|
||||
// 注册成功但登录失败,返回注册成功信息
|
||||
return ResultDomain.success("注册成功,请登录", loginResult.getData());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("用户注册失败", e);
|
||||
return ResultDomain.failure("注册失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.xyzh.auth.exception;
|
||||
import org.xyzh.common.core.exception.BaseException;
|
||||
|
||||
public class AuthException extends BaseException {
|
||||
|
||||
public AuthException(Integer code, String description, String message){
|
||||
super(code, description, message);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import org.xyzh.api.auth.service.AuthService;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.core.domain.LoginParam;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -17,6 +17,12 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
* @copyright yslg
|
||||
* @since 2025-11-09
|
||||
*/
|
||||
@DubboService(
|
||||
version = "1.0.0",
|
||||
group = "auth",
|
||||
timeout = 3000,
|
||||
retries = 0
|
||||
)
|
||||
public class AuthServiceImpl implements AuthService{
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthServiceImpl.class);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user