This commit is contained in:
2025-12-02 13:21:18 +08:00
parent fab8c13cb3
commit ee6dd64f98
192 changed files with 25783 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
-- 删除已存在的数据库(如果存在)
DROP DATABASE IF EXISTS urban-lifeline;
-- 创建新数据库,使用 UTF8 编码,并设置适合中文的排序规则
-- 使用 template0 确保干净的数据库模板
-- zh_CN.UTF-8 支持中文字符排序和比较
CREATE DATABASE urban-lifeline
ENCODING 'UTF8'
TEMPLATE template0
LC_COLLATE 'zh_CN.UTF-8'
LC_CTYPE 'zh_CN.UTF-8';
-- 连接到新创建的数据库
\c urban-lifeline;
-- -- 创建扩展(如果需要)
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID 支持
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- 文本搜索支持
CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- GiST 索引支持
-- 设置搜索路径(可选,但建议设置)
-- ALTER DATABASE urban-lifeline SET search_path TO sys, public;
-- sudo ./configure --prefix=/opt/postgres/postgres-17.6
-- --with-uuid=ossp --with-openssl --with-libxml --with-pam
-- && sudo make && sudo make install

View File

@@ -0,0 +1,308 @@
-- =============================
-- 智能体管理和平台基础设施模块
-- 支持智能体广场、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)
);
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';
-- 智能体会话表
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;
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)
);
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 '智能体消息表';
-- 智能体工具表
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, -- 函数SchemaOpenAI 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;
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)
);
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集成注册表';
-- 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);
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)
);
CREATE INDEX idx_metrics_agent_date ON agent.tb_agent_metrics(agent_id, metric_date DESC);
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)
);
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 '智能体异常日志表';
-- 智能体评价表
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;
COMMENT ON TABLE agent.tb_agent_rating IS '智能体评价表';

View File

@@ -0,0 +1,209 @@
-- =============================
-- 泰豪电源AI数智化平台 - 完整数据库初始化脚本
-- 包含所有业务模块的表结构
-- =============================
-- 安装必要的扩展
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 "vector"; -- pgvector向量检索需要单独安装
-- =============================
-- 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
-- =============================
-- 创建通用触发器函数
-- =============================
-- 自动更新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();
-- =============================
-- 创建视图
-- =============================
-- 用户完整信息视图
CREATE OR REPLACE VIEW sys.v_user_full_info AS
SELECT
u.user_id,
u.email,
u.phone,
u.wechat_id,
u.status,
ui.avatar,
ui.full_name,
ui.gender,
ui.level,
u.create_time,
u.update_time
FROM sys.tb_sys_user u
LEFT JOIN sys.tb_sys_user_info ui ON u.user_id = ui.user_id
WHERE u.deleted = false AND (ui.deleted = false OR ui.deleted IS NULL);
-- 用户角色权限视图
CREATE OR REPLACE VIEW sys.v_user_role_permission AS
SELECT DISTINCT
ur.user_id,
r.role_id,
r.name AS role_name,
p.permission_id,
p.code AS permission_code,
p.name AS permission_name,
m.module_id,
m.name AS module_name
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
LEFT JOIN sys.tb_sys_module m ON p.module_id = m.module_id
WHERE ur.deleted = false
AND r.deleted = false
AND rp.deleted = false
AND p.deleted = false;
-- 智能体使用统计视图
CREATE OR REPLACE VIEW agent.v_agent_usage_stats AS
SELECT
a.agent_id,
a.agent_name,
a.agent_type,
COUNT(DISTINCT s.session_id) AS total_sessions,
COUNT(DISTINCT s.user_id) AS unique_users,
SUM(s.message_count) AS total_messages,
AVG(s.token_usage) AS avg_token_usage,
AVG(r.rating) AS avg_rating,
COUNT(r.rating_id) AS rating_count,
MAX(s.start_time) AS last_used_time
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;
-- 客服工单统计视图
CREATE OR REPLACE VIEW customer_service.v_ticket_stats AS
SELECT
t.ticket_status,
t.priority,
t.ticket_type,
COUNT(*) AS ticket_count,
AVG(EXTRACT(EPOCH FROM (t.resolution_time - t.create_time))/3600) AS avg_resolution_hours,
AVG(t.customer_rating) AS avg_rating,
COUNT(CASE WHEN t.is_overdue THEN 1 END) AS overdue_count
FROM customer_service.tb_ticket t
WHERE t.deleted = false
GROUP BY t.ticket_status, t.priority, t.ticket_type;
-- 招投标项目统计视图
CREATE OR REPLACE VIEW bidding.v_project_stats AS
SELECT
p.project_status,
p.project_type,
COUNT(*) AS project_count,
SUM(p.budget_amount) AS total_budget,
SUM(CASE WHEN p.winning_status = 'won' THEN 1 ELSE 0 END) AS won_count,
SUM(CASE WHEN p.winning_status = 'won' THEN p.winning_amount ELSE 0 END) AS total_won_amount,
AVG(CASE WHEN p.winning_status = 'won' THEN p.winning_amount / NULLIF(p.budget_amount, 0) ELSE NULL END) AS avg_win_rate
FROM bidding.tb_bidding_project p
WHERE p.deleted = false
GROUP BY p.project_status, p.project_type;
COMMENT ON VIEW sys.v_user_full_info IS '用户完整信息视图';
COMMENT ON VIEW sys.v_user_role_permission IS '用户角色权限视图';
COMMENT ON VIEW agent.v_agent_usage_stats IS '智能体使用统计视图';
COMMENT ON VIEW customer_service.v_ticket_stats IS '客服工单统计视图';
COMMENT ON VIEW bidding.v_project_stats IS '招投标项目统计视图';
-- =============================
-- 数据库初始化完成
-- =============================

View File

