311 lines
16 KiB
SQL
311 lines
16 KiB
SQL
-- ============================================================
|
||
-- 智能客服系统 - 完整数据库迁移
|
||
-- 数据库:MySQL 5.7+
|
||
-- 作者:OpenClaw Team
|
||
-- 日期:2026-03-01
|
||
-- ============================================================
|
||
|
||
-- 创建数据库
|
||
CREATE DATABASE IF NOT EXISTS `openclaw`
|
||
CHARACTER SET utf8mb4
|
||
COLLATE utf8mb4_unicode_ci;
|
||
|
||
USE `openclaw`;
|
||
|
||
-- ============================================================
|
||
-- 租户管理表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `tenants` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`name` VARCHAR(200) NOT NULL COMMENT '租户名称',
|
||
`slug` VARCHAR(100) UNIQUE NOT NULL COMMENT '租户唯一标识',
|
||
`email` VARCHAR(255) NOT NULL COMMENT '管理员邮箱',
|
||
`phone` VARCHAR(50) DEFAULT NULL COMMENT '联系电话',
|
||
`logo` VARCHAR(500) DEFAULT NULL COMMENT 'Logo URL',
|
||
`website` VARCHAR(500) DEFAULT NULL COMMENT '官方网站',
|
||
`description` TEXT DEFAULT NULL COMMENT '租户描述',
|
||
`status` ENUM('pending', 'active', 'suspended', 'archived') DEFAULT 'pending',
|
||
`plan` ENUM('free', 'basic', 'pro', 'enterprise') DEFAULT 'free',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
UNIQUE KEY `uk_slug` (`slug`),
|
||
KEY `idx_status` (`status`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='租户表';
|
||
|
||
-- ============================================================
|
||
-- 用户表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `users` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '所属租户 ID',
|
||
`username` VARCHAR(100) NOT NULL COMMENT '用户名',
|
||
`email` VARCHAR(255) NOT NULL COMMENT '邮箱',
|
||
`password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
|
||
`full_name` VARCHAR(100) DEFAULT NULL COMMENT '全名',
|
||
`avatar` VARCHAR(500) DEFAULT NULL COMMENT '头像 URL',
|
||
`phone` VARCHAR(50) DEFAULT NULL COMMENT '手机号',
|
||
`role` ENUM('owner', 'admin', 'member', 'guest') DEFAULT 'member',
|
||
`status` ENUM('active', 'inactive', 'suspended', 'deleted') DEFAULT 'active',
|
||
`last_login_at` TIMESTAMP DEFAULT NULL,
|
||
`last_login_ip` VARCHAR(50) DEFAULT NULL COMMENT '最后登录 IP',
|
||
`remember_token` VARCHAR(100) DEFAULT NULL COMMENT '长期登录 Token',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
UNIQUE KEY `uk_username` (`username`),
|
||
UNIQUE KEY `uk_email` (`email`),
|
||
KEY `idx_tenant_status` (`tenant_id`, `status`) USING BTREE,
|
||
CONSTRAINT `fk_users_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
|
||
|
||
-- ============================================================
|
||
-- 角色表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `roles` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`tenant_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '租户 ID(NULL 为全局角色)',
|
||
`name` VARCHAR(100) NOT NULL COMMENT '角色名称',
|
||
`code` VARCHAR(100) NOT NULL COMMENT '角色代码',
|
||
`description` TEXT DEFAULT NULL COMMENT '角色描述',
|
||
`is_global` BOOLEAN DEFAULT FALSE COMMENT '是否为全局角色',
|
||
`is_system` BOOLEAN DEFAULT FALSE COMMENT '是否为系统内置角色',
|
||
`status` ENUM('active', 'inactive', 'archived') DEFAULT 'active',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
UNIQUE KEY `uk_code` (`code`),
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
CONSTRAINT `fk_roles_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表';
|
||
|
||
-- 初始化系统内置角色
|
||
INSERT INTO `roles` (`name`, `code`, `description`, `is_global`, `is_system`, `status`) VALUES
|
||
('系统管理员', 'system_admin', '拥有系统全部权限', TRUE, TRUE, 'active'),
|
||
('超级管理员', 'super_admin', '租户超级管理员', FALSE, TRUE, 'active'),
|
||
('普通用户', 'user', '普通用户角色', FALSE, TRUE, 'active'),
|
||
('访客', 'guest', '访客角色(只读)', FALSE, TRUE, 'active');
|
||
|
||
-- ============================================================
|
||
-- 资源/权限表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `resources` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`tenant_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '租户 ID',
|
||
`parent_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '父资源 ID',
|
||
`name` VARCHAR(200) NOT NULL COMMENT '资源名称',
|
||
`code` VARCHAR(200) NOT NULL COMMENT '资源代码(唯一)',
|
||
`type` ENUM('api', 'page', 'button', 'data') NOT NULL COMMENT '资源类型',
|
||
`group` VARCHAR(100) DEFAULT NULL COMMENT '资源分组',
|
||
`path` VARCHAR(500) DEFAULT NULL COMMENT 'API/页面路径',
|
||
`method` VARCHAR(10) DEFAULT NULL COMMENT 'API 请求方法',
|
||
`description` TEXT DEFAULT NULL COMMENT '资源描述',
|
||
`icon` VARCHAR(100) DEFAULT NULL COMMENT '图标',
|
||
`sort_order` INT DEFAULT 0 COMMENT '排序',
|
||
`level` INT DEFAULT 0 COMMENT '层级深度',
|
||
`lft` INT DEFAULT NULL COMMENT '左值(用于树查询)',
|
||
`rgt` INT DEFAULT NULL COMMENT '右值(用于树查询)',
|
||
`is_system` BOOLEAN DEFAULT FALSE COMMENT '是否为系统资源',
|
||
`status` ENUM('active', 'inactive', 'archived') DEFAULT 'active',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
UNIQUE KEY `uk_code` (`code`),
|
||
KEY `idx_tenant_parent` (`tenant_id`, `parent_id`),
|
||
KEY `idx_group` (`group`),
|
||
KEY `idx_type` (`type`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源/权限表';
|
||
|
||
-- 初始化系统资源(示例)
|
||
INSERT INTO `resources` (`name`, `code`, `type`, `group`, `path`, `method`, `description`, `is_system`, `status`) VALUES
|
||
('租户管理', 'tenant:manage', 'api', 'tenant', '/api/v1/tenants', '', '租户列表查询', TRUE, 'active'),
|
||
('租户创建', 'tenant:create', 'api', 'tenant', '/api/v1/tenants', 'POST', '创建租户', TRUE, 'active'),
|
||
('租户更新', 'tenant:update', 'api', 'tenant', '/api/v1/tenants/*', 'PUT', '更新租户', TRUE, 'active'),
|
||
('租户删除', 'tenant:delete', 'api', 'tenant', '/api/v1/tenants/*', 'DELETE', '删除租户', TRUE, 'active'),
|
||
('用户管理', 'user:manage', 'api', 'user', '/api/v1/users', '', '用户列表查询', TRUE, 'active'),
|
||
('用户创建', 'user:create', 'api', 'user', '/api/v1/users', 'POST', '创建用户', TRUE, 'active'),
|
||
('角色管理', 'role:manage', 'api', 'role', '/api/v1/roles', '', '角色管理', TRUE, 'active'),
|
||
('资源管理', 'resource:manage', 'api', 'resource', '/api/v1/resources', '', '资源管理', TRUE, 'active'),
|
||
('工单管理', 'ticket:manage', 'api', 'ticket', '/api/v1/tickets', '', '工单管理', TRUE, 'active'),
|
||
('会话管理', 'conversation:manage', 'api', 'conversation', '/api/v1/conversations', '', '会话管理', TRUE, 'active'),
|
||
('知识库管理', 'knowledge:manage', 'api', 'knowledge', '/api/v1/knowledge', '', '知识库管理', TRUE, 'active');
|
||
|
||
-- ============================================================
|
||
-- 角色资源关联表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `role_resources` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`role_id` BIGINT UNSIGNED NOT NULL,
|
||
`resource_id` BIGINT UNSIGNED NOT NULL,
|
||
`actions` VARCHAR(255) DEFAULT NULL COMMENT '允许的操作 (JSON)',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
UNIQUE KEY `uk_role_resource` (`role_id`, `resource_id`),
|
||
KEY `idx_resource` (`resource_id`),
|
||
CONSTRAINT `fk_role_resources_role` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE,
|
||
CONSTRAINT `fk_role_resources_resource` FOREIGN KEY (`resource_id`) REFERENCES `resources`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色资源关联表';
|
||
|
||
-- ============================================================
|
||
-- 用户角色关联表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `user_roles` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||
`role_id` BIGINT UNSIGNED NOT NULL,
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
UNIQUE KEY `uk_user_role` (`user_id`, `role_id`),
|
||
KEY `idx_role` (`role_id`),
|
||
CONSTRAINT `fk_user_roles_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
|
||
CONSTRAINT `fk_user_roles_role` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色关联表';
|
||
|
||
-- ============================================================
|
||
-- 会话表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `conversations` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
`user_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '用户 ID',
|
||
`title` VARCHAR(500) DEFAULT NULL COMMENT '会话标题',
|
||
`topic` VARCHAR(200) DEFAULT NULL COMMENT '会话主题',
|
||
`status` ENUM('active', 'closed', 'archived') DEFAULT 'active',
|
||
`metadata` JSON DEFAULT NULL COMMENT '元数据',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
KEY `idx_user` (`user_id`),
|
||
CONSTRAINT `fk_conversations_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会话表';
|
||
|
||
-- ============================================================
|
||
-- 消息表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `messages` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`conversation_id` BIGINT UNSIGNED NOT NULL COMMENT '会话 ID',
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
`user_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '用户 ID',
|
||
`role` ENUM('user', 'assistant', 'system') NOT NULL COMMENT '消息角色',
|
||
`content` TEXT NOT NULL COMMENT '消息内容',
|
||
`content_type` ENUM('text', 'image', 'file') DEFAULT 'text',
|
||
`content_url` VARCHAR(1000) DEFAULT NULL COMMENT '内容 URL',
|
||
`metadata` JSON DEFAULT NULL COMMENT '消息元数据',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
|
||
KEY `idx_conversation` (`conversation_id`),
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
CONSTRAINT `fk_messages_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `conversations`(`id`) ON DELETE CASCADE,
|
||
CONSTRAINT `fk_messages_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='消息表';
|
||
|
||
-- ============================================================
|
||
-- 工单表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `tickets` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`ticket_number` VARCHAR(50) UNIQUE NOT NULL COMMENT '工单编号',
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
`user_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '用户 ID',
|
||
`title` VARCHAR(500) NOT NULL COMMENT '工单标题',
|
||
`description` TEXT NOT NULL COMMENT '工单描述',
|
||
`category` VARCHAR(100) DEFAULT NULL COMMENT '工单分类',
|
||
`priority` ENUM('low', 'medium', 'high', 'urgent') DEFAULT 'medium',
|
||
`status` ENUM('open', 'pending', 'in_progress', 'resolved', 'closed') DEFAULT 'open',
|
||
`assigned_to` BIGINT UNSIGNED DEFAULT NULL COMMENT '指配给',
|
||
`due_date` DATETIME DEFAULT NULL COMMENT '截止日期',
|
||
`resolution` TEXT DEFAULT NULL COMMENT '解决方案',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
KEY `idx_status` (`status`),
|
||
KEY `idx_assigned` (`assigned_to`),
|
||
CONSTRAINT `fk_tickets_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工单表';
|
||
|
||
-- ============================================================
|
||
-- 知识库分类表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `knowledge_bases` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
`name` VARCHAR(200) NOT NULL COMMENT '知识库名称',
|
||
`slug` VARCHAR(100) NOT NULL COMMENT '知识库唯一标识',
|
||
`description` TEXT DEFAULT NULL COMMENT '知识库描述',
|
||
`icon` VARCHAR(100) DEFAULT NULL COMMENT '图标',
|
||
`sort_order` INT DEFAULT 0 COMMENT '排序',
|
||
`status` ENUM('draft', 'published', 'archived') DEFAULT 'draft',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
UNIQUE KEY `uk_slug` (`slug`),
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
CONSTRAINT `fk_kb_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='知识库分类';
|
||
|
||
-- ============================================================
|
||
-- 知识库项表
|
||
-- ============================================================
|
||
CREATE TABLE IF NOT EXISTS `knowledge_items` (
|
||
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
`knowledge_base_id` BIGINT UNSIGNED NOT NULL COMMENT '知识库 ID',
|
||
`tenant_id` BIGINT UNSIGNED NOT NULL COMMENT '租户 ID',
|
||
`title` VARCHAR(500) NOT NULL COMMENT '标题',
|
||
`slug` VARCHAR(200) NOT NULL COMMENT '唯一标识',
|
||
`content` LONGTEXT NOT NULL COMMENT '内容(Markdown)',
|
||
`summary` TEXT DEFAULT NULL COMMENT '摘要',
|
||
`tags` JSON DEFAULT NULL COMMENT '标签',
|
||
`metadata` JSON DEFAULT NULL COMMENT '元数据',
|
||
`author_id` BIGINT UNSIGNED DEFAULT NULL COMMENT '作者 ID',
|
||
`status` ENUM('draft', 'review', 'published', 'archived') DEFAULT 'draft',
|
||
`views` INT DEFAULT 0 COMMENT '浏览次数',
|
||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`deleted_at` TIMESTAMP DEFAULT NULL,
|
||
|
||
KEY `idx_kb` (`knowledge_base_id`),
|
||
KEY `idx_tenant` (`tenant_id`),
|
||
KEY `idx_status` (`status`),
|
||
KEY `idx_tags` (`tags`),
|
||
CONSTRAINT `fk_ki_kb` FOREIGN KEY (`knowledge_base_id`) REFERENCES `knowledge_bases`(`id`) ON DELETE CASCADE,
|
||
CONSTRAINT `fk_ki_tenant` FOREIGN KEY (`tenant_id`) REFERENCES `tenants`(`id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='知识库项';
|
||
|
||
-- ============================================================
|
||
-- 全表索引优化
|
||
-- ============================================================
|
||
|
||
-- 用户角色查询优化
|
||
CREATE INDEX `idx_users_roles_composite` ON `user_roles` (`user_id`, `created_at`);
|
||
|
||
-- 消息时间查询优化
|
||
CREATE INDEX `idx_messages_created` ON `messages` (`created_at`);
|
||
|
||
-- 会话活跃状态优化
|
||
CREATE INDEX `idx_conversations_active` ON `conversations` (`status`, `created_at`);
|
||
|
||
-- 工单状态查询优化
|
||
CREATE INDEX `idx_tickets_status_priority` ON `tickets` (`status`, `priority`, `created_at`);
|
||
|
||
-- 知识库全文索引(可选)
|
||
ALTER TABLE `knowledge_items` ADD FULLTEXT INDEX `idx_content_fulltext` (`content`);
|
||
ALTER TABLE `knowledge_items` ADD FULLTEXT INDEX `idx_title_content` (`title`, `content`);
|
||
|
||
-- ============================================================
|
||
-- 完成迁移
|
||
-- ============================================================
|
||
|
||
-- 输出迁移信息
|
||
SELECT '✅ 数据库迁移完成!' AS status;
|