@@ -0,0 +1,264 @@
-- =============================
-- 招投标智能体业务模块
-- 支持:招标文件管理、投标文件生成、评分分析、流程跟踪
-- =============================
CREATE SCHEMA IF NOT EXISTS bidding;
-- 招标项目表
DROP TABLE IF EXISTS bidding.tb_bidding_project CASCADE;
CREATE TABLE bidding.tb_bidding_project (
optsn VARCHAR(50) NOT NULL, -- 流水号
project_id VARCHAR(50) NOT NULL, -- 项目ID
project_no VARCHAR(100) NOT NULL, -- 项目编号
project_name VARCHAR(500) NOT NULL, -- 项目名称
project_type VARCHAR(50) NOT NULL, -- 项目类型public-公开招标/invitation-邀请招标/competitive_negotiation-竞争性谈判
industry VARCHAR(100), -- 所属行业
source_platform VARCHAR(100), -- 来源平台(如:政府采购网、企业官网等)
source_url VARCHAR(500), -- 来源URL
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-放弃
winning_status VARCHAR(30), -- 中标状态pending-待定/won-中标/lost-未中标
winning_amount DECIMAL(18,2), -- 中标金额
client_name VARCHAR(255), -- 客户名称
client_contact VARCHAR(100), -- 客户联系方式
contact_person VARCHAR(100), -- 联系人
project_location VARCHAR(500), -- 项目地点
description TEXT, -- 项目描述
keywords TEXT[], -- 关键词数组
metadata JSONB DEFAULT NULL, -- 项目元数据
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
responsible_user VARCHAR(50), -- 负责人
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (project_id),
UNIQUE (optsn),
UNIQUE (project_no)
);
CREATE INDEX idx_project_status ON bidding.tb_bidding_project(project_status) WHERE deleted = false;
CREATE INDEX idx_project_deadline ON bidding.tb_bidding_project(deadline) WHERE deleted = false;
CREATE INDEX idx_project_dept ON bidding.tb_bidding_project(dept_path) WHERE deleted = false;
CREATE INDEX idx_project_responsible ON bidding.tb_bidding_project(responsible_user) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bidding_project IS '招标项目表';
COMMENT ON COLUMN bidding.tb_bidding_project.project_status IS '项目状态collecting/analyzing/preparing/submitted/opened/won/lost/abandoned';
-- 招标文件表
DROP TABLE IF EXISTS bidding.tb_bidding_document CASCADE;
CREATE TABLE bidding.tb_bidding_document (
optsn VARCHAR(50) NOT NULL, -- 流水号
doc_id VARCHAR(50) NOT NULL, -- 文档ID
project_id VARCHAR(50) NOT NULL, -- 所属项目ID
doc_type VARCHAR(50) NOT NULL, -- 文档类型tender-招标文件/technical-技术标/commercial-商务标/clarification-澄清文件/other-其他
doc_name VARCHAR(500) NOT NULL, -- 文档名称
file_id VARCHAR(50), -- 关联文件表ID
file_path VARCHAR(500), -- 文件路径
file_size BIGINT, -- 文件大小
mime_type VARCHAR(100), -- MIME类型
version VARCHAR(20) DEFAULT '1.0', -- 版本号
language VARCHAR(20) DEFAULT 'zh-CN', -- 语言
page_count INTEGER, -- 页数
parse_status VARCHAR(30) DEFAULT 'pending', -- 解析状态pending-待解析/parsing-解析中/completed-已完成/failed-失败
parse_result JSONB, -- 解析结果JSON格式提取的要素、表格、图纸等
extraction_data JSONB, -- 提取的结构化数据
ai_analysis TEXT, -- AI分析结果
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (doc_id),
UNIQUE (optsn),
FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id)
);
CREATE INDEX idx_doc_project ON bidding.tb_bidding_document(project_id) WHERE deleted = false;
CREATE INDEX idx_doc_type ON bidding.tb_bidding_document(doc_type) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bidding_document IS '招标文件表';
COMMENT ON COLUMN bidding.tb_bidding_document.parse_status IS '解析状态pending/parsing/completed/failed';
-- 招标要素提取表
DROP TABLE IF EXISTS bidding.tb_bidding_requirement CASCADE;
CREATE TABLE bidding.tb_bidding_requirement (
optsn VARCHAR(50) NOT NULL, -- 流水号
req_id VARCHAR(50) NOT NULL, -- 要素ID
project_id VARCHAR(50) NOT NULL, -- 所属项目ID
doc_id VARCHAR(50), -- 来源文档ID
req_category VARCHAR(50) NOT NULL, -- 要素类别commercial-商务要素/technical-技术参数/veto-否决项/qualification-资质要求/delivery-交付要求/payment-付款条件/scoring-评分标准
req_name VARCHAR(255) NOT NULL, -- 要素名称
req_content TEXT NOT NULL, -- 要素内容
req_value VARCHAR(500), -- 要素值
is_mandatory BOOLEAN DEFAULT false, -- 是否必填
is_veto BOOLEAN DEFAULT false, -- 是否为否决项
priority INTEGER DEFAULT 0, -- 优先级
extraction_method VARCHAR(30) DEFAULT 'ai', -- 提取方式ai-AI提取/manual-人工录入
confidence_score DECIMAL(5,4), -- 置信度分数0-1
source_location JSONB, -- 来源位置(页码、段落等)
compliance_status VARCHAR(30), -- 合规状态compliant-符合/non_compliant-不符合/pending-待确认
response_content TEXT, -- 响应内容(我方的应答)
notes TEXT, -- 备注
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 (req_id),
UNIQUE (optsn),
FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id)
);
CREATE INDEX idx_req_project ON bidding.tb_bidding_requirement(project_id) WHERE deleted = false;
CREATE INDEX idx_req_category ON bidding.tb_bidding_requirement(req_category) WHERE deleted = false;
CREATE INDEX idx_req_veto ON bidding.tb_bidding_requirement(is_veto) WHERE deleted = false AND is_veto = true;
COMMENT ON TABLE bidding.tb_bidding_requirement IS '招标要素提取表';
COMMENT ON COLUMN bidding.tb_bidding_requirement.req_category IS '要素类别commercial/technical/veto/qualification/delivery/payment/scoring';
-- 投标文件生成表
DROP TABLE IF EXISTS bidding.tb_bid_response CASCADE;
CREATE TABLE bidding.tb_bid_response (
optsn VARCHAR(50) NOT NULL, -- 流水号
response_id VARCHAR(50) NOT NULL, -- 响应文件ID
project_id VARCHAR(50) NOT NULL, -- 所属项目ID
response_type VARCHAR(50) NOT NULL, -- 响应类型technical-技术标/commercial-商务标/comprehensive-综合标
doc_name VARCHAR(500) NOT NULL, -- 文档名称
outline TEXT, -- 文档大纲JSON格式
content TEXT, -- 文档内容
generation_method VARCHAR(30) DEFAULT 'ai', -- 生成方式ai-AI生成/template-模板生成/manual-人工编写
template_id VARCHAR(50), -- 使用的模板ID
ai_model VARCHAR(100), -- 使用的AI模型
generation_status VARCHAR(30) DEFAULT 'draft', -- 生成状态draft-草稿/reviewing-审核中/approved-已批准/rejected-已拒绝/submitted-已提交
file_id VARCHAR(50), -- 生成的文件ID
file_path VARCHAR(500), -- 文件路径
version VARCHAR(20) DEFAULT '1.0', -- 版本号
parent_version_id VARCHAR(50), -- 父版本ID
review_comments TEXT, -- 审核意见
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 (response_id),
UNIQUE (optsn),
FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id)
);
CREATE INDEX idx_response_project ON bidding.tb_bid_response(project_id) WHERE deleted = false;
CREATE INDEX idx_response_status ON bidding.tb_bid_response(generation_status) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bid_response IS '投标文件生成表';
COMMENT ON COLUMN bidding.tb_bid_response.generation_status IS '生成状态draft/reviewing/approved/rejected/submitted';
-- 评分规则表
DROP TABLE IF EXISTS bidding.tb_bidding_scoring_rule CASCADE;
CREATE TABLE bidding.tb_bidding_scoring_rule (
optsn VARCHAR(50) NOT NULL, -- 流水号
rule_id VARCHAR(50) NOT NULL, -- 规则ID
project_id VARCHAR(50) NOT NULL, -- 所属项目ID
rule_category VARCHAR(50) NOT NULL, -- 规则类别technical-技术分/commercial-商务分/price-价格分/credit-信誉分
rule_name VARCHAR(255) NOT NULL, -- 规则名称
rule_description TEXT, -- 规则描述
max_score DECIMAL(10,2) NOT NULL, -- 最高分值
weight DECIMAL(5,4), -- 权重0-1
scoring_method VARCHAR(50), -- 评分方法fixed-固定分值/range-区间评分/formula-公式计算
calculation_formula TEXT, -- 计算公式
evaluation_criteria TEXT, -- 评分标准
our_score DECIMAL(10,2), -- 我方得分(预估)
score_analysis TEXT, -- 得分分析
optimization_advice TEXT, -- 优化建议
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 (rule_id),
UNIQUE (optsn),
FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id)
);
CREATE INDEX idx_rule_project ON bidding.tb_bidding_scoring_rule(project_id) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bidding_scoring_rule IS '评分规则表';
-- 项目流程节点表
DROP TABLE IF EXISTS bidding.tb_bidding_process CASCADE;
CREATE TABLE bidding.tb_bidding_process (
optsn VARCHAR(50) NOT NULL, -- 流水号
process_id VARCHAR(50) NOT NULL, -- 流程节点ID
project_id VARCHAR(50) NOT NULL, -- 所属项目ID
node_name VARCHAR(255) NOT NULL, -- 节点名称
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, -- 实际结束时间
responsible_user VARCHAR(50), -- 负责人
participants VARCHAR(50)[], -- 参与人员数组
notes TEXT, -- 节点备注
attachments VARCHAR(50)[], -- 附件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, -- 是否删除
PRIMARY KEY (process_id),
UNIQUE (optsn),
FOREIGN KEY (project_id) REFERENCES bidding.tb_bidding_project(project_id)
);
CREATE INDEX idx_process_project ON bidding.tb_bidding_process(project_id, node_order) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bidding_process IS '项目流程节点表';
COMMENT ON COLUMN bidding.tb_bidding_process.node_type IS '节点类型collection/analysis/preparation/review/submission/opening/result';
-- 投标模板表
DROP TABLE IF EXISTS bidding.tb_bid_template CASCADE;
CREATE TABLE bidding.tb_bid_template (
optsn VARCHAR(50) NOT NULL, -- 流水号
template_id VARCHAR(50) NOT NULL, -- 模板ID
template_name VARCHAR(255) NOT NULL, -- 模板名称
template_type VARCHAR(50) NOT NULL, -- 模板类型technical-技术标/commercial-商务标/comprehensive-综合标
industry VARCHAR(100), -- 适用行业
template_content TEXT, -- 模板内容
outline_structure JSONB, -- 大纲结构JSON格式
file_id VARCHAR(50), -- 模板文件ID
usage_count INTEGER DEFAULT 0, -- 使用次数
is_default BOOLEAN DEFAULT false, -- 是否默认模板
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (template_id),
UNIQUE (optsn)
);
CREATE INDEX idx_template_type ON bidding.tb_bid_template(template_type) WHERE deleted = false;
COMMENT ON TABLE bidding.tb_bid_template IS '投标模板表';

View File

@@ -0,0 +1,51 @@
CREATE SCHEMA IF NOT EXISTS config;
DROP TABLE IF EXISTS config.tb_sys_config CASCADE;
CREATE TABLE config.tb_sys_config (
optsn VARCHAR(50) NOT NULL, -- 流水号
config_id VARCHAR(50) NOT NULL, -- 配置ID
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)
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, -- 配置组
module_id VARCHAR(255) NOT NULL, -- 模块id
order_num INT NOT NULL, -- 配置顺序
status INT NOT NULL DEFAULT 0, -- 配置状态 0:启用 1:禁用
remark VARCHAR(255) NOT NULL, -- 配置备注
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, -- 配置删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (config_id),
UNIQUE (optsn)
);
COMMENT ON TABLE config.tb_sys_config IS '系统配置表';
COMMENT ON COLUMN config.tb_sys_config.optsn IS '流水号';
COMMENT ON COLUMN config.tb_sys_config.config_id IS '配置ID';
COMMENT ON COLUMN config.tb_sys_config.key IS '配置键';
COMMENT ON COLUMN config.tb_sys_config.name IS '配置名称';
COMMENT ON COLUMN config.tb_sys_config.value IS '配置值';
COMMENT ON COLUMN config.tb_sys_config.config_type IS '数据类型';
COMMENT ON COLUMN config.tb_sys_config.render_type IS '数据渲染类型';
COMMENT ON COLUMN config.tb_sys_config.description IS '配置描述';
COMMENT ON COLUMN config.tb_sys_config.re IS '正则表达式校验规则';
COMMENT ON COLUMN config.tb_sys_config.options IS '可选项';
COMMENT ON COLUMN config.tb_sys_config.group IS'配置组名称';
COMMENT ON COLUMN config.tb_sys_config.module_id IS '模块id';
COMMENT ON COLUMN config.tb_sys_config.order_num IS '配置顺序';
COMMENT ON COLUMN config.tb_sys_config.status IS '配置状态';
COMMENT ON COLUMN config.tb_sys_config.remark IS '配置备注';
COMMENT ON COLUMN config.tb_sys_config.creator IS '创建者';
COMMENT ON COLUMN config.tb_sys_config.dept_path IS '部门全路径';
COMMENT ON COLUMN config.tb_sys_config.updater IS '更新者';
COMMENT ON COLUMN config.tb_sys_config.create_time IS '配置创建时间';
COMMENT ON COLUMN config.tb_sys_config.update_time IS '配置更新时间';
COMMENT ON COLUMN config.tb_sys_config.delete_time IS '配置删除时间';
COMMENT ON COLUMN config.tb_sys_config.deleted IS '是否删除';

View File

@@ -0,0 +1,289 @@
-- =============================
-- 智能客服系统业务模块
-- 支持微信小程序客户咨询、智能问答、工单管理、CRM集成
-- =============================
CREATE SCHEMA IF NOT EXISTS customer_service;
-- 客户信息表
DROP TABLE IF EXISTS customer_service.tb_customer CASCADE;
CREATE TABLE customer_service.tb_customer (
optsn VARCHAR(50) NOT NULL, -- 流水号
customer_id VARCHAR(50) NOT NULL, -- 客户ID
customer_no VARCHAR(100), -- 客户编号
customer_name VARCHAR(255), -- 客户姓名
customer_type VARCHAR(30) DEFAULT 'individual', -- 客户类型individual-个人/enterprise-企业
company_name VARCHAR(255), -- 公司名称
phone VARCHAR(20), -- 电话
email VARCHAR(100), -- 邮箱
wechat_openid VARCHAR(100), -- 微信OpenID
wechat_unionid VARCHAR(100), -- 微信UnionID
avatar VARCHAR(500), -- 头像URL
gender INTEGER DEFAULT 0, -- 性别0-未知/1-男/2-女
address VARCHAR(500), -- 地址
customer_level VARCHAR(20) DEFAULT 'normal', -- 客户等级vip/important/normal/potential
customer_source VARCHAR(50), -- 客户来源wechat-微信/web-网站/phone-电话/referral-推荐
tags TEXT[], -- 客户标签数组
notes TEXT, -- 备注
crm_customer_id VARCHAR(50), -- CRM系统客户ID外部系统
last_contact_time timestamptz, -- 最后联系时间
total_consultations INTEGER DEFAULT 0, -- 咨询总次数
total_orders INTEGER DEFAULT 0, -- 订单总数
total_amount DECIMAL(18,2) DEFAULT 0, -- 总消费金额
satisfaction_score DECIMAL(3,2), -- 满意度评分1-5
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (customer_id),
UNIQUE (optsn),
UNIQUE (wechat_openid),
UNIQUE (phone),
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;
COMMENT ON TABLE customer_service.tb_customer IS '客户信息表';
COMMENT ON COLUMN customer_service.tb_customer.customer_level IS '客户等级vip/important/normal/potential';
-- 会话表
DROP TABLE IF EXISTS customer_service.tb_conversation CASCADE;
CREATE TABLE customer_service.tb_conversation (
optsn VARCHAR(50) NOT NULL, -- 流水号
conversation_id VARCHAR(50) NOT NULL, -- 会话ID
customer_id VARCHAR(50) NOT NULL, -- 客户ID
conversation_type VARCHAR(30) DEFAULT 'ai', -- 会话类型ai-AI客服/human-人工客服/transfer-转接
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, -- 会话结束时间
duration_seconds INTEGER, -- 会话时长(秒)
message_count INTEGER DEFAULT 0, -- 消息数量
conversation_status VARCHAR(20) DEFAULT 'active', -- 会话状态active-进行中/closed-已结束/transferred-已转接/timeout-超时
satisfaction_rating INTEGER, -- 满意度评分1-5星
satisfaction_feedback TEXT, -- 满意度反馈
summary TEXT, -- 会话摘要AI生成
tags TEXT[], -- 会话标签
metadata 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 (conversation_id),
UNIQUE (optsn),
FOREIGN KEY (customer_id) REFERENCES customer_service.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;
COMMENT ON TABLE customer_service.tb_conversation IS '会话表';
COMMENT ON COLUMN customer_service.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 (
optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID
conversation_id VARCHAR(50) NOT NULL, -- 所属会话ID
sender_type VARCHAR(20) NOT NULL, -- 发送者类型customer-客户/agent-座席/system-系统
sender_id VARCHAR(50), -- 发送者ID
message_type VARCHAR(30) NOT NULL DEFAULT 'text',-- 消息类型text-文本/image-图片/voice-语音/video-视频/file-文件/card-卡片
content TEXT, -- 消息内容
content_url VARCHAR(500), -- 内容URL图片、文件等
is_ai_generated BOOLEAN DEFAULT false, -- 是否AI生成
ai_model VARCHAR(100), -- 使用的AI模型
kb_references VARCHAR(50)[], -- 引用的知识库文档ID数组
confidence_score DECIMAL(5,4), -- AI回答置信度
sentiment VARCHAR(20), -- 情感分析positive-正面/neutral-中性/negative-负面
intent VARCHAR(100), -- 意图识别结果
is_sensitive BOOLEAN DEFAULT false, -- 是否敏感信息
read_status BOOLEAN DEFAULT false, -- 已读状态
read_time timestamptz, -- 阅读时间
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 (conversation_id) REFERENCES customer_service.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;
COMMENT ON TABLE customer_service.tb_conversation_message IS '会话消息表';
COMMENT ON COLUMN customer_service.tb_conversation_message.sentiment IS '情感分析positive/neutral/negative';
-- 工单表
DROP TABLE IF EXISTS customer_service.tb_ticket CASCADE;
CREATE TABLE customer_service.tb_ticket (
optsn VARCHAR(50) NOT NULL, -- 流水号
ticket_id VARCHAR(50) NOT NULL, -- 工单ID
ticket_no VARCHAR(100) NOT NULL, -- 工单编号
customer_id VARCHAR(50) NOT NULL, -- 客户ID
conversation_id VARCHAR(50), -- 关联会话ID
ticket_type VARCHAR(50) NOT NULL, -- 工单类型consultation-咨询/complaint-投诉/suggestion-建议/repair-维修/installation-安装/other-其他
ticket_category VARCHAR(100), -- 工单分类(具体业务分类)
priority VARCHAR(20) DEFAULT 'normal', -- 优先级urgent-紧急/high-高/normal-普通/low-低
title VARCHAR(500) NOT NULL, -- 工单标题
description TEXT NOT NULL, -- 问题描述
attachments VARCHAR(50)[], -- 附件ID数组
ticket_source VARCHAR(30) DEFAULT 'ai', -- 工单来源ai-AI生成/manual-人工创建/system-系统自动
assigned_to VARCHAR(50), -- 分配给(处理人)
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截止时间
is_overdue BOOLEAN DEFAULT false, -- 是否逾期
customer_rating INTEGER, -- 客户评分1-5星
customer_feedback TEXT, -- 客户反馈
crm_ticket_id VARCHAR(50), -- CRM系统工单ID外部系统
sync_status VARCHAR(20) DEFAULT 'pending', -- 同步状态pending-待同步/synced-已同步/failed-失败
tags TEXT[], -- 工单标签
metadata 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 (ticket_id),
UNIQUE (optsn),
UNIQUE (ticket_no),
FOREIGN KEY (customer_id) REFERENCES customer_service.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;
COMMENT ON TABLE customer_service.tb_ticket IS '工单表';
COMMENT ON COLUMN customer_service.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 (
optsn VARCHAR(50) NOT NULL, -- 流水号
log_id VARCHAR(50) NOT NULL, -- 日志ID
ticket_id VARCHAR(50) NOT NULL, -- 工单ID
action_type VARCHAR(50) NOT NULL, -- 操作类型create-创建/assign-分配/update-更新/comment-评论/resolve-解决/close-关闭/reopen-重开
action_content TEXT, -- 操作内容
old_value TEXT, -- 旧值
new_value TEXT, -- 新值
operator_id VARCHAR(50), -- 操作人ID
operator_name VARCHAR(100), -- 操作人姓名
attachments VARCHAR(50)[], -- 附件ID数组
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
create_time timestamptz NOT NULL DEFAULT now(), -- 创建时间
PRIMARY KEY (log_id),
UNIQUE (optsn),
FOREIGN KEY (ticket_id) REFERENCES customer_service.tb_ticket(ticket_id)
);
CREATE INDEX idx_ticket_log_ticket ON customer_service.tb_ticket_log(ticket_id, create_time DESC);
COMMENT ON TABLE customer_service.tb_ticket_log IS '工单处理记录表';
-- FAQ表常见问题
DROP TABLE IF EXISTS customer_service.tb_faq CASCADE;
CREATE TABLE customer_service.tb_faq (
optsn VARCHAR(50) NOT NULL, -- 流水号
faq_id VARCHAR(50) NOT NULL, -- FAQ ID
kb_id VARCHAR(50), -- 关联知识库ID
category VARCHAR(100) NOT NULL, -- 分类
question TEXT NOT NULL, -- 问题
answer TEXT NOT NULL, -- 答案
similar_questions TEXT[], -- 相似问题数组
keywords TEXT[], -- 关键词数组
hit_count INTEGER DEFAULT 0, -- 命中次数
helpful_count INTEGER DEFAULT 0, -- 有帮助次数
unhelpful_count INTEGER DEFAULT 0, -- 无帮助次数
is_published BOOLEAN DEFAULT false, -- 是否发布
priority 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 (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;
COMMENT ON TABLE customer_service.tb_faq IS 'FAQ常见问题表';
-- 客服评价表
DROP TABLE IF EXISTS customer_service.tb_service_evaluation CASCADE;
CREATE TABLE customer_service.tb_service_evaluation (
optsn VARCHAR(50) NOT NULL, -- 流水号
evaluation_id VARCHAR(50) NOT NULL, -- 评价ID
customer_id VARCHAR(50) NOT NULL, -- 客户ID
conversation_id VARCHAR(50), -- 会话ID
ticket_id VARCHAR(50), -- 工单ID
evaluation_type VARCHAR(30) NOT NULL, -- 评价类型conversation-会话/ticket-工单/overall-整体服务
rating INTEGER NOT NULL, -- 评分1-5星
dimensions JSONB, -- 分维度评分JSON格式响应速度、专业性、态度等
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 (evaluation_id),
UNIQUE (optsn),
FOREIGN KEY (customer_id) REFERENCES customer_service.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;
COMMENT ON TABLE customer_service.tb_service_evaluation IS '客服评价表';
-- CRM集成配置表
DROP TABLE IF EXISTS customer_service.tb_crm_config CASCADE;
CREATE TABLE customer_service.tb_crm_config (
optsn VARCHAR(50) NOT NULL, -- 流水号
config_id VARCHAR(50) NOT NULL, -- 配置ID
crm_system VARCHAR(50) NOT NULL, -- CRM系统名称
api_endpoint VARCHAR(500) NOT NULL, -- API端点
api_key VARCHAR(500), -- API密钥加密存储
auth_type VARCHAR(30) DEFAULT 'api_key', -- 认证类型api_key/oauth2/basic_auth
sync_interval INTEGER DEFAULT 3600, -- 同步间隔(秒)
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, -- 最后同步时间
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 (config_id),
UNIQUE (optsn)
);
COMMENT ON TABLE customer_service.tb_crm_config IS 'CRM集成配置表';

View File

@@ -0,0 +1,42 @@
CREATE SCHEMA IF NOT EXISTS file;
DROP TABLE IF EXISTS file.tb_sys_file CASCADE;
CREATE TABLE file.tb_sys_file (
optsn VARCHAR(50) NOT NULL, -- 流水号
file_id VARCHAR(50) NOT NULL, -- 文件ID
name VARCHAR(255) NOT NULL, -- 文件名
path VARCHAR(255) NOT NULL, -- 文件路径
size BIGINT NOT NULL, -- 文件大小
type VARCHAR(50) NOT NULL, -- 文件类型
storage_type VARCHAR(50) NOT NULL, -- 存储类型
mime_type VARCHAR(255) NOT NULL, -- 文件MIME类型
url VARCHAR(255) NOT NULL, -- 文件URL
status VARCHAR(50) NOT NULL, -- 文件状态
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, -- 是否删除
PRIMARY KEY (file_id),
UNIQUE (optsn)
);
COMMENT ON TABLE file.tb_sys_file 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 '文件名';
COMMENT ON COLUMN file.tb_sys_file.path IS '文件路径';
COMMENT ON COLUMN file.tb_sys_file.size IS '文件大小';
COMMENT ON COLUMN file.tb_sys_file.type IS '文件类型';
COMMENT ON COLUMN file.tb_sys_file.storage_type IS '存储类型';
COMMENT ON COLUMN file.tb_sys_file.mime_type IS '文件MIME类型';
COMMENT ON COLUMN file.tb_sys_file.url IS '文件URL';
COMMENT ON COLUMN file.tb_sys_file.status IS '文件状态';
COMMENT ON COLUMN file.tb_sys_file.dept_path IS '当前部门路径';
COMMENT ON COLUMN file.tb_sys_file.creator IS '创建者';
COMMENT ON COLUMN file.tb_sys_file.updater IS '更新者';
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 '是否删除';

View File

@@ -0,0 +1,138 @@
-- =============================
-- 知识库管理模块
-- 支持:招投标知识库、客服知识库、企业内部知识库
-- =============================
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
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-内部
description TEXT, -- 知识库描述
storage_path VARCHAR(500), -- 存储路径
version VARCHAR(20) DEFAULT '1.0', -- 当前版本号
config JSONB DEFAULT NULL, -- 知识库配置JSON格式索引配置、检索参数等
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (kb_id),
UNIQUE (optsn)
);
CREATE INDEX idx_kb_type ON knowledge.tb_knowledge_base(kb_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.access_level IS '访问级别public-公开/private-私有/internal-内部';
-- 知识文档表
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
title VARCHAR(500) NOT NULL, -- 文档标题
doc_type VARCHAR(50) NOT NULL, -- 文档类型text-文本/pdf/word/excel/image/video
category VARCHAR(100), -- 文档分类(自动或手动分类)
content TEXT, -- 文档内容(文本类型)
content_summary TEXT, -- 内容摘要AI生成
file_id VARCHAR(50), -- 关联文件表ID
file_path VARCHAR(500), -- 文件路径
file_size BIGINT, -- 文件大小(字节)
mime_type VARCHAR(100), -- MIME类型
version VARCHAR(20) DEFAULT '1.0', -- 文档版本号
parent_doc_id VARCHAR(50), -- 父文档ID用于版本管理
tags TEXT[], -- 文档标签数组
keywords TEXT[], -- 关键词数组AI提取
embedding_status VARCHAR(20) DEFAULT 'pending', -- 向量化状态pending-待处理/processing-处理中/completed-完成/failed-失败
embedding_model VARCHAR(100), -- 使用的向量化模型
chunk_count INTEGER DEFAULT 0, -- 切片数量
metadata JSONB DEFAULT NULL, -- 文档元数据JSON格式
source_url VARCHAR(500), -- 来源URL
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (doc_id),
UNIQUE (optsn),
FOREIGN KEY (kb_id) REFERENCES knowledge.tb_knowledge_base(kb_id)
);
CREATE INDEX idx_doc_kb ON knowledge.tb_knowledge_document(kb_id) 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;
COMMENT ON TABLE knowledge.tb_knowledge_document IS '知识文档表';
COMMENT ON COLUMN knowledge.tb_knowledge_document.embedding_status IS '向量化状态pending/processing/completed/failed';
-- 知识文档片段表用于RAG检索
DROP TABLE IF EXISTS knowledge.tb_knowledge_chunk CASCADE;
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
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-图片
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, -- 更新时间
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)
);
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);
COMMENT ON TABLE knowledge.tb_knowledge_chunk IS '知识文档片段表RAG检索';
COMMENT ON COLUMN knowledge.tb_knowledge_chunk.embedding IS '向量嵌入需要pgvector扩展';
-- 知识访问日志表
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
doc_id VARCHAR(50), -- 文档ID
user_id VARCHAR(50) NOT NULL, -- 用户ID
access_type VARCHAR(20) NOT NULL, -- 访问类型view-查看/download-下载/search-搜索/edit-编辑
query_text TEXT, -- 搜索查询文本
result_count INTEGER, -- 搜索结果数量
ip_address VARCHAR(45), -- IP地址
user_agent TEXT, -- 用户代理
dept_path VARCHAR(255) DEFAULT NULL, -- 部门全路径
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);
COMMENT ON TABLE knowledge.tb_knowledge_access_log IS '知识访问日志表';

View File

@@ -0,0 +1,39 @@
CREATE SCHEMA IF NOT EXISTS log;
DROP TABLE IF EXISTS log.tb_sys_log CASCADE;
CREATE TABLE log.tb_sys_log (
optsn VARCHAR(50) NOT NULL, -- 流水号
log_id VARCHAR(50) NOT NULL, -- 日志ID
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), -- 操作系统
message VARCHAR(255) NOT NULL, -- 日志消息
data JSONB DEFAULT NULL, -- 日志数据
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, -- 是否删除
PRIMARY KEY (log_id),
UNIQUE (optsn)
);
COMMENT ON TABLE log.tb_sys_log IS '系统日志表';
COMMENT ON COLUMN log.tb_sys_log.optsn IS '流水号';
COMMENT ON COLUMN log.tb_sys_log.log_id IS '日志ID';
COMMENT ON COLUMN log.tb_sys_log.type IS '日志类型';
COMMENT ON COLUMN log.tb_sys_log.level IS '日志级别';
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.dept_path IS '部门全路径';
COMMENT ON COLUMN log.tb_sys_log.updater IS '更新者';
COMMENT ON COLUMN log.tb_sys_log.create_time IS '日志创建时间';
COMMENT ON COLUMN log.tb_sys_log.update_time IS '日志更新时间';
COMMENT ON COLUMN log.tb_sys_log.delete_time IS '日志删除时间';
COMMENT ON COLUMN log.tb_sys_log.deleted IS '是否删除';

View File

@@ -0,0 +1,161 @@
CREATE SCHEMA IF NOT EXISTS message;
DROP TABLE IF EXISTS message.tb_message CASCADE;
CREATE TABLE message.tb_message (
optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID
title VARCHAR(255) NOT NULL, -- 消息标题
content VARCHAR(255) NOT NULL, -- 消息内容
type VARCHAR(50) NOT NULL, -- 消息类型
status 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,
deleted BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY (message_id),
UNIQUE (optsn)
);
COMMENT ON TABLE message.tb_message IS '消息表';
COMMENT ON COLUMN message.tb_message.optsn IS '流水号';
COMMENT ON COLUMN message.tb_message.message_id IS '消息ID';
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.dept_path IS '部门全路径';
COMMENT ON COLUMN message.tb_message.creator IS '创建者';
COMMENT ON COLUMN message.tb_message.updater IS '更新者';
COMMENT ON COLUMN message.tb_message.create_time IS '创建时间';
COMMENT ON COLUMN message.tb_message.update_time IS '更新时间';
COMMENT ON COLUMN message.tb_message.delete_time IS '删除时间';
COMMENT ON COLUMN message.tb_message.deleted IS '是否删除';
-- 消息发送范围定义表(定义消息要发送给哪些对象,通过什么渠道)
DROP TABLE IF EXISTS message.tb_message_range CASCADE;
CREATE TABLE message.tb_message_range (
optsn VARCHAR(50) NOT NULL, -- 流水号
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等
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (optsn),
UNIQUE (message_id, target_type, target_id, channel)
);
COMMENT ON TABLE message.tb_message_range IS '消息发送范围定义表';
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.dept_path IS '部门全路径';
COMMENT ON COLUMN message.tb_message_range.creator IS '创建者';
COMMENT ON COLUMN message.tb_message_range.updater IS '更新者';
COMMENT ON COLUMN message.tb_message_range.create_time IS '创建时间';
COMMENT ON COLUMN message.tb_message_range.update_time IS '更新时间';
COMMENT ON COLUMN message.tb_message_range.delete_time IS '删除时间';
COMMENT ON COLUMN message.tb_message_range.deleted IS '是否删除';
-- 用户消息接收记录表(记录每个用户实际收到的消息及处理状态)
DROP TABLE IF EXISTS message.tb_message_receiver CASCADE;
CREATE TABLE message.tb_message_receiver (
optsn VARCHAR(50) NOT NULL, -- 流水号
message_id VARCHAR(50) NOT NULL, -- 消息ID
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, -- 处理时间
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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (optsn),
UNIQUE (message_id, user_id, channel)
);
-- 创建索引以提高查询效率
CREATE INDEX idx_message_user_user_status ON message.tb_message_receiver(user_id, status, create_time DESC) WHERE deleted = false;
CREATE INDEX idx_message_user_message ON message.tb_message_receiver(message_id) WHERE deleted = false;
COMMENT ON TABLE message.tb_message_receiver IS '用户消息接收记录表';
COMMENT ON COLUMN message.tb_message_receiver.optsn IS '流水号';
COMMENT ON COLUMN message.tb_message_receiver.message_id IS '消息ID';
COMMENT ON COLUMN message.tb_message_receiver.user_id IS '用户ID';
COMMENT ON COLUMN message.tb_message_receiver.channel IS '接收渠道app/sms/email/wechat等';
COMMENT ON COLUMN message.tb_message_receiver.status IS '消息状态unread-未读/read-已读/handled-已处理/deleted-已删除';
COMMENT ON COLUMN message.tb_message_receiver.read_time IS '阅读时间';
COMMENT ON COLUMN message.tb_message_receiver.handle_time IS '处理时间';
COMMENT ON COLUMN message.tb_message_receiver.dept_path IS '部门全路径';
COMMENT ON COLUMN message.tb_message_receiver.creator IS '创建者';
COMMENT ON COLUMN message.tb_message_receiver.updater IS '更新者';
COMMENT ON COLUMN message.tb_message_receiver.create_time IS '创建时间(接收时间)';
COMMENT ON COLUMN message.tb_message_receiver.update_time IS '更新时间';
COMMENT ON COLUMN message.tb_message_receiver.delete_time IS '删除时间';
COMMENT ON COLUMN message.tb_message_receiver.deleted IS '是否删除';
-- 消息渠道配置表(管理各种消息发送渠道的配置)
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_name VARCHAR(100) NOT NULL, -- 渠道名称
channel_desc VARCHAR(255) DEFAULT NULL, -- 渠道描述
config TEXT DEFAULT NULL, -- 渠道配置JSON格式如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, -- 删除时间
deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除
PRIMARY KEY (channel_id),
UNIQUE (optsn),
UNIQUE (channel_code)
);
COMMENT ON TABLE message.tb_message_channel IS '消息渠道配置表';
COMMENT ON COLUMN message.tb_message_channel.optsn IS '流水号';
COMMENT ON COLUMN message.tb_message_channel.channel_id IS '渠道ID';
COMMENT ON COLUMN message.tb_message_channel.channel_code IS '渠道编码app/sms/email/wechat/dingtalk等';
COMMENT ON COLUMN message.tb_message_channel.channel_name IS '渠道名称';
COMMENT ON COLUMN message.tb_message_channel.channel_desc IS '渠道描述';
COMMENT ON COLUMN message.tb_message_channel.config IS '渠道配置JSON格式';
COMMENT ON COLUMN message.tb_message_channel.status IS '渠道状态enabled-启用/disabled-禁用/maintenance-维护中';
COMMENT ON COLUMN message.tb_message_channel.priority IS '优先级(数字越大优先级越高)';
COMMENT ON COLUMN message.tb_message_channel.dept_path IS '部门全路径';
COMMENT ON COLUMN message.tb_message_channel.creator IS '创建者';
COMMENT ON COLUMN message.tb_message_channel.updater IS '更新者';
COMMENT ON COLUMN message.tb_message_channel.create_time IS '创建时间';
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);

View File

@@ -0,0 +1,461 @@
CREATE SCHEMA IF NOT EXISTS sys;
-- 通用更新时间触发函数(用于模拟 MySQL 的 ON UPDATE CURRENT_TIMESTAMP
-- CREATE OR REPLACE FUNCTION sys.set_update_time()
-- RETURNS trigger AS $$
-- BEGIN
-- NEW.update_time := CURRENT_TIMESTAMP;
-- RETURN NEW;
-- END;
-- $$ LANGUAGE plpgsql;
-- 部门表
DROP TABLE IF EXISTS sys.tb_sys_dept CASCADE;
CREATE TABLE sys.tb_sys_dept (
optsn VARCHAR(50) NOT NULL, -- 流水号
dept_id VARCHAR(50) NOT NULL, -- 部门ID
name VARCHAR(100) NOT NULL, -- 部门名称
parent_id VARCHAR(50) DEFAULT NULL, -- 父部门ID
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, -- 是否删除
PRIMARY KEY (dept_id),
UNIQUE (optsn)
);
-- 创建索引
CREATE INDEX idx_sys_dept_parent ON sys.tb_sys_dept USING btree (parent_id);
COMMENT ON TABLE sys.tb_sys_dept IS '部门表';
COMMENT ON COLUMN sys.tb_sys_dept.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_dept.dept_id IS '部门ID';
COMMENT ON COLUMN sys.tb_sys_dept.name IS '部门名称';
COMMENT ON COLUMN sys.tb_sys_dept.parent_id IS '父部门ID';
COMMENT ON COLUMN sys.tb_sys_dept.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_dept.description IS '部门描述';
COMMENT ON COLUMN sys.tb_sys_dept.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_dept.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_dept.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_dept.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_dept.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_dept.deleted IS '是否删除';
-- 角色表
DROP TABLE IF EXISTS sys.tb_sys_role CASCADE;
CREATE TABLE sys.tb_sys_role (
optsn VARCHAR(50) NOT NULL, -- 流水号
role_id VARCHAR(50) NOT NULL, -- 角色ID
name VARCHAR(100) NOT NULL,
description VARCHAR(200) DEFAULT NULL, -- 角色名称
scope VARCHAR(20) NOT NULL DEFAULT 'dept', -- 角色作用域global/dept
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, -- 部门全路径
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 (role_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_role IS '角色表';
COMMENT ON COLUMN sys.tb_sys_role.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_role.role_id IS '角色ID';
COMMENT ON COLUMN sys.tb_sys_role.name IS '角色名称';
COMMENT ON COLUMN sys.tb_sys_role.description IS '角色名称';
COMMENT ON COLUMN sys.tb_sys_role.scope IS '角色作用域global=通用dept=部门私有';
COMMENT ON COLUMN sys.tb_sys_role.owner_dept_id IS '部门私有角色的所属部门IDscope=dept 时必填)';
COMMENT ON COLUMN sys.tb_sys_role.status IS '角色状态';
COMMENT ON COLUMN sys.tb_sys_role.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_role.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_role.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_role.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_role.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_role.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_role.deleted IS '是否删除';
-- 唯一性:
-- 全局角色name 在未删除且 scope=global 下唯一
-- 部门私有角色:同一部门下 name 唯一scope=dept
CREATE UNIQUE INDEX IF NOT EXISTS uq_sys_role_global_name
ON sys.tb_sys_role USING btree (name)
WHERE deleted = false AND scope = 'global';
CREATE UNIQUE INDEX IF NOT EXISTS uq_sys_role_dept_name
ON sys.tb_sys_role USING btree (owner_dept_id, name)
WHERE deleted = false AND scope = 'dept';
CREATE INDEX IF NOT EXISTS idx_sys_role_owner_dept ON sys.tb_sys_role USING btree (owner_dept_id) WHERE deleted = false;
-- 部门角色关联表
DROP TABLE IF EXISTS sys.tb_sys_dept_role CASCADE;
CREATE TABLE sys.tb_sys_dept_role (
optsn VARCHAR(50) NOT NULL, -- 流水号
dept_id VARCHAR(50) NOT NULL, -- 部门ID
role_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, -- 是否删除
PRIMARY KEY (dept_id, role_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_dept_role IS '部门角色关联表';
COMMENT ON COLUMN sys.tb_sys_dept_role.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_dept_role.dept_id IS '部门ID';
COMMENT ON COLUMN sys.tb_sys_dept_role.role_id IS '角色ID';
COMMENT ON COLUMN sys.tb_sys_dept_role.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_dept_role.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_dept_role.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_dept_role.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_dept_role.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_dept_role.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_dept_role.deleted IS '是否删除';
-- 用户角色关联表
DROP TABLE IF EXISTS sys.tb_sys_user_role CASCADE;
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_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 (user_id, role_id),
UNIQUE (optsn)
);
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_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_user_role.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_user_role.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_user_role.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_user_role.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_user_role.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_user_role.deleted IS '是否删除';
-- 视图表
DROP TABLE IF EXISTS sys.tb_sys_view CASCADE;
CREATE TABLE sys.tb_sys_view (
optsn VARCHAR(50) NOT NULL, -- 流水号
view_id VARCHAR(50) NOT NULL, -- 视图ID
name VARCHAR(100) NOT NULL, -- 视图名称
parent_id VARCHAR(50) DEFAULT NULL, -- 父视图ID
url VARCHAR(255) DEFAULT NULL, -- 视图URL
component VARCHAR(255) DEFAULT NULL, -- 视图组件
icon VARCHAR(100) DEFAULT NULL, -- 视图图标
type integer DEFAULT 0, -- 视图类型
layout VARCHAR(100) DEFAULT NULL, -- 布局组件路径名称
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, -- 是否删除
PRIMARY KEY (view_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_view IS '视图表';
COMMENT ON COLUMN sys.tb_sys_view.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_view.view_id IS '视图ID';
COMMENT ON COLUMN sys.tb_sys_view.name IS '视图名称';
COMMENT ON COLUMN sys.tb_sys_view.parent_id IS '父视图ID';
COMMENT ON COLUMN sys.tb_sys_view.url IS '视图URL';
COMMENT ON COLUMN sys.tb_sys_view.component IS '视图组件';
COMMENT ON COLUMN sys.tb_sys_view.icon IS '视图图标';
COMMENT ON COLUMN sys.tb_sys_view.type IS '视图类型';
COMMENT ON COLUMN sys.tb_sys_view.layout IS '布局组件路径名称';
COMMENT ON COLUMN sys.tb_sys_view.order_num IS '视图排序号';
COMMENT ON COLUMN sys.tb_sys_view.description IS '视图描述';
COMMENT ON COLUMN sys.tb_sys_view.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_view.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_view.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_view.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_view.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_view.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_view.deleted IS '是否删除';
-- 模块表
DROP TABLE IF EXISTS sys.tb_sys_module CASCADE;
CREATE TABLE sys.tb_sys_module (
optsn VARCHAR(50) NOT NULL, -- 流水号
module_id VARCHAR(50) NOT NULL, -- 模块ID
name VARCHAR(100) NOT NULL, -- 模块名称
description VARCHAR(255) DEFAULT NULL, -- 模块描述
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, -- 是否删除
PRIMARY KEY (module_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_module IS '模块表';
COMMENT ON COLUMN sys.tb_sys_module.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_module.module_id IS '模块ID';
COMMENT ON COLUMN sys.tb_sys_module.name IS '模块名称';
COMMENT ON COLUMN sys.tb_sys_module.description IS '模块描述';
COMMENT ON COLUMN sys.tb_sys_module.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_module.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_module.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_module.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_module.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_module.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_module.deleted IS '是否删除';
-- 权限表
DROP TABLE IF EXISTS sys.tb_sys_permission CASCADE;
CREATE TABLE sys.tb_sys_permission (
optsn VARCHAR(50) NOT NULL, -- 流水号
permission_id VARCHAR(50) NOT NULL, -- 权限ID
name VARCHAR(100) NOT NULL, -- 权限名称
code VARCHAR(100) NOT NULL, -- 权限代码
description VARCHAR(255) DEFAULT NULL, -- 权限描述
module_id VARCHAR(50) DEFAULT NULL, -- 所属模块ID
creator VARCHAR(50) DEFAULT NULL, -- 创建者
dept_path VARCHAR(255) DEFAULT NULL,
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, -- 是否删除
PRIMARY KEY (permission_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_permission IS '权限表';
COMMENT ON COLUMN sys.tb_sys_permission.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_permission.permission_id IS '权限ID';
COMMENT ON COLUMN sys.tb_sys_permission.name IS '权限名称';
COMMENT ON COLUMN sys.tb_sys_permission.code IS '权限代码';
COMMENT ON COLUMN sys.tb_sys_permission.description IS '权限描述' ;
COMMENT ON COLUMN sys.tb_sys_permission.module_id IS '所属模块ID';
COMMENT ON COLUMN sys.tb_sys_permission.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_permission.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_permission.status IS '角色状态';
COMMENT ON COLUMN sys.tb_sys_permission.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_permission.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_permission.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_permission.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_permission.deleted IS '是否删除';
-- 角色权限
DROP TABLE IF EXISTS sys.tb_sys_role_permission CASCADE;
CREATE TABLE sys.tb_sys_role_permission (
optsn VARCHAR(50) NOT NULL, -- 流水号
role_id VARCHAR(50) NOT NULL, -- 角色ID
permission_id VARCHAR(50) NOT NULL, -- 权限ID
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, -- 是否删除
PRIMARY KEY (role_id, permission_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_role_permission IS '角色权限表';
COMMENT ON COLUMN sys.tb_sys_role_permission.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_role_permission.role_id IS '角色ID';
COMMENT ON COLUMN sys.tb_sys_role_permission.permission_id IS '权限ID';
COMMENT ON COLUMN sys.tb_sys_role_permission.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_role_permission.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_role_permission.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_role_permission.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_role_permission.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_role_permission.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_role_permission.deleted IS '是否删除';
-- 视图权限
DROP TABLE IF EXISTS sys.tb_sys_view_permission CASCADE;
CREATE TABLE sys.tb_sys_view_permission (
optsn VARCHAR(50) NOT NULL, -- 流水号
view_id VARCHAR(50) NOT NULL, -- 视图ID
permission_id VARCHAR(50) NOT NULL, -- 权限ID
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, -- 是否删除
PRIMARY KEY (view_id, permission_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_view_permission IS '视图权限表';
COMMENT ON COLUMN sys.tb_sys_view_permission.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_view_permission.view_id IS '视图ID';
COMMENT ON COLUMN sys.tb_sys_view_permission.permission_id IS '权限ID';
COMMENT ON COLUMN sys.tb_sys_view_permission.creator IS '创建者';
COMMENT ON COLUMN sys.tb_sys_view_permission.dept_path IS '部门全路径';
COMMENT ON COLUMN sys.tb_sys_view_permission.updater IS '更新者';
COMMENT ON COLUMN sys.tb_sys_view_permission.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_view_permission.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_view_permission.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_view_permission.deleted IS '是否删除';
-- 为所有表创建更新时间触发器
-- DROP TRIGGER IF EXISTS trg_tb_sys_dept_update_time ON sys.tb_sys_dept;
-- CREATE TRIGGER trg_tb_sys_dept_update_time
-- BEFORE UPDATE ON sys.tb_sys_dept
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_role_update_time ON sys.tb_sys_role;
-- CREATE TRIGGER trg_tb_sys_role_update_time
-- BEFORE UPDATE ON sys.tb_sys_role
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_dept_role_update_time ON sys.tb_sys_dept_role;
-- CREATE TRIGGER trg_tb_sys_dept_role_update_time
-- BEFORE UPDATE ON sys.tb_sys_dept_role
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_user_role_update_time ON sys.tb_sys_user_role;
-- CREATE TRIGGER trg_tb_sys_user_role_update_time
-- BEFORE UPDATE ON sys.tb_sys_user_role
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_view_update_time ON sys.tb_sys_view;
-- CREATE TRIGGER trg_tb_sys_view_update_time
-- BEFORE UPDATE ON sys.tb_sys_view
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_module_update_time ON sys.tb_sys_module;
-- CREATE TRIGGER trg_tb_sys_module_update_time
-- BEFORE UPDATE ON sys.tb_sys_module
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_permission_update_time ON sys.tb_sys_permission;
-- CREATE TRIGGER trg_tb_sys_permission_update_time
-- BEFORE UPDATE ON sys.tb_sys_permission
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_role_permission_update_time ON sys.tb_sys_role_permission;
-- CREATE TRIGGER trg_tb_sys_role_permission_update_time
-- BEFORE UPDATE ON sys.tb_sys_role_permission
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- DROP TRIGGER IF EXISTS trg_tb_sys_view_permission_update_time ON sys.tb_sys_view_permission;
-- CREATE TRIGGER trg_tb_sys_view_permission_update_time
-- BEFORE UPDATE ON sys.tb_sys_view_permission
-- FOR EACH ROW
-- EXECUTE FUNCTION sys.set_update_time();
-- =============================
-- 通用对象级权限ACL
-- 支持对象类型:任意(如 article/file/course/...
-- 支持主体user/dept/role
-- 权限位1=读(read)2=写(write)4=执行(exec),可相加
-- include_descendants当主体为 dept/role 时,是否包含其子级(便于“所有子级可查看”场景)
-- allowtrue=允许false=显式拒绝(拒绝优先生效)
-- dept_path用于数据范围隔离与现有规则一致
-- =============================
DROP TABLE IF EXISTS sys.tb_sys_acl CASCADE;
CREATE TABLE sys.tb_sys_acl (
optsn VARCHAR(50) NOT NULL, -- 流水号
acl_id VARCHAR(50) NOT NULL, -- ACL主键
object_type VARCHAR(50) NOT NULL, -- 对象类型article/file/course/...
object_id VARCHAR(50) NOT NULL, -- 对象ID
principal_type VARCHAR(20) NOT NULL, -- 主体类型user/dept/role
principal_id VARCHAR(50) NOT NULL, -- 主体ID
principal_dept_id VARCHAR(50) DEFAULT NULL, -- 当主体为role且限定到某部门时的部门ID支持“某部门的某角色”
permission SMALLINT NOT NULL, -- 权限位1读 2写 4执行
allow BOOLEAN NOT NULL DEFAULT true, -- 允许或显式拒绝
include_descendants BOOLEAN NOT NULL DEFAULT false, -- 是否包含子级对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, -- 是否删除
PRIMARY KEY (acl_id),
UNIQUE (object_type, object_id, principal_type, principal_id, principal_dept_id, deleted),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_acl IS '通用对象级权限表ACL';
COMMENT ON COLUMN sys.tb_sys_acl.object_type IS '对象类型article/file/course/...';
COMMENT ON COLUMN sys.tb_sys_acl.object_id IS '对象ID';
COMMENT ON COLUMN sys.tb_sys_acl.principal_type IS '主体类型user/dept/role';
COMMENT ON COLUMN sys.tb_sys_acl.principal_id IS '主体ID';
COMMENT ON COLUMN sys.tb_sys_acl.principal_dept_id IS '当主体为角色时可选的限定部门ID某部门的某角色';
COMMENT ON COLUMN sys.tb_sys_acl.permission IS '权限位1读 2写 4执行可相加';
COMMENT ON COLUMN sys.tb_sys_acl.allow IS '是否允许false=显式拒绝)';
COMMENT ON COLUMN sys.tb_sys_acl.include_descendants IS '是否包含子级dept/role时启用';
COMMENT ON COLUMN sys.tb_sys_acl.dept_path IS '部门全路径(用于数据范围隔离)';
CREATE INDEX idx_sys_acl_object ON sys.tb_sys_acl USING btree (object_type, object_id) WHERE deleted = false;
CREATE INDEX idx_sys_acl_principal ON sys.tb_sys_acl USING btree (principal_type, principal_id) WHERE deleted = false;
CREATE INDEX idx_sys_acl_dept_path ON sys.tb_sys_acl USING btree (dept_path) WHERE deleted = false;
-- 针对“某部门的某角色”的检索优化
CREATE INDEX idx_sys_acl_role_scoped ON sys.tb_sys_acl USING btree (principal_id, principal_dept_id)
WHERE deleted = false AND principal_type = 'role';
-- =============================
-- ACL 策略表:定义对象类型的层级可见/可编辑规则
-- 例如:
-- - 同级与父级管理员可修改edit_hierarchy_rule = 'parent_or_same_admin'
-- - 子级全部可查看view_hierarchy_rule = 'children_all'
-- - 课程:下级只有指定部门/角色可查看view_hierarchy_rule = 'children_specified'
-- 说明:业务侧需结合“管理员”的判定(通常由角色判定)在应用层实现;本表做规则声明
-- =============================
DROP TABLE IF EXISTS sys.tb_sys_acl_policy CASCADE;
CREATE TABLE sys.tb_sys_acl_policy (
optsn VARCHAR(50) NOT NULL, -- 流水号
policy_id VARCHAR(50) NOT NULL, -- 策略ID
name VARCHAR(255) NOT NULL, -- 策略名称
object_type VARCHAR(50) NOT NULL, -- 目标对象类型
edit_hierarchy_rule VARCHAR(50) DEFAULT NULL, -- 编辑层级规则parent_only/parent_or_same_admin/owner_only/none
view_hierarchy_rule VARCHAR(50) DEFAULT NULL, -- 查看层级规则children_all/children_specified/none
default_permission SMALLINT DEFAULT 0, -- 默认权限位无显式ACL时应用
default_allow BOOLEAN DEFAULT true, -- 默认是否允许
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,
PRIMARY KEY (policy_id),
UNIQUE (object_type, deleted),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_acl_policy IS 'ACL对象类型策略表层级可见/可编辑规则)';
COMMENT ON COLUMN sys.tb_sys_acl_policy.object_type IS '对象类型article/file/course/...';
COMMENT ON COLUMN sys.tb_sys_acl_policy.edit_hierarchy_rule IS '编辑层级规则parent_only/parent_or_same_admin/owner_only/none';
COMMENT ON COLUMN sys.tb_sys_acl_policy.view_hierarchy_rule IS '查看层级规则children_all/children_specified/none';
COMMENT ON COLUMN sys.tb_sys_acl_policy.default_permission IS '默认权限位无显式ACL时兜底';
COMMENT ON COLUMN sys.tb_sys_acl_policy.apply_to_children IS '默认是否应用到子级';
CREATE INDEX idx_sys_acl_policy_object ON sys.tb_sys_acl_policy USING btree (object_type) WHERE deleted = false;

View File

@@ -0,0 +1,120 @@
-- 创建 sys schema如果不存在
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, -- 状态
PRIMARY KEY (user_id),
UNIQUE (optsn),
UNIQUE (email),
UNIQUE (phone),
UNIQUE (wechat_id)
);
CREATE INDEX idx_tb_sys_user_phone ON sys.tb_sys_user USING btree (phone);
-- 按 email 域名建立表达式索引(对域名小写处理以实现不区分大小写的域名查询)
-- 使用 split_part(email, '@', 2) 提取 @ 之后的域名部分,再做 lower() 归一化
-- WHERE email IS NOT NULL 可以避免索引包含大量 NULL
CREATE INDEX idx_tb_sys_user_email_domain ON sys.tb_sys_user USING btree (lower(split_part(email, '@', 2)))
WHERE email IS NOT NULL;
CREATE INDEX idx_tb_sys_user_wechat_id ON sys.tb_sys_user USING btree (wechat_id);
-- 可选:保留列注释(如果你想把 MySQL 的 COMMENT 同步到 Postgres
COMMENT ON TABLE sys.tb_sys_user IS '用户表';
COMMENT ON COLUMN sys.tb_sys_user.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_user.user_id IS '用户ID';
COMMENT ON COLUMN sys.tb_sys_user.password IS '密码(建议存储 bcrypt/argon2 哈希)';
COMMENT ON COLUMN sys.tb_sys_user.email IS '电子邮件';
COMMENT ON COLUMN sys.tb_sys_user.phone IS '电话号码';
COMMENT ON COLUMN sys.tb_sys_user.wechat_id IS '微信ID';
COMMENT ON COLUMN sys.tb_sys_user.create_time IS '创建时间';
COMMENT ON COLUMN sys.tb_sys_user.update_time IS '更新时间';
COMMENT ON COLUMN sys.tb_sys_user.delete_time IS '删除时间';
COMMENT ON COLUMN sys.tb_sys_user.deleted IS '是否删除';
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, -- 是否删除
PRIMARY KEY (user_id),
UNIQUE (optsn)
);
COMMENT ON TABLE sys.tb_sys_user_info IS '用户信息表';
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.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.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 '删除时间';
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(), -- 创建时间
PRIMARY KEY (optsn)
);
-- B-tree 索引(显式指定 USING btreePostgres 默认即为 btree
CREATE INDEX idx_tb_sys_login_log_user_id ON sys.tb_sys_login_log USING btree (user_id);
CREATE INDEX idx_tb_sys_login_log_login_time ON sys.tb_sys_login_log USING btree (login_time);
-- 可选:保留列注释
COMMENT ON TABLE sys.tb_sys_login_log IS '登录日志表';
COMMENT ON COLUMN sys.tb_sys_login_log.optsn IS '流水号';
COMMENT ON COLUMN sys.tb_sys_login_log.user_id IS '用户ID';
COMMENT ON COLUMN sys.tb_sys_login_log.username IS '用户名';
COMMENT ON COLUMN sys.tb_sys_login_log.ip_address IS 'IP地址';
COMMENT ON COLUMN sys.tb_sys_login_log.ip_source IS 'IP来源';
COMMENT ON COLUMN sys.tb_sys_login_log.browser IS '浏览器';
COMMENT ON COLUMN sys.tb_sys_login_log.os IS '操作系统';
COMMENT ON COLUMN sys.tb_sys_login_log.password IS '密码(建议存储 bcrypt/argon2 哈希)';
COMMENT ON COLUMN sys.tb_sys_login_log.login_time IS '登录时间';
COMMENT ON COLUMN sys.tb_sys_login_log.status IS '登录状态0失败 1成功';
COMMENT ON COLUMN sys.tb_sys_login_log.error_count IS '错误次数';
COMMENT ON COLUMN sys.tb_sys_login_log.message IS '登录消息';
COMMENT ON COLUMN sys.tb_sys_login_log.create_time IS '创建时间';

View File

@@ -0,0 +1,11 @@
-- 按顺序执行初始化
\i createDB.sql -- 创建数据库和基础扩展
\i createTableUser.sql -- 用户表相关(核心表)
\i createTablePermission.sql -- 权限相关(核心表)
\i createTableFile.sql -- 文件管理
\i createTableMessage.sql -- 消息管理
\i createTableConfig.sql -- 配置管理
\i createTableLog.sql -- 日志管理
-- 初始化基础数据(如果有)
-- \i initBaseData.sql -- 取消注释如果需要初始化基础数据

View File

@@ -0,0 +1,43 @@
-- 初始化系统常用配置(与 config.tb_sys_config 对应)
-- 仅插入常用示例,可按需调整 value/remark
INSERT INTO config.tb_sys_config (
optsn, config_id, key, value, type, description, "group", "order", 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-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-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-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),
-- 通知(邮件/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-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-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);

View File

@@ -0,0 +1,549 @@
-- =============================
-- 数据库优化补丁脚本
-- 基于现有表结构的增强和修改
-- =============================
-- =============================
-- 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 $$;