作者 徐宝林

初始化项目0908

正在显示 90 个修改的文件 包含 8158 行增加0 行删除
# AIGEO - AI内容生成平台
AIGEO是一个基于人工智能技术的内容生成平台,旨在帮助企业用户高效生成各种类型的内容,包括文章、落地页和网站。
## 功能特性
- **AI文章生成** - 基于关键词和主题自动生成高质量文章
- **AI落地页生成** - 根据业务需求自动生成营销落地页
- **AI网站生成** - 一键生成企业官网或电商网站
- **多租户架构** - 支持多企业用户独立使用
- **权限管理** - 完善的用户角色和权限控制
- **订阅计费** - 灵活的订阅计划和计费系统
- **内容发布** - 支持将生成内容发布到多种平台
- **SEO优化** - 自动生成SEO友好的内容结构
## 技术栈
- **后端**: Spring Boot 3.3.3
- **数据库**: MySQL 8.0
- **ORM框架**: JPA/Hibernate
- **安全框架**: Spring Security + JWT
- **缓存**: Redis
- **API文档**: Knife4j (OpenAPI 3)
- **任务调度**: Quartz
- **构建工具**: Maven
- **其他**: Lombok, Hutool, FastJSON2
## 系统要求
- JDK 17+
- MySQL 8.0+
- Redis
- Maven 3.8+
## 快速开始
### 1. 克隆项目
```bash
git clone <repository-url>
cd aigeo
```
### 2. 数据库配置
在 `src/main/resources/application.yml` 中配置数据库连接:
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/aigeo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: your_password
```
### 3. Redis配置
在 `src/main/resources/application.yml` 中配置Redis连接:
```yaml
spring:
data:
redis:
host: localhost
port: 6379
```
### 4. 构建和运行
```bash
# 构建项目
mvn clean package
# 运行项目
mvn spring-boot:run
# 或者运行打包后的JAR文件
java -jar target/aigeo-1.0.0.jar
```
## API文档
项目启动后,访问以下地址查看API文档:
- Knife4j UI: http://localhost:8080/api/doc.html
- OpenAPI JSON: http://localhost:8080/api/v3/api-docs
## 项目结构
```
src/main/java/com/aigeo
├── AigeoApplication.java # 应用启动类
├── ai/ # AI配置模块
│ ├── controller/
│ ├── dto/
│ ├── entity/
│ ├── repository/
│ └── service/
├── article/ # AI文章生成模块
│ ├── controller/
│ ├── dto/
│ ├── entity/
│ ├── repository/
│ └── service/
├── auth/ # 认证模块
│ └── dto/
├── common/ # 公共组件
│ ├── enums/ # 枚举类
│ ├── exception/ # 异常处理
│ └── config/ # 配置类
├── company/ # 公司与用户模块
│ ├── controller/
│ ├── dto/
│ ├── entity/
│ ├── repository/
│ └── service/
├── config/ # 配置类
├── controller/ # 控制器层(旧结构,待迁移)
├── entity/ # 实体类(旧结构,待迁移)
├── exception/ # 异常处理
├── landingpage/ # 落地页生成模块
│ ├── controller/
│ ├── dto/
│ ├── entity/
│ ├── repository/
│ └── service/
├── repository/ # 数据访问层(旧结构,待迁移)
├── service/ # 业务逻辑层(旧结构,待迁移)
├── util/ # 工具类
└── website/ # 网站构建模块(待实现)
src/main/resources/
├── application.yml # 应用配置
├── schema.sql # 数据库表结构
├── data.sql # 初始化数据
```
## 数据库设计
系统包含100+张数据表,主要模块包括:
1. **核心模块** - 公司、用户、权限、订阅
2. **AI功能模块** - 文章生成、落地页生成、网站生成
3. **内容管理模块** - 关键词、话题、文章、页面
4. **发布系统模块** - 平台配置、发布任务、发布记录
5. **统计分析模块** - 使用统计、活动日志
## 开发规范
- 使用Lombok简化实体类代码
- 遵循RESTful API设计规范
- 使用JPA注解进行ORM映射
- 采用分层架构设计(Controller-Service-Repository)
- 统一异常处理和响应格式
## 模块迁移计划
当前项目正在从扁平化结构迁移到模块化结构,迁移计划如下:
1. **已完成**:
- 创建模块化目录结构
- 创建DTO类
- 创建枚举类
2. **进行中**:
- 迁移Controller类到对应模块
- 迁移Entity类到对应模块
- 迁移Repository类到对应模块
- 迁移Service类到对应模块
3. **待完成**:
- 实现website模块
- 完善各模块间的交互
- 添加单元测试
## 部署
### 生产环境部署
```bash
# 构建生产包
mvn clean package -Pprod
# 运行
java -jar target/aigeo-1.0.0.jar --spring.profiles.active=prod
```
### Docker部署(可选)
```bash
# 构建Docker镜像
docker build -t aigeo:latest .
# 运行容器
docker run -d -p 8080:8080 aigeo:latest
```
## 贡献
欢迎提交Issue和Pull Request来改进项目。
## 许可证
本项目仅供学习和参考使用。
\ No newline at end of file
... ...
此 diff 太大无法显示。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ====================================================================================================
-- 1) 核心:公司、用户、权限、订阅
-- ====================================================================================================
-- 公司表(多租户根)
-- 存储企业客户的基本信息和订阅状态。
CREATE TABLE `ai_companies` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '公司主键ID',
`name` VARCHAR(255) NOT NULL COMMENT '公司名称',
`domain` VARCHAR(100) DEFAULT NULL COMMENT '公司域名,用于多租户访问',
`status` ENUM('active','suspended','trial') DEFAULT 'trial' COMMENT '公司状态',
`trial_expiry_date` DATE DEFAULT NULL COMMENT '试用到期日',
`default_settings` JSON DEFAULT NULL COMMENT '企业默认设置(JSON)',
`billing_email` VARCHAR(100) DEFAULT NULL COMMENT '账单邮箱',
`contact_phone` VARCHAR(20) DEFAULT NULL COMMENT '联系电话',
`address` TEXT DEFAULT NULL COMMENT '公司地址',
`logo_url` VARCHAR(255) DEFAULT NULL COMMENT '公司Logo URL',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_companies_domain` (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司表(多租户根)';
-- 用户表
-- 存储用户信息,并关联到所属公司。
CREATE TABLE `ai_users` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户主键ID',
`company_id` INT NOT NULL COMMENT '所属公司ID(外键)',
`username` VARCHAR(50) NOT NULL COMMENT '登录用户名',
`email` VARCHAR(100) NOT NULL COMMENT '用户邮箱',
`password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
`full_name` VARCHAR(100) DEFAULT NULL COMMENT '用户全名',
`avatar_url` VARCHAR(255) DEFAULT NULL COMMENT '用户头像URL',
`phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
`role` ENUM('admin','manager','editor','viewer') DEFAULT 'editor' COMMENT '用户角色',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用(1启用/0禁用)',
`last_login` TIMESTAMP NULL DEFAULT NULL COMMENT '最近登录时间',
`last_password_change` TIMESTAMP NULL DEFAULT NULL COMMENT '上次修改密码时间',
`failed_login_attempts` INT DEFAULT 0 COMMENT '登录失败次数',
`locked_until` TIMESTAMP NULL DEFAULT NULL COMMENT '锁定截止时间',
`timezone` VARCHAR(50) DEFAULT 'Asia/Shanghai' COMMENT '用户时区',
`preferences` JSON DEFAULT NULL COMMENT '用户个性化设置',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_users_username` (`username`),
UNIQUE KEY `uk_users_email` (`email`),
KEY `idx_users_company` (`company_id`),
KEY `idx_users_company_role` (`company_id`, `role`),
KEY `idx_users_active` (`is_active`),
CONSTRAINT `fk_user_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
-- 角色表 (增强权限控制)
-- 允许公司自定义角色及其权限。
CREATE TABLE `ai_roles` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '所属公司',
`name` VARCHAR(50) NOT NULL COMMENT '角色名称(如 admin, editor)',
`description` VARCHAR(255) DEFAULT NULL,
`permissions` JSON DEFAULT NULL COMMENT '该角色拥有的权限列表(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_roles_company_name` (`company_id`, `name`),
CONSTRAINT `fk_role_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 用户-角色关联表 (支持多角色)
-- 一个用户可以拥有多个角色。
CREATE TABLE `ai_user_roles` (
`user_id` INT NOT NULL,
`role_id` INT NOT NULL,
PRIMARY KEY (`user_id`, `role_id`),
FOREIGN KEY (user_id) REFERENCES ai_users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES ai_roles(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 审计日志表
-- 记录用户的关键操作,用于安全审计和追踪。
CREATE TABLE `ai_audit_logs` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '审计日志主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '操作用户ID(外键)',
`action` VARCHAR(100) NOT NULL COMMENT '操作类型(create/update/delete/publish等)',
`target_table` VARCHAR(100) NOT NULL COMMENT '被操作表名',
`target_id` INT NOT NULL COMMENT '被操作记录ID',
`details` JSON DEFAULT NULL COMMENT '操作详情(JSON,可记录前后值)',
`ip_address` VARCHAR(45) DEFAULT NULL COMMENT '客户端IP',
`user_agent` TEXT DEFAULT NULL COMMENT '浏览器信息',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
PRIMARY KEY (`id`),
KEY `idx_audit_company` (`company_id`),
KEY `idx_audit_user` (`user_id`),
CONSTRAINT `fk_audit_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_audit_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='操作审计日志';
-- ====================================================================================================
-- 2) 订阅与计费系统
-- ====================================================================================================
-- 订阅计划定义表
-- 定义可用的订阅计划及其基本属性。
CREATE TABLE `ai_subscription_plans` (
`id` INT NOT NULL AUTO_INCREMENT,
`plan_key` VARCHAR(50) NOT NULL COMMENT '计划标识符(如 free, basic, premium)',
`name` VARCHAR(100) NOT NULL COMMENT '计划显示名称',
`description` TEXT DEFAULT NULL COMMENT '计划描述',
`price_monthly` DECIMAL(10,2) DEFAULT 0.00 COMMENT '月费价格',
`price_yearly` DECIMAL(10,2) DEFAULT 0.00 COMMENT '年费价格',
`max_users` INT DEFAULT 1 COMMENT '最大用户数',
`max_storage_mb` INT DEFAULT 100 COMMENT '最大存储空间(MB)',
`max_api_calls_per_day` INT DEFAULT 1000 COMMENT '每日API调用限制',
`features` JSON DEFAULT NULL COMMENT '包含的功能列表(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`sort_order` INT DEFAULT 0 COMMENT '排序权重',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plans_plan_key` (`plan_key`),
KEY `idx_plans_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅计划定义表';
-- 公司订阅记录表
-- 记录每个公司的订阅历史和当前状态。
CREATE TABLE `ai_company_subscriptions` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`plan_id` INT NOT NULL COMMENT '订阅计划ID',
`plan_key` VARCHAR(50) NOT NULL COMMENT '冗余字段:计划标识符',
`subscription_type` ENUM('monthly','yearly') DEFAULT 'monthly' COMMENT '订阅类型',
`status` ENUM('active','cancelled','expired','suspended') DEFAULT 'active' COMMENT '订阅状态',
`start_date` DATE NOT NULL COMMENT '订阅开始日期',
`end_date` DATE DEFAULT NULL COMMENT '订阅结束日期',
`next_billing_date` DATE DEFAULT NULL COMMENT '下次计费日期',
`trial_start_date` DATE DEFAULT NULL COMMENT '试用开始日期',
`trial_end_date` DATE DEFAULT NULL COMMENT '试用结束日期',
`amount` DECIMAL(10,2) DEFAULT 0.00 COMMENT '订阅金额',
`payment_method` VARCHAR(50) DEFAULT NULL COMMENT '支付方式',
`payment_status` ENUM('pending','paid','failed','refunded') DEFAULT 'pending' COMMENT '支付状态',
`auto_renew` TINYINT(1) DEFAULT 1 COMMENT '是否自动续费',
`cancel_reason` TEXT DEFAULT NULL COMMENT '取消原因',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_subscriptions_company` (`company_id`),
KEY `idx_subscriptions_status` (`status`),
KEY `idx_subscriptions_next_billing` (`next_billing_date`),
CONSTRAINT `fk_subscription_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_subscription_plan` FOREIGN KEY (`plan_id`) REFERENCES `ai_subscription_plans` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公司订阅记录表';
-- 订阅支付记录表
-- 记录具体的支付交易。
CREATE TABLE `ai_subscription_payments` (
`id` INT NOT NULL AUTO_INCREMENT,
`subscription_id` INT NOT NULL COMMENT '订阅ID',
`company_id` INT NOT NULL COMMENT '公司ID',
`amount` DECIMAL(10,2) NOT NULL COMMENT '支付金额',
`currency` VARCHAR(3) DEFAULT 'CNY' COMMENT '货币类型',
`payment_method` VARCHAR(50) DEFAULT NULL COMMENT '支付方式(如 alipay, wechat, stripe)',
`transaction_id` VARCHAR(255) DEFAULT NULL COMMENT '交易ID',
`payment_status` ENUM('pending','success','failed','refunded') DEFAULT 'pending' COMMENT '支付状态',
`payment_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '支付时间',
`period_start` DATE DEFAULT NULL COMMENT '计费周期开始日期',
`period_end` DATE DEFAULT NULL COMMENT '计费周期结束日期',
`invoice_url` VARCHAR(500) DEFAULT NULL COMMENT '发票URL',
`failure_reason` TEXT DEFAULT NULL COMMENT '失败原因',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_payments_company` (`company_id`),
KEY `idx_payments_subscription` (`subscription_id`),
KEY `idx_payments_status` (`payment_status`),
CONSTRAINT `fk_payment_subscription` FOREIGN KEY (`subscription_id`) REFERENCES `ai_company_subscriptions` (`id`),
CONSTRAINT `fk_payment_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅支付记录表';
-- ====================================================================================================
-- 3) AI功能模块与权限控制
-- ====================================================================================================
-- AI功能模块定义表
-- 定义系统提供的所有AI功能模块。
CREATE TABLE `ai_features` (
`id` INT NOT NULL AUTO_INCREMENT,
`feature_key` VARCHAR(50) NOT NULL COMMENT '功能标识符 (如 ai_copywriting, ai_landing_page)',
`name` VARCHAR(100) NOT NULL COMMENT '功能名称',
`description` TEXT DEFAULT NULL COMMENT '功能描述',
`category` VARCHAR(50) DEFAULT NULL COMMENT '功能分类(如 content, marketing, website)',
`is_premium` TINYINT(1) DEFAULT 0 COMMENT '是否为高级功能',
`sort_order` INT DEFAULT 0 COMMENT '排序权重',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_features_key` (`feature_key`),
KEY `idx_features_category` (`category`),
KEY `idx_features_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI功能模块定义表';
-- 订阅计划功能权限表
-- 定义每个订阅计划对各AI功能的访问权限和使用限制。
CREATE TABLE `ai_plan_features` (
`id` INT NOT NULL AUTO_INCREMENT,
`plan_id` INT NOT NULL COMMENT '订阅计划ID',
`feature_id` INT NOT NULL COMMENT '功能ID',
`is_allowed` TINYINT(1) DEFAULT 1 COMMENT '是否允许使用',
`usage_limit` INT DEFAULT NULL COMMENT '使用限制(如每月次数,NULL为无限制)',
`limit_period` ENUM('daily','monthly','yearly','total') DEFAULT 'monthly' COMMENT '限制周期',
`custom_config` JSON DEFAULT NULL COMMENT '自定义配置(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plan_feature` (`plan_id`, `feature_id`),
CONSTRAINT `fk_planfeature_plan` FOREIGN KEY (`plan_id`) REFERENCES `ai_subscription_plans` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_planfeature_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅计划功能权限表';
-- 功能使用记录表
-- 记录用户对公司功能的具体使用情况,用于计费和分析。
CREATE TABLE `ai_feature_usage` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`user_id` INT DEFAULT NULL COMMENT '用户ID(可选)',
`feature_id` INT NOT NULL COMMENT '功能ID',
`usage_type` VARCHAR(50) DEFAULT NULL COMMENT '使用类型(如 generate, export, analyze)',
`usage_count` INT DEFAULT 1 COMMENT '使用次数',
`related_resource_id` VARCHAR(100) DEFAULT NULL COMMENT '相关资源ID(如文章ID、页面ID)',
`ip_address` VARCHAR(45) DEFAULT NULL COMMENT '客户端IP',
`user_agent` TEXT DEFAULT NULL COMMENT '用户代理',
`metadata` JSON DEFAULT NULL COMMENT '额外元数据',
`used_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '使用时间',
PRIMARY KEY (`id`),
KEY `idx_usage_company_feature` (`company_id`, `feature_id`),
KEY `idx_usage_feature_date` (`feature_id`, `used_at`),
KEY `idx_usage_user` (`user_id`),
CONSTRAINT `fk_usage_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_usage_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='功能使用记录表';
-- 功能使用统计表(用于快速查询)
-- 按日统计功能使用量,提高查询效率。
CREATE TABLE `ai_feature_usage_stats` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`feature_id` INT NOT NULL COMMENT '功能ID',
`stat_date` DATE NOT NULL COMMENT '统计日期',
`usage_count` INT DEFAULT 0 COMMENT '当日使用次数',
`last_used_at` TIMESTAMP DEFAULT NULL COMMENT '最后使用时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_stats_company_feature_date` (`company_id`, `feature_id`, `stat_date`),
KEY `idx_stats_company` (`company_id`),
KEY `idx_stats_feature` (`feature_id`),
CONSTRAINT `fk_stats_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_stats_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='功能使用统计表';
-- ====================================================================================================
-- 4) AI内容生成核心:模型、Prompt、文件
-- ====================================================================================================
-- AI服务配置表
-- 存储连接到不同AI服务(如Dify, OpenAI)的配置信息。
CREATE TABLE `ai_dify_api_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'AI配置主键ID',
`company_id` INT DEFAULT NULL COMMENT '公司ID(NULL 表示共享/通用)',
`provider` ENUM('dify','openai','anthropic','google','azure_openai','other') DEFAULT 'dify' COMMENT 'AI 提供方',
`name` VARCHAR(100) NOT NULL COMMENT '配置名称(便于识别)',
`base_url` VARCHAR(255) DEFAULT NULL COMMENT 'API 基础地址(可选)',
`api_key` VARCHAR(255) DEFAULT NULL COMMENT 'API Key/Token',
`model_name` VARCHAR(100) DEFAULT NULL COMMENT '模型名称',
`temperature` DECIMAL(3,2) DEFAULT 0.70 COMMENT '默认温度值',
`top_p` DECIMAL(3,2) DEFAULT 1.00 COMMENT 'TopP 值',
`max_tokens` INT DEFAULT 2048 COMMENT '最大生成 token 数',
`request_headers` JSON DEFAULT NULL COMMENT '额外请求头(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_dify_company` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI 服务配置(Dify/OpenAI 等)';
-- Prompt 模板表
-- 存储可复用的Prompt模板。
CREATE TABLE `ai_prompt_templates` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'Prompt 模板主键ID',
`company_id` INT DEFAULT NULL COMMENT '公司ID(NULL 表示系统模板)',
`name` VARCHAR(100) NOT NULL COMMENT '模板名称',
`description` VARCHAR(255) DEFAULT NULL COMMENT '模板描述',
`language` VARCHAR(20) DEFAULT 'zh' COMMENT '默认语言编码(en/zh 等)',
`content` LONGTEXT NOT NULL COMMENT '模板内容(可含变量占位符)',
`variables` JSON DEFAULT NULL COMMENT '变量说明(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_prompt_company` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Prompt 模板表';
-- 上传文件表
-- 管理用户上传的文件,如知识库、图片、视频等。
CREATE TABLE `ai_uploaded_files` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '上传文件主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '上传者用户ID(外键)',
`file_name` VARCHAR(255) NOT NULL COMMENT '原始文件名',
`file_path` VARCHAR(500) NOT NULL COMMENT '服务器存储路径或外部URL',
`file_type` ENUM('knowledge','image','video','document','other') NOT NULL COMMENT '文件类型',
`file_size` BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
`mime_type` VARCHAR(100) DEFAULT NULL COMMENT 'MIME 类型',
`checksum` VARCHAR(64) DEFAULT NULL COMMENT '校验和(可选)',
`version` INT DEFAULT 1 COMMENT '版本号(用于版本控制)',
`status` ENUM('active','archived','deleted') DEFAULT 'active' COMMENT '文件状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
PRIMARY KEY (`id`),
KEY `idx_files_company` (`company_id`),
KEY `idx_files_user` (`user_id`),
CONSTRAINT `fk_file_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_file_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='上传文件表(知识库/媒体等)';
-- ====================================================================================================
-- 5) AI内容生成:文章
-- ====================================================================================================
-- 文章类型表
-- 分类文章,如产品介绍、新闻稿等。
CREATE TABLE `ai_article_types` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章类型主键ID',
`name` VARCHAR(50) NOT NULL COMMENT '文章类型名称(如产品介绍)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '类型说明',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_types_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章类型表';
-- 文章生成配置表
-- 存储文章生成的参数和偏好设置。
CREATE TABLE `ai_article_generation_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章生成配置主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`name` VARCHAR(100) NOT NULL COMMENT '配置名称',
`platform_id` INT DEFAULT NULL COMMENT '适用发布平台ID(可选)',
`article_type_id` INT DEFAULT NULL COMMENT '文章类型ID(外键)',
`writing_language` VARCHAR(20) DEFAULT 'en' COMMENT '写作语言(en/zh)',
`remove_ai_tone` TINYINT(1) DEFAULT 1 COMMENT '是否去除AI味道',
`ai_taste_level` ENUM('colloquial','junior_high','senior_high','professional') DEFAULT 'junior_high' COMMENT 'AI风格等级',
`article_length_min` INT DEFAULT 800 COMMENT '最小长度(字符)',
`article_length_max` INT DEFAULT 1500 COMMENT '最大长度(字符)',
`auto_seo_optimization` TINYINT(1) DEFAULT 1 COMMENT '自动SEO优化',
`keyword_density_min` DECIMAL(5,2) DEFAULT 1.00 COMMENT '关键词密度下限(%)',
`keyword_density_max` DECIMAL(5,2) DEFAULT 2.00 COMMENT '关键词密度上限(%)',
`auto_geo_optimization` TINYINT(1) DEFAULT 1 COMMENT '是否自动GEO优化',
`auto_structured_data` TINYINT(1) DEFAULT 1 COMMENT '是否自动生成结构化数据',
`multi_version_count` INT DEFAULT 3 COMMENT '生成版本数量',
`extra_options` JSON DEFAULT NULL COMMENT '额外选项(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_config_company` (`company_id`),
KEY `idx_config_platform` (`platform_id`),
KEY `idx_config_article_type` (`article_type_id`),
CONSTRAINT `fk_config_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_config_platform` FOREIGN KEY (`platform_id`) REFERENCES `ai_publishing_platforms` (`id`),
CONSTRAINT `fk_config_article_type` FOREIGN KEY (`article_type_id`) REFERENCES `ai_article_types` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI 文章生成配置';
-- 文章生成任务表
-- 记录每次文章生成的请求和状态。
CREATE TABLE `ai_article_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章生成任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID(外键)',
`config_id` INT DEFAULT NULL COMMENT '使用的生成配置ID(外键)',
`article_theme` VARCHAR(255) DEFAULT NULL COMMENT '文章主题/标题(输入)',
`topic_ids` TEXT DEFAULT NULL COMMENT '所选话题ID列表(逗号分隔)',
`reference_urls` TEXT DEFAULT NULL COMMENT '参考URL列表(逗号分隔)',
`reference_content` LONGTEXT DEFAULT NULL COMMENT '高度参考链接抓取到的内容摘要',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`progress` TINYINT DEFAULT 0 COMMENT '进度(0-100)',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID(外键)',
`prompt_template_id` INT DEFAULT NULL COMMENT '使用的 Prompt 模板 ID(外键)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_task_company_status` (`company_id`,`status`),
KEY `idx_task_user` (`user_id`),
KEY `idx_task_config` (`config_id`),
CONSTRAINT `fk_task_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_task_config` FOREIGN KEY (`config_id`) REFERENCES `ai_article_generation_configs` (`id`),
CONSTRAINT `fk_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`),
CONSTRAINT `fk_task_prompt_template` FOREIGN KEY (`prompt_template_id`) REFERENCES `ai_prompt_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章生成任务';
-- 生成的文章表(多版本支持)
-- 存储AI生成的最终文章内容。
CREATE TABLE `ai_generated_articles` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成文章主键ID',
`task_id` INT DEFAULT NULL COMMENT '来源生成任务ID(外键,可空)',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`version` INT DEFAULT 1 COMMENT '文章版本号(用于多版本)',
`title` VARCHAR(255) DEFAULT NULL COMMENT '文章标题',
`content` LONGTEXT DEFAULT NULL COMMENT '文章纯文本内容(不含HTML)',
`html_content` LONGTEXT DEFAULT NULL COMMENT '文章HTML格式内容(含排版)',
`faq_section` JSON DEFAULT NULL COMMENT 'FAQ 部分(JSON)',
`structured_data` JSON DEFAULT NULL COMMENT '结构化数据 JSON-LD(全文)',
`word_count` INT DEFAULT 0 COMMENT '文章字数统计',
`keyword_density` JSON DEFAULT NULL COMMENT '关键词密度分析结果(JSON)',
`is_selected` TINYINT(1) DEFAULT 0 COMMENT '是否被选为最终版本(1是)',
`status` ENUM('draft','approved','archived','deleted') DEFAULT 'draft' COMMENT '文章状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_articles_company_status` (`company_id`,`status`),
KEY `idx_articles_task` (`task_id`),
CONSTRAINT `fk_article_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`),
CONSTRAINT `fk_article_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成的文章表(多版本支持)';
-- 文章FAQ列表
-- 存储文章的FAQ部分。
CREATE TABLE `ai_article_faqs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章 FAQ 主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`question` VARCHAR(255) NOT NULL COMMENT 'FAQ 问题',
`answer` TEXT NOT NULL COMMENT 'FAQ 回答',
PRIMARY KEY (`id`),
KEY `idx_article_faqs_article` (`article_id`),
CONSTRAINT `fk_faq_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章 FAQ 列表';
-- 文章结构化数据
-- 存储文章的结构化数据(JSON-LD)。
CREATE TABLE `ai_article_structured_data` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '结构化数据主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`json_ld` JSON NOT NULL COMMENT 'JSON-LD 结构化数据内容',
PRIMARY KEY (`id`),
KEY `idx_structured_article` (`article_id`),
CONSTRAINT `fk_structured_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章结构化数据(单独表便于管理/更新)';
-- 文章媒体资源
-- 存储文章关联的图片、视频等媒体。
CREATE TABLE `ai_article_media` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章媒体资源主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`media_type` ENUM('image','video','audio') NOT NULL COMMENT '媒体类型',
`url` VARCHAR(500) NOT NULL COMMENT '媒体链接或存储路径',
`prompt` TEXT DEFAULT NULL COMMENT '生成提示语(AI 配图时记录)',
`source_type` ENUM('ai_generated','user_provided','external') DEFAULT 'external' COMMENT '资源来源类型',
`alt_text` VARCHAR(255) DEFAULT NULL COMMENT '图片替代文本(SEO)',
`caption` VARCHAR(255) DEFAULT NULL COMMENT '图片说明/标题',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_media_article` (`article_id`),
CONSTRAINT `fk_media_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章媒体资源(多张图片/多视频)';
-- 文章多语言翻译表
-- 存储文章的不同语言版本。
CREATE TABLE `ai_article_translations` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章翻译主键ID',
`article_id` INT NOT NULL COMMENT '原文章ID(外键)',
`language` VARCHAR(20) NOT NULL COMMENT '翻译目标语言(如 en/zh)',
`title` VARCHAR(255) DEFAULT NULL COMMENT '译文标题',
`content` LONGTEXT DEFAULT NULL COMMENT '译文纯文本内容',
`html_content` LONGTEXT DEFAULT NULL COMMENT '译文 HTML 内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_language` (`article_id`,`language`),
KEY `idx_translations_article` (`article_id`),
CONSTRAINT `fk_translation_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章多语言翻译表';
-- ====================================================================================================
-- 6) AI内容生成:落地页
-- ====================================================================================================
-- 落地页模板表
-- 存储可用的落地页布局模板。
CREATE TABLE `ai_landing_page_templates` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '落地页模板主键ID',
`name` VARCHAR(100) NOT NULL COMMENT '模板名称(如:单栏布局)',
`code` VARCHAR(50) NOT NULL COMMENT '模板代码(如:single-column)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '模板描述',
`preview_image_url` VARCHAR(255) DEFAULT NULL COMMENT '预览图URL',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_templates_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页布局与设计模板';
-- 落地页项目表
-- 代表一个完整的落地页创建流程。
CREATE TABLE `ai_landing_page_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '落地页项目主键ID',
`company_id` INT NOT NULL COMMENT '所属公司ID(外键)',
`user_id` INT NOT NULL COMMENT '创建者用户ID(外键)',
`name` VARCHAR(255) NOT NULL COMMENT '落地页项目名称(用于内部识别)',
`status` ENUM('draft','configuring','generated','published','archived') DEFAULT 'draft' COMMENT '项目状态',
`last_step_completed` INT DEFAULT 0 COMMENT '最后完成的步骤号',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_lp_projects_company` (`company_id`),
KEY `idx_lp_projects_user` (`user_id`),
CONSTRAINT `fk_lp_project_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_lp_project_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI落地页构建项目表';
-- 落地页各步骤配置数据
-- 存储落地页构建过程中用户输入的所有配置信息。
CREATE TABLE `ai_landing_page_step_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID(外键)',
-- Step 1: 目标用户
`target_audience_desc` TEXT COMMENT '目标用户描述',
`user_pain_points` TEXT COMMENT '用户痛点(可JSON或换行分隔)',
`user_expectations` TEXT COMMENT '用户期望结果',
`age_groups` VARCHAR(255) DEFAULT NULL COMMENT '年龄段(逗号分隔)',
`gender_preference` ENUM('male','female','balanced') DEFAULT 'balanced' COMMENT '性别倾向',
`behavior_characteristics` VARCHAR(255) DEFAULT NULL COMMENT '用户行为特征(逗号分隔)',
`decision_making_styles` VARCHAR(255) DEFAULT NULL COMMENT '用户决策方式(逗号分隔)',
-- Step 2: 落地页目标
`industry_primary` VARCHAR(100) DEFAULT NULL COMMENT '一级行业',
`industry_secondary` VARCHAR(100) DEFAULT NULL COMMENT '二级行业',
`industry_tertiary` VARCHAR(100) DEFAULT NULL COMMENT '子分类',
`marketing_goal` VARCHAR(50) DEFAULT NULL COMMENT '营销目标(lead-collection, product-sales等)',
-- Step 3: 风格与配色
`design_style` VARCHAR(50) DEFAULT NULL COMMENT '设计风格(modern, professional等)',
`primary_color` VARCHAR(20) DEFAULT NULL COMMENT '主色调',
`accent_color` VARCHAR(20) DEFAULT NULL COMMENT '辅助色调',
`template_id` INT DEFAULT NULL COMMENT '布局模板ID(外键)',
-- Step 4: 核心卖点
`unique_value_proposition` TEXT COMMENT '独特价值主张',
`core_advantages` JSON DEFAULT NULL COMMENT '核心优势列表(JSON数组)',
`primary_keyword` VARCHAR(255) DEFAULT NULL COMMENT '主要关键词',
`secondary_keywords` JSON DEFAULT NULL COMMENT '次要关键词列表(JSON数组)',
-- Step 5: 页面内容
`content_generation_type` ENUM('ai','custom','upload') DEFAULT 'ai' COMMENT '内容生成方式',
`company_name` VARCHAR(255) DEFAULT NULL COMMENT '公司全称',
`brand_name` VARCHAR(255) DEFAULT NULL COMMENT '品牌名称',
`company_description` TEXT COMMENT '公司介绍',
`video_url` VARCHAR(500) DEFAULT NULL COMMENT '视频链接',
`logo_file_id` INT DEFAULT NULL COMMENT '公司Logo文件ID(关联ai_uploaded_files)',
`contact_info` JSON DEFAULT NULL COMMENT '联系信息(地址、电话、邮箱、工作时间)',
`social_media_links` JSON DEFAULT NULL COMMENT '社交媒体链接(JSON数组)',
-- Step 6: CTA
`primary_cta_text` VARCHAR(100) DEFAULT NULL COMMENT '主要CTA按钮文案',
`secondary_cta_texts` JSON DEFAULT NULL COMMENT '次要CTA按钮文案(JSON数组)',
-- Step 7: 信任元素
`testimonials` JSON DEFAULT NULL COMMENT '客户评价/推荐语(JSON数组,含姓名、职位、内容)',
`social_proofs` JSON DEFAULT NULL COMMENT '社会证明数据(JSON数组,含标签、数值)',
-- Step 8: 表单字段
`form_fields` JSON DEFAULT NULL COMMENT '表单字段配置(JSON对象,key为字段名,value为是否启用)',
-- Step 9: 生成与部署
`page_title` VARCHAR(255) DEFAULT NULL COMMENT '页面SEO标题',
`page_description` TEXT COMMENT '页面SEO描述',
`ga_tracking_code` TEXT COMMENT '谷歌广告跟踪代码',
`deployment_method` ENUM('ftp','link') DEFAULT 'link' COMMENT '部署方式',
`deployment_config` JSON DEFAULT NULL COMMENT '部署配置(FTP信息或子域名)',
`pricing_plan` VARCHAR(50) DEFAULT NULL COMMENT '选择的套餐(basic, pro, enterprise)',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_config_project` (`project_id`),
CONSTRAINT `fk_lp_config_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_lp_config_template` FOREIGN KEY (`template_id`) REFERENCES `ai_landing_page_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页各步骤配置数据';
-- 落地页AI生成任务表
-- 记录落地页生成的请求和状态。
CREATE TABLE `ai_landing_page_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID (外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID (外键)',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`progress` TINYINT DEFAULT 0 COMMENT '进度 (0-100)',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID (外键, 关联 ai_dify_api_configs)',
`prompt_template_id` INT DEFAULT NULL COMMENT '使用的Prompt模板ID (外键, 关联 ai_prompt_templates)',
`final_prompt_snapshot` LONGTEXT DEFAULT NULL COMMENT '发送给AI的最终Prompt快照(用于调试和记录)',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_lp_task_project` (`project_id`),
KEY `idx_lp_task_status` (`status`),
CONSTRAINT `fk_lp_task_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`),
CONSTRAINT `fk_lp_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_lp_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`),
CONSTRAINT `fk_lp_task_prompt_template` FOREIGN KEY (`prompt_template_id`) REFERENCES `ai_prompt_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页AI生成任务表';
-- 最终生成的落地页(支持多版本)
-- 存储AI生成的最终落地页HTML代码。
CREATE TABLE `ai_generated_landing_pages` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成落地页主键ID',
`project_id` INT NOT NULL COMMENT '来源项目ID(外键)',
`version_code` VARCHAR(20) NOT NULL DEFAULT 'A' COMMENT '版本标识(用于A/B测试,如A, B)',
`html_content` LONGTEXT COMMENT '落地页HTML内容',
`status` ENUM('draft','final','published') DEFAULT 'draft' COMMENT '版本状态',
`publish_url` VARCHAR(500) DEFAULT NULL COMMENT '发布后的URL(使用link方式时)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_project_version` (`project_id`, `version_code`),
CONSTRAINT `fk_lp_page_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='最终生成的落地页(支持多版本)';
-- 落地页项目关联的媒体资产
-- 存储落地页项目中使用的图片、Logo等文件。
CREATE TABLE `ai_landing_page_assets` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '资产主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID(外键)',
`asset_type` ENUM('product_image','certification_logo','testimonial_avatar') NOT NULL COMMENT '资产类型',
`uploaded_file_id` INT NOT NULL COMMENT '上传文件ID(外键)',
`related_data` JSON DEFAULT NULL COMMENT '相关数据(如关联的产品名或评价人)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_lp_assets_project` (`project_id`),
CONSTRAINT `fk_lp_asset_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`),
CONSTRAINT `fk_lp_asset_file` FOREIGN KEY (`uploaded_file_id`) REFERENCES `ai_uploaded_files` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页项目关联的媒体资产';
-- ====================================================================================================
-- 7) AI内容生成:网站 (简化版)
-- ====================================================================================================
-- AI网站构建项目总表
-- 代表一个完整的网站创建流程。
CREATE TABLE `ai_website_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '网站项目主键ID',
`company_id` INT NOT NULL COMMENT '所属公司ID (外键)',
`user_id` INT NOT NULL COMMENT '创建者用户ID (外键)',
`project_name` VARCHAR(255) NOT NULL COMMENT '项目名称 (用于内部识别)',
`site_name` VARCHAR(255) DEFAULT NULL COMMENT '最终生成的网站名称',
`status` ENUM('draft','configuring','generating','completed','published') DEFAULT 'draft' COMMENT '项目状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_website_projects_company` (`company_id`),
CONSTRAINT `fk_website_project_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_website_project_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI网站构建项目总表';
-- AI网站构建器配置(存储站点地图)
-- 存储网站的全局配置和站点地图结构。
CREATE TABLE `ai_website_build_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
`project_id` INT NOT NULL COMMENT '网站项目ID (外键)',
`website_type` VARCHAR(50) DEFAULT NULL COMMENT '网站类型 (business, portfolio等)',
`site_identity` JSON DEFAULT NULL COMMENT '网站身份信息 (名称, 标语, 描述, 关键词)',
`design_preferences` JSON DEFAULT NULL COMMENT '设计偏好 (风格, 主色调)',
`sitemap_structure` JSON DEFAULT NULL COMMENT '站点地图结构定义 (JSON, 描述栏目层级和类型)',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_website_config_project` (`project_id`),
CONSTRAINT `fk_website_config_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI网站构建器配置(存储站点地图)';
-- 网站栏目结构表 (支持无限层级)
-- 定义网站的栏目结构。
CREATE TABLE `ai_website_channels` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '网站栏目主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`parent_id` INT DEFAULT NULL COMMENT '父栏目ID (用于实现层级结构)',
`name` VARCHAR(100) NOT NULL COMMENT '栏目名称 (如: 公司介绍, 新闻中心)',
`path` VARCHAR(100) NOT NULL COMMENT 'URL路径 (如: /about, /news)',
`channel_type` ENUM('single_page', 'article_list', 'product_list', 'custom') NOT NULL COMMENT '栏目类型',
`display_order` INT DEFAULT 0 COMMENT '显示顺序',
`is_visible_in_nav` TINYINT(1) DEFAULT 1 COMMENT '是否在主导航中可见',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_channel_project` (`project_id`),
KEY `idx_channel_parent` (`parent_id`),
CONSTRAINT `fk_channel_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_channel_parent` FOREIGN KEY (`parent_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站栏目结构表 (支持无限层级)';
-- 网站文章内容表
-- 存储网站栏目下的文章内容。
CREATE TABLE `ai_website_articles` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`channel_id` INT NOT NULL COMMENT '所属文章栏目ID (外键)',
`title` VARCHAR(255) NOT NULL COMMENT '文章标题',
`summary` TEXT DEFAULT NULL COMMENT '文章摘要',
`content` LONGTEXT COMMENT '文章主体内容 (Markdown或HTML)',
`status` ENUM('draft', 'published') DEFAULT 'draft' COMMENT '发布状态',
`published_at` TIMESTAMP NULL DEFAULT NULL COMMENT '发布时间',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_article_project_channel` (`project_id`, `channel_id`),
CONSTRAINT `fk_website_article_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_article_channel` FOREIGN KEY (`channel_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站文章内容表';
-- 网站产品内容表
-- 存储网站栏目下的产品内容。
CREATE TABLE `ai_website_products` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '产品主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`channel_id` INT NOT NULL COMMENT '所属产品栏目ID (外键)',
`name` VARCHAR(255) NOT NULL COMMENT '产品名称',
`description` LONGTEXT COMMENT '产品详细描述',
`specifications` JSON DEFAULT NULL COMMENT '产品规格 (JSON格式)',
`main_image_url` VARCHAR(255) DEFAULT NULL COMMENT '产品主图URL',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_product_project_channel` (`project_id`, `channel_id`),
CONSTRAINT `fk_website_product_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_product_channel` FOREIGN KEY (`channel_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站产品内容表';
-- 网站AI生成任务表(支持父子任务)
-- 记录网站生成的请求和状态。
CREATE TABLE `ai_website_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务主键ID',
`project_id` INT NOT NULL COMMENT '网站项目ID (外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID (外键)',
`parent_task_id` INT DEFAULT NULL COMMENT '父任务ID (用于父子任务)',
`task_type` ENUM('full_site', 'generate_shell', 'generate_page_content', 'regenerate_channel') NOT NULL COMMENT '任务类型',
`target_id` INT DEFAULT NULL COMMENT '任务目标ID (如特定页面或栏目ID)',
`status` ENUM('pending','processing','completed','failed', 'waiting_for_children') DEFAULT 'pending' COMMENT '任务状态',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID (外键)',
`config_snapshot` JSON DEFAULT NULL COMMENT '生成时刻的配置快照',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_website_task_project` (`project_id`),
KEY `idx_website_task_parent` (`parent_task_id`),
CONSTRAINT `fk_website_task_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_website_task_parent` FOREIGN KEY (`parent_task_id`) REFERENCES `ai_website_generation_tasks` (`id`),
CONSTRAINT `fk_website_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站AI生成任务表(支持父子任务)';
-- 生成的网站页面(映射到栏目或内容项)
-- 存储AI生成的最终网站页面HTML代码。
CREATE TABLE `ai_generated_website_pages` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成页面主键ID',
`project_id` INT NOT NULL COMMENT '来源网站项目ID (外键)',
`task_id` INT NOT NULL COMMENT '来源生成任务ID (外键)',
`pageable_type` VARCHAR(100) NOT NULL COMMENT '关联类型 (Channel, Article, Product)',
`pageable_id` INT NOT NULL COMMENT '关联类型ID',
`file_name` VARCHAR(100) NOT NULL COMMENT '文件名 (如: index.html, news/article-1.html)',
`html_content` LONGTEXT COMMENT '页面的完整HTML内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
PRIMARY KEY (`id`),
KEY `idx_pageable` (`pageable_type`, `pageable_id`),
CONSTRAINT `fk_website_page_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_page_task` FOREIGN KEY (`task_id`) REFERENCES `ai_website_generation_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成的网站页面(映射到栏目或内容项)';
-- ====================================================================================================
-- 8) 内容发布系统
-- ====================================================================================================
-- 目标网站类型表
-- 对目标平台进行大类划分。
CREATE TABLE `ai_publishing_platform_types` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '平台类型主键ID',
`name` VARCHAR(50) NOT NULL COMMENT '平台类型名称(如 Blog, Social, Video)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '类型描述',
`icon` VARCHAR(100) DEFAULT NULL COMMENT '图标标识',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_platform_types_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站类型表';
-- 目标网站表
-- 定义支持发布的目标平台及其API配置模板。
CREATE TABLE `ai_publishing_platforms` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '目标网站主键ID',
`type_id` INT NOT NULL COMMENT '目标网站类型ID(外键)',
`name` VARCHAR(100) NOT NULL COMMENT '目标网站名称(如 WordPress, LinkedIn, 小红书)',
`code` VARCHAR(50) NOT NULL COMMENT '目标网站代码(唯一)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '目标网站说明',
`icon` VARCHAR(100) DEFAULT NULL COMMENT '目标网站图标',
`auth_type` ENUM('oauth','api_key','basic','custom') NOT NULL COMMENT '认证类型',
`api_config_template` JSON DEFAULT NULL COMMENT 'API 配置模板(JSON schema)',
`character_limit` INT DEFAULT NULL COMMENT '目标网站字符限制(如微博)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_platforms_code` (`code`),
KEY `idx_platforms_type` (`type_id`),
CONSTRAINT `fk_platform_type` FOREIGN KEY (`type_id`) REFERENCES `ai_publishing_platform_types` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站表';
-- 企业在目标网站的配置(API key/Token等)
-- 存储公司对特定平台的授权信息。
CREATE TABLE `ai_company_platform_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '企业平台配置主键ID',
`company_id` INT NOT NULL COMMENT '授权公司ID(外键)',
`platform_id` INT NOT NULL COMMENT '目标网站ID(外键)',
`config_data` JSON NOT NULL COMMENT '目标网站API配置信息(如 token、client_id)',
`account_name` VARCHAR(100) DEFAULT NULL COMMENT '企业在该目标网站的账号名/展示名',
`is_enabled` TINYINT(1) DEFAULT 1 COMMENT '是否启用该配置',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_platform` (`company_id`,`platform_id`),
KEY `idx_company_platform_company` (`company_id`),
KEY `idx_company_platform_platform` (`platform_id`),
CONSTRAINT `fk_company_platform_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_company_platform_platform` FOREIGN KEY (`platform_id`) REFERENCES `ai_publishing_platforms` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='企业在目标网站的配置(API key/Token等)';
-- 定时发布任务表
-- 管理计划在未来某个时间点执行的发布任务。
CREATE TABLE `ai_scheduled_publishing_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '定时发布任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`publishable_type` VARCHAR(50) DEFAULT 'article' COMMENT '发布内容类型(article, landing_page)',
`publishable_id` INT NOT NULL COMMENT '发布内容ID',
`article_id` INT DEFAULT NULL COMMENT '要发布的文章ID(外键) - 兼容旧版',
`platform_config_id` INT NOT NULL COMMENT '使用的企业平台配置ID(外键)',
`schedule_time` TIMESTAMP NOT NULL COMMENT '计划发布时间',
`status` ENUM('scheduled','processing','success','failed','cancelled') DEFAULT 'scheduled' COMMENT '任务状态',
`retry_count` INT DEFAULT 0 COMMENT '已重试次数',
`max_retries` INT DEFAULT 3 COMMENT '最大重试次数',
`last_attempt_at` TIMESTAMP NULL DEFAULT NULL COMMENT '最近一次尝试执行时间',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息(失败时记录)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_schedule_company_time` (`company_id`, `schedule_time`),
KEY `idx_schedule_status` (`status`),
CONSTRAINT `fk_schedule_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_schedule_platform_config` FOREIGN KEY (`platform_config_id`) REFERENCES `ai_company_platform_configs` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时发布任务表';
-- 目标网站发布记录表(执行日志)
-- 记录所有发布操作的执行结果。
CREATE TABLE `ai_publishing_records` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '发布记录主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`publishable_type` VARCHAR(50) DEFAULT 'article' COMMENT '发布内容类型(article, landing_page)',
`publishable_id` INT NOT NULL COMMENT '发布内容ID',
`article_id` INT DEFAULT NULL COMMENT '文章ID(外键) - 兼容旧版',
`platform_config_id` INT NOT NULL COMMENT '目标网站配置ID(外键)',
`scheduled_task_id` INT DEFAULT NULL COMMENT '来源的定时任务ID(如果是定时发布则关联)',
`status` ENUM('scheduled','published','failed') DEFAULT 'scheduled' COMMENT '发布记录状态',
`publish_url` VARCHAR(500) DEFAULT NULL COMMENT '发布后目标网站返回的文章URL',
`external_post_id` VARCHAR(255) DEFAULT NULL COMMENT '目标网站返回的外部帖文/文章ID',
`publish_time` TIMESTAMP NULL DEFAULT NULL COMMENT '实际发布时间',
`error_message` TEXT DEFAULT NULL COMMENT '失败原因(若失败)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
PRIMARY KEY (`id`),
KEY `idx_publishing_company_time` (`company_id`,`publish_time`),
KEY `idx_publishing_status` (`status`),
CONSTRAINT `fk_publishing_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_publishing_platform_config` FOREIGN KEY (`platform_config_id`) REFERENCES `ai_company_platform_configs` (`id`),
CONSTRAINT `fk_publishing_scheduled_task` FOREIGN KEY (`scheduled_task_id`) REFERENCES `ai_scheduled_publishing_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站发布记录表(执行日志)';
-- ====================================================================================================
-- 9) 关键词与话题管理 (SEO/内容规划)
-- ====================================================================================================
-- 关键词表
-- 管理用于内容生成和SEO的关键词。
CREATE TABLE `ai_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`keyword` VARCHAR(255) NOT NULL COMMENT '关键词文本',
`search_volume` INT DEFAULT 0 COMMENT '搜索量估算',
`cpc` DECIMAL(10,2) DEFAULT 0.00 COMMENT '估计每次点击成本',
`difficulty` TINYINT DEFAULT 0 COMMENT '关键词难度评分(0-100)',
`source` ENUM('baidu','google','manual','expansion','import') DEFAULT 'manual' COMMENT '来源类型',
`status` ENUM('pending','planned','generated','published') DEFAULT 'pending' COMMENT '关键词状态',
`tags` VARCHAR(255) DEFAULT NULL COMMENT '关键词标签,逗号分隔',
`usage_count` INT DEFAULT 0 COMMENT '关键词被文章使用次数',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_keyword` (`company_id`,`keyword`),
KEY `idx_keywords_company_status` (`company_id`,`status`),
CONSTRAINT `fk_keyword_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关键词表';
-- 关键词扩展表(保存 related_searches)
-- 存储关键词的扩展词(如相关搜索词)。
CREATE TABLE `ai_keyword_expansions` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词扩展主键ID',
`keyword_id` INT NOT NULL COMMENT '原始关键词ID(外键)',
`related_keyword` VARCHAR(255) NOT NULL COMMENT '扩展关键词(来自 related_searches 等)',
`source` ENUM('baidu','google','import') DEFAULT 'google' COMMENT '扩展来源',
`raw_response` JSON DEFAULT NULL COMMENT 'API 原始返回(便于溯源)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_keyword_exp_keyword` (`keyword_id`),
CONSTRAINT `fk_keyword_expansion_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关键词扩展表(保存 related_searches)';
-- 话题表
-- 管理更宽泛的内容主题。
CREATE TABLE `ai_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`source_task_id` INT DEFAULT NULL COMMENT '来源的抓取任务ID(外键,可空)',
`title` VARCHAR(255) NOT NULL COMMENT '话题标题',
`description` TEXT DEFAULT NULL COMMENT '话题描述或摘要',
`source_url` VARCHAR(500) DEFAULT NULL COMMENT '原始来源链接(可选)',
`status` ENUM('raw','curated','rejected') DEFAULT 'raw' COMMENT '话题状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_topics_company_status` (`company_id`,`status`),
KEY `idx_topics_source_task` (`source_task_id`),
CONSTRAINT `fk_topic_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_topic_source_task` FOREIGN KEY (`source_task_id`) REFERENCES `ai_search_sources_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='话题表';
-- 话题与关键词的多对多映射
-- 建立话题和关键词之间的关联。
CREATE TABLE `ai_topic_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题-关键词关联主键ID',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_topic_keyword` (`topic_id`,`keyword_id`),
KEY `idx_topic_keywords_topic` (`topic_id`),
KEY `idx_topic_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_topic_keyword_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_topic_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='话题与关键词的多对多映射';
-- AI数据源配置表
-- 配置用于抓取话题的外部数据源(如SERP API)。
CREATE TABLE `ai_search_sources_api` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '数据源配置主键ID',
`name` VARCHAR(100) NOT NULL COMMENT '数据来源名称 (如 百度前10、Google also ask)',
`source_type` ENUM('serp_api', 'rss', 'custom_api', 'web_scraping', 'database') NOT NULL COMMENT '来源类型',
`api_config` JSON NOT NULL COMMENT 'API 配置',
`result_parser` JSON NOT NULL COMMENT '结果解析规则',
`is_active` BOOLEAN DEFAULT TRUE COMMENT '是否启用',
`priority` TINYINT UNSIGNED DEFAULT 10 COMMENT '优先级 (1-100, 数字越小优先级越高)',
`rate_limit` JSON COMMENT '限流配置 {"requests": 100, "period": 3600}',
`health_check` JSON COMMENT '健康检查配置',
`metadata` JSON COMMENT '元数据 (描述、版本等)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_source_name` (`name`),
INDEX `idx_source_type` (`source_type`),
INDEX `idx_source_active` (`is_active`),
INDEX `idx_source_priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI数据源配置表';
-- AI数据源抓取任务表
-- 记录从外部数据源抓取话题的任务。
CREATE TABLE `ai_search_sources_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题抓取任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '发起任务的用户ID(外键)',
`topic_source_id` INT NOT NULL COMMENT '话题来源配置ID(外键)',
`keywords` TEXT DEFAULT NULL COMMENT '用于本次抓取的关键词快照(逗号分隔)',
`topic_id` INT DEFAULT NULL COMMENT '关联的话题ID(外键,可空)',
`keyword_id` INT DEFAULT NULL COMMENT '关联的关键词ID(外键,可空)',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`result_count` INT DEFAULT 0 COMMENT '抓取结果数量',
`raw_response` JSON DEFAULT NULL COMMENT 'API 原始返回(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '任务完成时间',
PRIMARY KEY (`id`),
KEY `idx_topic_fetch_company` (`company_id`),
KEY `idx_topic_fetch_source` (`topic_source_id`),
KEY `idx_topic_fetch_status` (`status`),
CONSTRAINT `fk_search_task_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_search_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_search_task_source` FOREIGN KEY (`topic_source_id`) REFERENCES `ai_search_sources_api` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI数据源抓取任务表';
-- ====================================================================================================
-- 10) 任务关联表 (连接生成任务与资源)
-- ====================================================================================================
-- 任务参考链接明细(可标注高度参考)
-- 存储文章生成任务中使用的参考链接。
CREATE TABLE `ai_task_references` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务参考链接主键ID',
`task_id` INT NOT NULL COMMENT '对应任务ID(外键)',
`url` VARCHAR(500) NOT NULL COMMENT '参考链接URL',
`title` VARCHAR(255) DEFAULT NULL COMMENT '页面标题(可选)',
`source_engine` VARCHAR(50) DEFAULT NULL COMMENT '来源引擎(google/baidu/zhihu等)',
`position` INT DEFAULT NULL COMMENT '在搜索结果中的排名位置',
`is_high_reference` TINYINT(1) DEFAULT 0 COMMENT '是否标记为高度参考(1是)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_task_references_task` (`task_id`),
CONSTRAINT `fk_task_reference_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务参考链接明细(可标注高度参考)';
-- 生成任务与关键词映射(规划用)
-- 将生成任务与计划使用的关键词关联。
CREATE TABLE `ai_task_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务-关键词关联主键ID',
`task_id` INT NOT NULL COMMENT '生成任务ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
`is_primary` TINYINT(1) DEFAULT 0 COMMENT '是否主关键词',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_task_keyword` (`task_id`,`keyword_id`),
KEY `idx_task_keywords_task` (`task_id`),
KEY `idx_task_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_task_keyword_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成任务与关键词映射(规划用)';
-- 生成任务与话题映射
-- 将生成任务与相关话题关联。
CREATE TABLE `ai_task_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务-话题关联主键ID',
`task_id` INT NOT NULL COMMENT '生成任务ID(外键)',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_task_topic` (`task_id`,`topic_id`),
KEY `idx_task_topics_task` (`task_id`),
KEY `idx_task_topics_topic` (`topic_id`),
CONSTRAINT `fk_task_topic_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_topic_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成任务与话题映射';
-- 任务知识库来源(公司库或上传的解析内容)
-- 指定生成任务使用的知识来源。
CREATE TABLE `ai_task_knowledge_sources` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务知识来源主键ID',
`task_id` INT NOT NULL COMMENT '任务ID(外键)',
`knowledge_type` ENUM('company','uploaded') NOT NULL COMMENT '知识来源类型(公司知识库/上传文件)',
`knowledge_id` INT DEFAULT NULL COMMENT '当 knowledge_type=uploaded 时,关联 ai_uploaded_files.id',
`content` LONGTEXT DEFAULT NULL COMMENT '若上传文件被解析,存解析后的文本内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_task_knowledge_task` (`task_id`),
KEY `idx_task_knowledge_knowledge` (`knowledge_id`),
CONSTRAINT `fk_task_knowledge_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_knowledge_file` FOREIGN KEY (`knowledge_id`) REFERENCES `ai_uploaded_files` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务知识库来源(公司库或上传的解析内容)';
-- 文章与关键词关联(实际使用)
-- 将最终生成的文章与实际使用的关键词关联。
CREATE TABLE `ai_article_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章关键词关联主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
`is_primary` TINYINT(1) DEFAULT 0 COMMENT '是否主关键词(1主/0辅)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_keyword` (`article_id`,`keyword_id`),
KEY `idx_article_keywords_article` (`article_id`),
KEY `idx_article_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_article_keyword_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_article_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章与关键词关联(实际使用)';
-- 文章与话题关联
-- 将最终生成的文章与相关话题关联。
CREATE TABLE `ai_article_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章话题关联主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_topic` (`article_id`,`topic_id`),
KEY `idx_article_topics_article` (`article_id`),
KEY `idx_article_topics_topic` (`topic_id`),
CONSTRAINT `fk_article_topic_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_article_topic_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章与话题关联';
-- ====================================================================================================
-- 11) 统计与活动日志
-- ====================================================================================================
-- 用户活动日志(审计/分析)
-- 记录用户的常规活动,用于行为分析。
CREATE TABLE `ai_user_activity_logs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户活动日志主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '用户ID(外键)',
`activity_type` VARCHAR(50) NOT NULL COMMENT '活动类型(如 login/create_article)',
`activity_details` JSON DEFAULT NULL COMMENT '活动详情(JSON)',
`ip_address` VARCHAR(45) DEFAULT NULL COMMENT '操作IP',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_activity_company_user` (`company_id`,`user_id`),
KEY `idx_activity_type` (`activity_type`),
CONSTRAINT `fk_activity_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_activity_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户活动日志(审计/分析)';
-- 公司使用统计
-- 统计公司的资源使用情况,用于计费和容量管理。
CREATE TABLE `ai_company_usage_stats` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '公司用量统计主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`stat_date` DATE NOT NULL COMMENT '统计日期',
`article_count` INT DEFAULT 0 COMMENT '当日生成文章数量',
`ai_token_usage` BIGINT DEFAULT 0 COMMENT '当日 AI 令牌使用量',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_date` (`company_id`,`stat_date`),
KEY `idx_usage_company` (`company_id`),
CONSTRAINT `fk_usage_stats_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司使用统计';
SET FOREIGN_KEY_CHECKS = 1;
\ No newline at end of file
... ...
package com.aigeo.ai.controller;
import com.aigeo.ai.entity.Feature;
import com.aigeo.ai.service.FeatureService;
import com.aigeo.common.Result;
import com.aigeo.common.ResultPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* AI功能模块控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/features")
@Tag(name = "AI功能管理", description = "AI功能模块相关接口")
public class FeatureController {
@Autowired
private FeatureService featureService;
@PostMapping
@Operation(summary = "创建AI功能", description = "创建新的AI功能")
public Result<Feature> createFeature(@RequestBody Feature feature) {
try {
Feature savedFeature = featureService.save(feature);
return Result.success("功能创建成功", savedFeature);
} catch (Exception e) {
log.error("创建AI功能失败", e);
return Result.error("功能创建失败");
}
}
@GetMapping("/{id}")
@Operation(summary = "获取AI功能详情", description = "根据ID获取AI功能详情")
public Result<Feature> getFeatureById(@PathVariable Integer id) {
try {
return featureService.findById(id)
.map(feature -> Result.success("查询成功", feature))
.orElse(Result.error("功能不存在"));
} catch (Exception e) {
log.error("获取AI功能详情失败, id: {}", id, e);
return Result.error("查询失败");
}
}
@GetMapping
@Operation(summary = "获取AI功能列表", description = "获取所有AI功能列表")
public Result<List<Feature>> getAllFeatures() {
try {
List<Feature> features = featureService.findAll();
return Result.success("查询成功", features);
} catch (Exception e) {
log.error("获取AI功能列表失败", e);
return Result.error("查询失败");
}
}
@GetMapping("/active")
@Operation(summary = "获取启用的AI功能列表", description = "获取所有启用的AI功能列表")
public Result<List<Feature>> getActiveFeatures() {
try {
List<Feature> features = featureService.findActiveFeatures();
return Result.success("查询成功", features);
} catch (Exception e) {
log.error("获取启用的AI功能列表失败", e);
return Result.error("查询失败");
}
}
@GetMapping("/category/{category}")
@Operation(summary = "根据分类获取AI功能列表", description = "根据分类获取AI功能列表")
public Result<List<Feature>> getFeaturesByCategory(@PathVariable String category) {
try {
List<Feature> features = featureService.findByCategory(category);
return Result.success("查询成功", features);
} catch (Exception e) {
log.error("根据分类获取AI功能列表失败, category: {}", category, e);
return Result.error("查询失败");
}
}
@PutMapping("/{id}")
@Operation(summary = "更新AI功能", description = "更新AI功能信息")
public Result<Feature> updateFeature(@PathVariable Integer id, @RequestBody Feature feature) {
try {
if (!featureService.findById(id).isPresent()) {
return Result.error("功能不存在");
}
feature.setId(id);
Feature updatedFeature = featureService.save(feature);
return Result.success("功能更新成功", updatedFeature);
} catch (Exception e) {
log.error("更新AI功能失败, id: {}", id, e);
return Result.error("功能更新失败");
}
}
@DeleteMapping("/{id}")
@Operation(summary = "删除AI功能", description = "删除指定ID的AI功能")
public Result<String> deleteFeature(@PathVariable Integer id) {
try {
if (!featureService.findById(id).isPresent()) {
return Result.error("功能不存在");
}
featureService.deleteById(id);
return Result.success("功能删除成功");
} catch (Exception e) {
log.error("删除AI功能失败, id: {}", id, e);
return Result.error("功能删除失败");
}
}
}
\ No newline at end of file
... ...
/**
* AI模块控制器包
*/
package com.aigeo.ai.controller;
\ No newline at end of file
... ...
package com.aigeo.ai.dto;
import com.aigeo.ai.entity.DifyApiConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.beans.BeanUtils;
/**
* Dify API配置DTO
*/
@Data
@Schema(description = "Dify API配置DTO")
public class DifyApiConfigDTO {
@Schema(description = "配置ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "配置名称")
private String name;
@Schema(description = "API Key")
private String apiKey;
@Schema(description = "API地址")
private String apiUrl;
@Schema(description = "是否启用")
private Boolean isActive;
@Schema(description = "备注")
private String remark;
/**
* 将DTO转换为实体类
*/
public DifyApiConfig toEntity() {
DifyApiConfig entity = new DifyApiConfig();
BeanUtils.copyProperties(this, entity);
return entity;
}
/**
* 将实体类转换为DTO
*/
public static DifyApiConfigDTO fromEntity(DifyApiConfig entity) {
DifyApiConfigDTO dto = new DifyApiConfigDTO();
BeanUtils.copyProperties(entity, dto);
return dto;
}
}
\ No newline at end of file
... ...
package com.aigeo.ai.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* AI功能模块DTO
*/
@Data
@Schema(description = "AI功能模块数据传输对象")
public class FeatureDTO {
@Schema(description = "功能ID")
private Integer id;
@Schema(description = "功能标识符", example = "ai_article")
private String featureKey;
@Schema(description = "功能名称", example = "AI文章生成")
private String name;
@Schema(description = "功能描述", example = "基于关键词和主题自动生成高质量文章")
private String description;
@Schema(description = "功能分类", example = "content")
private String category;
@Schema(description = "是否为高级功能")
private Boolean isPremium;
@Schema(description = "排序权重")
private Integer sortOrder;
@Schema(description = "是否启用")
private Boolean isActive;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
}
\ No newline at end of file
... ...
package com.aigeo.ai.entity;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
/**
* AI功能模块实体类
*/
@Data
@Entity
@Table(name = "ai_features")
public class Feature {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "feature_key", nullable = false, unique = true)
private String featureKey;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "description")
private String description;
@Column(name = "category")
private String category;
@Column(name = "is_premium")
private Boolean isPremium;
@Column(name = "sort_order")
private Integer sortOrder;
@Column(name = "is_active")
private Boolean isActive;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
if (isActive == null) {
isActive = true;
}
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
\ No newline at end of file
... ...
/**
* AI模块实体包
*/
package com.aigeo.ai.entity;
\ No newline at end of file
... ...
package com.aigeo.ai.repository;
import com.aigeo.ai.entity.Feature;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* AI功能模块仓库接口
*/
@Repository
public interface FeatureRepository extends JpaRepository<Feature, Integer> {
/**
* 根据功能标识符查找功能
*/
Optional<Feature> findByFeatureKey(String featureKey);
/**
* 根据分类查找功能列表
*/
List<Feature> findByCategory(String category);
/**
* 查找启用的功能列表
*/
List<Feature> findByIsActiveTrue();
/**
* 根据分类和启用状态查找功能列表
*/
List<Feature> findByCategoryAndIsActiveTrue(String category);
}
\ No newline at end of file
... ...
/**
* AI模块数据访问包
*/
package com.aigeo.ai.repository;
\ No newline at end of file
... ...
package com.aigeo.ai.service;
import com.aigeo.ai.entity.Feature;
import java.util.List;
import java.util.Optional;
/**
* AI功能模块服务接口
*/
public interface FeatureService {
/**
* 保存功能
*/
Feature save(Feature feature);
/**
* 根据ID查找功能
*/
Optional<Feature> findById(Integer id);
/**
* 根据功能标识符查找功能
*/
Optional<Feature> findByFeatureKey(String featureKey);
/**
* 查找所有功能
*/
List<Feature> findAll();
/**
* 查找启用的功能列表
*/
List<Feature> findActiveFeatures();
/**
* 根据分类查找功能列表
*/
List<Feature> findByCategory(String category);
/**
* 根据分类和启用状态查找功能列表
*/
List<Feature> findByCategoryAndIsActiveTrue(String category);
/**
* 删除功能
*/
void deleteById(Integer id);
}
\ No newline at end of file
... ...
package com.aigeo.ai.service.impl;
import com.aigeo.ai.entity.DifyApiConfig;
import com.aigeo.ai.repository.DifyApiConfigRepository;
import com.aigeo.ai.service.DifyApiConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* AI配置服务实现类
*/
@Service
public class DifyApiConfigServiceImpl implements DifyApiConfigService {
@Autowired
private DifyApiConfigRepository difyApiConfigRepository;
@Override
public DifyApiConfig save(DifyApiConfig config) {
return difyApiConfigRepository.save(config);
}
@Override
public Optional<DifyApiConfig> findById(Integer id) {
return difyApiConfigRepository.findById(id);
}
@Override
public List<DifyApiConfig> findByCompanyId(Integer companyId) {
return difyApiConfigRepository.findByCompanyId(companyId);
}
@Override
public List<DifyApiConfig> findActiveByCompanyId(Integer companyId) {
return difyApiConfigRepository.findByCompanyIdAndIsActiveTrue(companyId);
}
@Override
public List<DifyApiConfig> findByProvider(DifyApiConfig.Provider provider) {
return difyApiConfigRepository.findByProvider(provider);
}
@Override
public List<DifyApiConfig> findActiveByProvider(DifyApiConfig.Provider provider) {
return difyApiConfigRepository.findByProviderAndIsActiveTrue(provider);
}
@Override
public List<DifyApiConfig> findAll() {
return difyApiConfigRepository.findAll();
}
@Override
public void deleteById(Integer id) {
difyApiConfigRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
package com.aigeo.ai.service.impl;
import com.aigeo.ai.entity.Feature;
import com.aigeo.ai.repository.FeatureRepository;
import com.aigeo.ai.service.FeatureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* AI功能模块服务实现类
*/
@Service
public class FeatureServiceImpl implements FeatureService {
@Autowired
private FeatureRepository featureRepository;
@Override
public Feature save(Feature feature) {
return featureRepository.save(feature);
}
@Override
public Optional<Feature> findById(Integer id) {
return featureRepository.findById(id);
}
@Override
public Optional<Feature> findByFeatureKey(String featureKey) {
return featureRepository.findByFeatureKey(featureKey);
}
@Override
public List<Feature> findAll() {
return featureRepository.findAll();
}
@Override
public List<Feature> findActiveFeatures() {
return featureRepository.findByIsActiveTrue();
}
@Override
public List<Feature> findByCategory(String category) {
return featureRepository.findByCategory(category);
}
@Override
public List<Feature> findByCategoryAndIsActiveTrue(String category) {
return featureRepository.findByCategoryAndIsActiveTrue(category);
}
@Override
public void deleteById(Integer id) {
featureRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* AI模块业务逻辑包
*/
package com.aigeo.ai.service;
\ No newline at end of file
... ...
package com.aigeo.article.controller;
import com.aigeo.article.entity.GeneratedArticle;
import com.aigeo.article.service.GeneratedArticleService;
import com.aigeo.common.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 生成的文章控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/articles")
@Tag(name = "生成文章管理", description = "AI生成文章相关接口")
public class GeneratedArticleController {
@Autowired
private GeneratedArticleService generatedArticleService;
@PostMapping
@Operation(summary = "创建生成文章", description = "创建新的生成文章")
public Result<GeneratedArticle> createArticle(@RequestBody GeneratedArticle article) {
try {
GeneratedArticle savedArticle = generatedArticleService.save(article);
return Result.success("文章创建成功", savedArticle);
} catch (Exception e) {
log.error("创建生成文章失败", e);
return Result.error("文章创建失败");
}
}
@GetMapping("/{id}")
@Operation(summary = "获取生成文章详情", description = "根据ID获取生成文章详情")
public Result<GeneratedArticle> getArticleById(@PathVariable Integer id) {
try {
return generatedArticleService.findById(id)
.map(article -> Result.success("查询成功", article))
.orElse(Result.error("文章不存在"));
} catch (Exception e) {
log.error("获取生成文章详情失败, id: {}", id, e);
return Result.error("查询失败");
}
}
@GetMapping
@Operation(summary = "获取生成文章列表", description = "获取所有生成文章列表")
public Result<List<GeneratedArticle>> getAllArticles() {
try {
List<GeneratedArticle> articles = generatedArticleService.findAll();
return Result.success("查询成功", articles);
} catch (Exception e) {
log.error("获取生成文章列表失败", e);
return Result.error("查询失败");
}
}
@GetMapping("/task/{taskId}")
@Operation(summary = "根据任务ID获取生成文章列表", description = "根据任务ID获取生成文章列表")
public Result<List<GeneratedArticle>> getArticlesByTaskId(@PathVariable Integer taskId) {
try {
List<GeneratedArticle> articles = generatedArticleService.findByTaskId(taskId);
return Result.success("查询成功", articles);
} catch (Exception e) {
log.error("根据任务ID获取生成文章列表失败, taskId: {}", taskId, e);
return Result.error("查询失败");
}
}
@GetMapping("/company/{companyId}")
@Operation(summary = "根据公司ID获取生成文章列表", description = "根据公司ID获取生成文章列表")
public Result<List<GeneratedArticle>> getArticlesByCompanyId(@PathVariable Integer companyId) {
try {
List<GeneratedArticle> articles = generatedArticleService.findByCompanyId(companyId);
return Result.success("查询成功", articles);
} catch (Exception e) {
log.error("根据公司ID获取生成文章列表失败, companyId: {}", companyId, e);
return Result.error("查询失败");
}
}
@GetMapping("/status/{status}")
@Operation(summary = "根据状态获取生成文章列表", description = "根据状态获取生成文章列表")
public Result<List<GeneratedArticle>> getArticlesByStatus(@PathVariable String status) {
try {
GeneratedArticle.ArticleStatus articleStatus = GeneratedArticle.ArticleStatus.fromCode(status);
List<GeneratedArticle> articles = generatedArticleService.findByStatus(articleStatus);
return Result.success("查询成功", articles);
} catch (Exception e) {
log.error("根据状态获取生成文章列表失败, status: {}", status, e);
return Result.error("查询失败");
}
}
@PutMapping("/{id}")
@Operation(summary = "更新生成文章", description = "更新生成文章信息")
public Result<GeneratedArticle> updateArticle(@PathVariable Integer id, @RequestBody GeneratedArticle article) {
try {
if (!generatedArticleService.findById(id).isPresent()) {
return Result.error("文章不存在");
}
article.setId(id);
GeneratedArticle updatedArticle = generatedArticleService.save(article);
return Result.success("文章更新成功", updatedArticle);
} catch (Exception e) {
log.error("更新生成文章失败, id: {}", id, e);
return Result.error("文章更新失败");
}
}
@DeleteMapping("/{id}")
@Operation(summary = "删除生成文章", description = "删除指定ID的生成文章")
public Result<String> deleteArticle(@PathVariable Integer id) {
try {
if (!generatedArticleService.findById(id).isPresent()) {
return Result.error("文章不存在");
}
generatedArticleService.deleteById(id);
return Result.success("文章删除成功");
} catch (Exception e) {
log.error("删除生成文章失败, id: {}", id, e);
return Result.error("文章删除失败");
}
}
}
\ No newline at end of file
... ...
/**
* 文章模块控制器包
*/
package com.aigeo.article.controller;
\ No newline at end of file
... ...
package com.aigeo.article.dto;
import com.aigeo.article.entity.ArticleGenerationTask;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import java.time.LocalDateTime;
/**
* 文章生成任务DTO
*/
@Data
@Schema(description = "文章生成任务DTO")
public class ArticleGenerationTaskDTO {
@Schema(description = "任务ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "任务名称")
private String name;
@Schema(description = "主题")
private String topic;
@Schema(description = "关键词")
private String keywords;
@Schema(description = "文章数量")
private Integer articleCount;
@Schema(description = "平台类型")
private String platformType;
@Schema(description = "状态")
private String status;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
/**
* 将DTO转换为实体类
*/
public ArticleGenerationTask toEntity() {
ArticleGenerationTask entity = new ArticleGenerationTask();
BeanUtils.copyProperties(this, entity);
return entity;
}
/**
* 将实体类转换为DTO
*/
public static ArticleGenerationTaskDTO fromEntity(ArticleGenerationTask entity) {
ArticleGenerationTaskDTO dto = new ArticleGenerationTaskDTO();
BeanUtils.copyProperties(entity, dto);
return dto;
}
}
\ No newline at end of file
... ...
package com.aigeo.article.dto;
import com.aigeo.article.entity.GeneratedArticle;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import java.time.LocalDateTime;
/**
* 生成文章DTO
*/
@Data
@Schema(description = "生成文章DTO")
public class GeneratedArticleDTO {
@Schema(description = "文章ID")
private Integer id;
@Schema(description = "任务ID")
private Integer taskId;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "标题")
private String title;
@Schema(description = "内容")
private String content;
@Schema(description = "状态")
private String status;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
/**
* 将DTO转换为实体类
*/
public GeneratedArticle toEntity() {
GeneratedArticle entity = new GeneratedArticle();
BeanUtils.copyProperties(this, entity);
return entity;
}
/**
* 将实体类转换为DTO
*/
public static GeneratedArticleDTO fromEntity(GeneratedArticle entity) {
GeneratedArticleDTO dto = new GeneratedArticleDTO();
BeanUtils.copyProperties(entity, dto);
return dto;
}
}
\ No newline at end of file
... ...
/**
* 文章模块实体包
*/
package com.aigeo.article.entity;
\ No newline at end of file
... ...
package com.aigeo.article.repository;
import com.aigeo.article.entity.GeneratedArticle;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 生成的文章仓库接口
*/
@Repository
public interface GeneratedArticleRepository extends JpaRepository<GeneratedArticle, Integer> {
/**
* 根据任务ID查找文章列表
*/
List<GeneratedArticle> findByTaskId(Integer taskId);
/**
* 根据公司ID查找文章列表
*/
List<GeneratedArticle> findByCompanyId(Integer companyId);
/**
* 根据任务ID和版本查找文章
*/
GeneratedArticle findByTaskIdAndVersion(Integer taskId, Integer version);
/**
* 根据任务ID查找选定的文章
*/
GeneratedArticle findByTaskIdAndIsSelectedTrue(Integer taskId);
/**
* 根据状态查找文章列表
*/
List<GeneratedArticle> findByStatus(GeneratedArticle.ArticleStatus status);
/**
* 根据公司ID和状态查找文章列表
*/
List<GeneratedArticle> findByCompanyIdAndStatus(Integer companyId, GeneratedArticle.ArticleStatus status);
}
\ No newline at end of file
... ...
/**
* 文章模块数据访问包
*/
package com.aigeo.article.repository;
\ No newline at end of file
... ...
package com.aigeo.article.service;
import com.aigeo.article.entity.ArticleGenerationTask;
import java.util.List;
import java.util.Optional;
/**
* 文章生成任务服务接口
*/
public interface ArticleGenerationTaskService {
/**
* 保存任务
*/
ArticleGenerationTask save(ArticleGenerationTask task);
/**
* 根据ID查找任务
*/
Optional<ArticleGenerationTask> findById(Integer id);
/**
* 根据公司ID查找任务列表
*/
List<ArticleGenerationTask> findByCompanyId(Integer companyId);
/**
* 根据用户ID查找任务列表
*/
List<ArticleGenerationTask> findByUserId(Integer userId);
/**
* 根据状态查找任务列表
*/
List<ArticleGenerationTask> findByStatus(ArticleGenerationTask.TaskStatus status);
/**
* 根据公司ID和状态查找任务列表
*/
List<ArticleGenerationTask> findByCompanyIdAndStatus(Integer companyId, ArticleGenerationTask.TaskStatus status);
/**
* 根据用户ID和状态查找任务列表
*/
List<ArticleGenerationTask> findByUserIdAndStatus(Integer userId, ArticleGenerationTask.TaskStatus status);
/**
* 查找所有任务
*/
List<ArticleGenerationTask> findAll();
/**
* 删除任务
*/
void deleteById(Integer id);
}
\ No newline at end of file
... ...
package com.aigeo.article.service;
import com.aigeo.article.entity.GeneratedArticle;
import java.util.List;
import java.util.Optional;
/**
* 生成的文章服务接口
*/
public interface GeneratedArticleService {
/**
* 保存文章
*/
GeneratedArticle save(GeneratedArticle article);
/**
* 根据ID查找文章
*/
Optional<GeneratedArticle> findById(Integer id);
/**
* 根据任务ID查找文章列表
*/
List<GeneratedArticle> findByTaskId(Integer taskId);
/**
* 根据公司ID查找文章列表
*/
List<GeneratedArticle> findByCompanyId(Integer companyId);
/**
* 根据任务ID和版本查找文章
*/
GeneratedArticle findByTaskIdAndVersion(Integer taskId, Integer version);
/**
* 根据任务ID查找选定的文章
*/
GeneratedArticle findByTaskIdAndIsSelectedTrue(Integer taskId);
/**
* 根据状态查找文章列表
*/
List<GeneratedArticle> findByStatus(GeneratedArticle.ArticleStatus status);
/**
* 根据公司ID和状态查找文章列表
*/
List<GeneratedArticle> findByCompanyIdAndStatus(Integer companyId, GeneratedArticle.ArticleStatus status);
/**
* 查找所有文章
*/
List<GeneratedArticle> findAll();
/**
* 删除文章
*/
void deleteById(Integer id);
}
\ No newline at end of file
... ...
package com.aigeo.article.service.impl;
import com.aigeo.article.entity.ArticleGenerationTask;
import com.aigeo.article.repository.ArticleGenerationTaskRepository;
import com.aigeo.article.service.ArticleGenerationTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 文章生成任务服务实现类
*/
@Service
public class ArticleGenerationTaskServiceImpl implements ArticleGenerationTaskService {
@Autowired
private ArticleGenerationTaskRepository articleGenerationTaskRepository;
@Override
public ArticleGenerationTask save(ArticleGenerationTask task) {
return articleGenerationTaskRepository.save(task);
}
@Override
public Optional<ArticleGenerationTask> findById(Integer id) {
return articleGenerationTaskRepository.findById(id);
}
@Override
public List<ArticleGenerationTask> findByCompanyId(Integer companyId) {
return articleGenerationTaskRepository.findByCompanyId(companyId);
}
@Override
public List<ArticleGenerationTask> findByUserId(Integer userId) {
return articleGenerationTaskRepository.findByUserId(userId);
}
@Override
public List<ArticleGenerationTask> findByStatus(ArticleGenerationTask.TaskStatus status) {
return articleGenerationTaskRepository.findByStatus(status);
}
@Override
public List<ArticleGenerationTask> findByCompanyIdAndStatus(Integer companyId, ArticleGenerationTask.TaskStatus status) {
return articleGenerationTaskRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<ArticleGenerationTask> findByUserIdAndStatus(Integer userId, ArticleGenerationTask.TaskStatus status) {
return articleGenerationTaskRepository.findByUserIdAndStatus(userId, status);
}
@Override
public List<ArticleGenerationTask> findAll() {
return articleGenerationTaskRepository.findAll();
}
@Override
public void deleteById(Integer id) {
articleGenerationTaskRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
package com.aigeo.article.service.impl;
import com.aigeo.article.entity.GeneratedArticle;
import com.aigeo.article.repository.GeneratedArticleRepository;
import com.aigeo.article.service.GeneratedArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 生成的文章服务实现类
*/
@Service
public class GeneratedArticleServiceImpl implements GeneratedArticleService {
@Autowired
private GeneratedArticleRepository generatedArticleRepository;
@Override
public GeneratedArticle save(GeneratedArticle article) {
return generatedArticleRepository.save(article);
}
@Override
public Optional<GeneratedArticle> findById(Integer id) {
return generatedArticleRepository.findById(id);
}
@Override
public List<GeneratedArticle> findByTaskId(Integer taskId) {
return generatedArticleRepository.findByTaskId(taskId);
}
@Override
public List<GeneratedArticle> findByCompanyId(Integer companyId) {
return generatedArticleRepository.findByCompanyId(companyId);
}
@Override
public GeneratedArticle findByTaskIdAndVersion(Integer taskId, Integer version) {
return generatedArticleRepository.findByTaskIdAndVersion(taskId, version);
}
@Override
public GeneratedArticle findByTaskIdAndIsSelectedTrue(Integer taskId) {
return generatedArticleRepository.findByTaskIdAndIsSelectedTrue(taskId);
}
@Override
public List<GeneratedArticle> findByStatus(GeneratedArticle.ArticleStatus status) {
return generatedArticleRepository.findByStatus(status);
}
@Override
public List<GeneratedArticle> findByCompanyIdAndStatus(Integer companyId, GeneratedArticle.ArticleStatus status) {
return generatedArticleRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<GeneratedArticle> findAll() {
return generatedArticleRepository.findAll();
}
@Override
public void deleteById(Integer id) {
generatedArticleRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 文章模块业务逻辑包
*/
package com.aigeo.article.service;
\ No newline at end of file
... ...
package com.aigeo.auth.dto;
import com.aigeo.company.entity.User;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 用户注册响应DTO
*/
@Data
@Schema(description = "用户注册响应数据")
public class RegisterResponse {
@Schema(description = "访问令牌")
private String token;
@Schema(description = "过期时间(毫秒)")
private Long expiresIn;
@Schema(description = "用户信息")
private User user;
}
\ No newline at end of file
... ...
package com.aigeo.auth.service;
import com.aigeo.company.entity.User;
import com.aigeo.company.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Optional;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> userOptional = userService.findByUsername(username);
if (!userOptional.isPresent()) {
userOptional = userService.findByEmail(username);
}
if (!userOptional.isPresent()) {
throw new UsernameNotFoundException("User not found with username or email: " + username);
}
User user = userOptional.get();
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPasswordHash(),
user.getIsActive(),
true,
true,
true,
Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + user.getRole().name()))
);
}
}
\ No newline at end of file
... ...
package com.aigeo.auth.service.impl;
import com.aigeo.auth.dto.LoginRequest;
import com.aigeo.auth.dto.LoginResponse;
import com.aigeo.auth.dto.RegisterRequest;
import com.aigeo.auth.dto.RegisterResponse;
import com.aigeo.auth.service.AuthService;
import com.aigeo.company.entity.Company;
import com.aigeo.company.entity.User;
import com.aigeo.company.service.CompanyService;
import com.aigeo.company.service.UserService;
import com.aigeo.common.enums.CompanyStatus;
import com.aigeo.common.enums.UserRole;
import com.aigeo.common.exception.BusinessException;
import com.aigeo.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Optional;
/**
* 认证服务实现类
*/
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {
private final UserService userService;
private final CompanyService companyService;
private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
public AuthServiceImpl(UserService userService, CompanyService companyService,
PasswordEncoder passwordEncoder, JwtUtil jwtUtil) {
this.userService = userService;
this.companyService = companyService;
this.passwordEncoder = passwordEncoder;
this.jwtUtil = jwtUtil;
}
@Override
public LoginResponse login(LoginRequest loginRequest) {
try {
// 查找用户
Optional<User> userOptional = userService.findByUsername(loginRequest.getUsername());
if (!userOptional.isPresent()) {
// 尝试通过邮箱查找
userOptional = userService.findByEmail(loginRequest.getUsername());
}
if (!userOptional.isPresent()) {
throw new BusinessException(400, "用户名或密码错误");
}
User user = userOptional.get();
// 验证密码
if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPasswordHash())) {
throw new BusinessException(400, "用户名或密码错误");
}
// 生成JWT token
String token = jwtUtil.generateToken(user);
// 构建响应
LoginResponse response = new LoginResponse();
response.setToken(token);
response.setExpiresIn(jwtUtil.getExpirationTimeSeconds());
response.setUser(user);
return response;
} catch (Exception e) {
log.error("用户登录失败: {}", loginRequest.getUsername(), e);
throw new BusinessException(500, "登录失败");
}
}
@Override
public RegisterResponse register(RegisterRequest registerRequest) {
try {
// 检查用户名是否已存在
if (userService.findByUsername(registerRequest.getUsername()).isPresent()) {
throw new BusinessException(400, "用户名已存在");
}
// 检查邮箱是否已存在
if (userService.findByEmail(registerRequest.getEmail()).isPresent()) {
throw new BusinessException(400, "邮箱已被注册");
}
// 验证密码和确认密码是否一致
if (!registerRequest.getPassword().equals(registerRequest.getConfirmPassword())) {
throw new BusinessException(400, "密码和确认密码不一致");
}
// 确定公司ID
Integer companyId = registerRequest.getCompanyId();
if (companyId == null) {
// 如果没有提供公司ID,则需要提供公司名称来创建新公司
if (registerRequest.getCompanyName() == null || registerRequest.getCompanyName().isEmpty()) {
throw new BusinessException(400, "必须提供公司ID或公司名称");
}
// 创建新公司
Company company = new Company();
company.setName(registerRequest.getCompanyName());
company.setBillingEmail(registerRequest.getEmail());
company.setStatus(CompanyStatus.TRIAL);
company.setTrialExpiryDate(LocalDateTime.now().plusDays(30)); // 30天试用期
Company savedCompany = companyService.save(company);
companyId = savedCompany.getId();
log.info("为新用户 {} 创建了新公司 {}, 公司ID: {}",
registerRequest.getUsername(), registerRequest.getCompanyName(), companyId);
}
// 创建新用户
User user = new User();
user.setUsername(registerRequest.getUsername());
user.setEmail(registerRequest.getEmail());
user.setPasswordHash(passwordEncoder.encode(registerRequest.getPassword()));
user.setFullName(registerRequest.getFullName());
user.setPhone(registerRequest.getPhone());
user.setCompanyId(companyId);
user.setRole(UserRole.EDITOR); // 使用现有的枚举值
user.setAvatarUrl(registerRequest.getAvatarUrl());
user.setIsActive(true);
// 保存用户
User savedUser = userService.save(user);
// 生成JWT token
String token = jwtUtil.generateToken(savedUser);
// 构建响应
RegisterResponse response = new RegisterResponse();
response.setToken(token);
response.setExpiresIn(jwtUtil.getExpirationTimeSeconds());
response.setUser(savedUser);
return response;
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
log.error("用户注册失败: {}", registerRequest.getUsername(), e);
throw new BusinessException(500, "注册失败");
}
}
}
\ No newline at end of file
... ...
package com.aigeo.common;
import com.aigeo.common.enums.ResultCode;
import lombok.Data;
import java.io.Serializable;
/**
* 统一响应结果封装类
*/
@Data
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 状态码
*/
private int code;
/**
* 消息
*/
private String message;
/**
* 数据
*/
private T data;
public Result() {
}
public Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 成功
*/
public static <T> Result<T> success() {
return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);
}
/**
* 成功
*/
public static <T> Result<T> success(T data) {
return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
}
/**
* 成功
*/
public static <T> Result<T> success(String message, T data) {
return new Result<>(ResultCode.SUCCESS.getCode(), message, data);
}
/**
* 失败
*/
public static <T> Result<T> error() {
return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), ResultCode.INTERNAL_SERVER_ERROR.getMessage(), null);
}
/**
* 失败
*/
public static <T> Result<T> error(String message) {
return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), message, null);
}
/**
* 失败
*/
public static <T> Result<T> error(ResultCode resultCode) {
return new Result<>(resultCode.getCode(), resultCode.getMessage(), null);
}
/**
* 失败
*/
public static <T> Result<T> error(int code, String message) {
return new Result<>(code, message, null);
}
/**
* 失败
*/
public static <T> Result<T> error(ResultCode resultCode, String message) {
return new Result<>(resultCode.getCode(), message, null);
}
/**
* 失败
*/
public static <T> Result<T> error(int code, String message, T data) {
return new Result<>(code, message, data);
}
}
\ No newline at end of file
... ...
package com.aigeo.common;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 分页结果封装类
*/
@Data
@Schema(description = "分页结果封装类")
public class ResultPage<T> {
@Schema(description = "当前页码")
private int pageNumber;
@Schema(description = "每页记录数")
private int pageSize;
@Schema(description = "总记录数")
private long total;
@Schema(description = "总页数")
private int totalPages;
@Schema(description = "当前页数据")
private List<T> items;
public ResultPage() {
}
public ResultPage(int pageNumber, int pageSize, long total, List<T> items) {
this.pageNumber = pageNumber;
this.pageSize = pageSize;
this.total = total;
this.items = items;
this.totalPages = (int) Math.ceil((double) total / pageSize);
}
/**
* 创建分页结果
*/
public static <T> ResultPage<T> of(int pageNumber, int pageSize, long total, List<T> items) {
return new ResultPage<>(pageNumber, pageSize, total, items);
}
}
\ No newline at end of file
... ...
package com.aigeo.common.enums;
/**
* 响应结果码枚举
*/
public enum ResultCode {
SUCCESS(200, "操作成功"),
BAD_REQUEST(400, "请求参数错误"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "禁止访问"),
NOT_FOUND(404, "资源不存在"),
INTERNAL_SERVER_ERROR(500, "服务器内部错误");
private final int code;
private final String message;
ResultCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public static ResultCode fromCode(Integer code) {
if (code == null) {
return INTERNAL_SERVER_ERROR;
}
for (ResultCode resultCode : ResultCode.values()) {
if (resultCode.getCode() == code) {
return resultCode;
}
}
return INTERNAL_SERVER_ERROR;
}
}
\ No newline at end of file
... ...
/**
* 公司模块控制器包
*/
package com.aigeo.company.controller;
\ No newline at end of file
... ...
package com.aigeo.company.dto;
import com.aigeo.common.enums.CompanyStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 公司DTO
*/
@Data
@Schema(description = "公司数据传输对象")
public class CompanyDTO {
@Schema(description = "公司ID")
private Integer id;
@Schema(description = "公司名称")
private String name;
@Schema(description = "公司域名")
private String domain;
@Schema(description = "公司状态")
private CompanyStatus status;
@Schema(description = "试用到期日")
private LocalDateTime trialExpiryDate;
@Schema(description = "企业默认设置(JSON)")
private String defaultSettings;
@Schema(description = "账单邮箱")
private String billingEmail;
@Schema(description = "联系电话")
private String contactPhone;
@Schema(description = "公司地址")
private String address;
@Schema(description = "公司Logo URL")
private String logoUrl;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "最后更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
package com.aigeo.company.dto;
import com.aigeo.common.enums.UserRole;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 用户DTO
*/
@Data
@Schema(description = "用户数据传输对象")
public class UserDTO {
@Schema(description = "用户ID")
private Integer id;
@Schema(description = "所属公司ID")
private Integer companyId;
@Schema(description = "用户名")
private String username;
@Schema(description = "用户邮箱")
private String email;
@Schema(description = "用户全名")
private String fullName;
@Schema(description = "用户头像URL")
private String avatarUrl;
@Schema(description = "手机号")
private String phone;
@Schema(description = "用户角色")
private UserRole role;
@Schema(description = "是否启用")
private Boolean isActive;
@Schema(description = "最近登录时间")
private LocalDateTime lastLogin;
@Schema(description = "上次修改密码时间")
private LocalDateTime lastPasswordChange;
@Schema(description = "登录失败次数")
private Integer failedLoginAttempts;
@Schema(description = "锁定截止时间")
private LocalDateTime lockedUntil;
@Schema(description = "用户时区")
private String timezone;
@Schema(description = "用户个性化设置")
private String preferences;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "最后更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
/**
* 公司模块实体包
*/
package com.aigeo.company.entity;
\ No newline at end of file
... ...
/**
* 公司模块数据访问包
*/
package com.aigeo.company.repository;
\ No newline at end of file
... ...
package com.aigeo.company.service.impl;
import com.aigeo.common.enums.CompanyStatus;
import com.aigeo.company.entity.Company;
import com.aigeo.company.repository.CompanyRepository;
import com.aigeo.company.service.CompanyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 公司服务实现类
*/
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyRepository companyRepository;
@Override
public Company save(Company company) {
return companyRepository.save(company);
}
@Override
public Optional<Company> findById(Integer id) {
return companyRepository.findById(id);
}
@Override
public List<Company> findByStatus(CompanyStatus status) {
return companyRepository.findByStatus(status);
}
@Override
public List<Company> findByName(String name) {
return companyRepository.findByName(name);
}
@Override
public List<Company> findByDomain(String domain) {
return companyRepository.findByDomain(domain);
}
@Override
public List<Company> findAll() {
return companyRepository.findAll();
}
@Override
public void deleteById(Integer id) {
companyRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
package com.aigeo.company.service.impl;
import com.aigeo.common.enums.UserRole;
import com.aigeo.company.entity.User;
import com.aigeo.company.repository.UserRepository;
import com.aigeo.company.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 用户服务实现类
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User save(User user) {
return userRepository.save(user);
}
@Override
public Optional<User> findById(Integer id) {
return userRepository.findById(id);
}
@Override
public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}
@Override
public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email);
}
@Override
public List<User> findByCompanyId(Integer companyId) {
return userRepository.findByCompanyId(companyId);
}
@Override
public List<User> findActiveByCompanyId(Integer companyId) {
return userRepository.findByCompanyIdAndIsActiveTrue(companyId);
}
@Override
public List<User> findByRole(UserRole role) {
return userRepository.findByRole(role);
}
@Override
public List<User> findByCompanyIdAndRole(Integer companyId, UserRole role) {
return userRepository.findByCompanyIdAndRole(companyId, role);
}
@Override
public List<User> findAll() {
return userRepository.findAll();
}
@Override
public void deleteById(Integer id) {
userRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 公司模块业务逻辑包
*/
package com.aigeo.company.service;
\ No newline at end of file
... ...
package com.aigeo.config;
import com.aigeo.auth.service.CustomUserDetailsService;
import com.aigeo.util.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtUtil.getUsernameFromToken(jwtToken);
} catch (Exception e) {
logger.error("Unable to get JWT Token", e);
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// 创建一个临时User对象用于验证token
com.aigeo.company.entity.User tempUser = new com.aigeo.company.entity.User();
tempUser.setUsername(username);
if (jwtUtil.validateToken(jwtToken, tempUser)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}
\ No newline at end of file
... ...
package com.aigeo.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Knife4jConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("AIGEO API Documentation")
.version("1.0.0")
.description("AI Content Generation Platform API Documentation")
.contact(new Contact()
.name("AIGEO Team")
.url("https://www.aigeo.com")
.email("contact@aigeo.com"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html")))
.components(new Components()
.addSecuritySchemes("bearerAuth", new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")))
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"));
}
}
\ No newline at end of file
... ...
package com.aigeo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class QuartzConfig {
}
\ No newline at end of file
... ...
package com.aigeo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
/*
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
*/
}
\ No newline at end of file
... ...
package com.aigeo.config;
import com.aigeo.auth.service.CustomUserDetailsService;
import com.aigeo.config.JwtAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authz -> authz
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html",
"/doc.html", "/webjars/**", "/swagger-resources/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
\ No newline at end of file
... ...
package com.aigeo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
\ No newline at end of file
... ...
/**
* 关键词模块控制器包
*/
package com.aigeo.keyword.controller;
\ No newline at end of file
... ...
package com.aigeo.keyword.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 关键词DTO
*/
@Data
@Schema(description = "关键词数据传输对象")
public class KeywordDTO {
@Schema(description = "关键词ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "关键词文本")
private String keyword;
@Schema(description = "搜索量估算")
private Integer searchVolume;
@Schema(description = "估计每次点击成本")
private Double cpc;
@Schema(description = "关键词难度评分")
private Byte difficulty;
@Schema(description = "来源类型")
private String source;
@Schema(description = "关键词状态")
private String status;
@Schema(description = "关键词标签")
private String tags;
@Schema(description = "关键词被文章使用次数")
private Integer usageCount;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
package com.aigeo.keyword.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 话题DTO
*/
@Data
@Schema(description = "话题数据传输对象")
public class TopicDTO {
@Schema(description = "话题ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "来源任务ID")
private Integer sourceTaskId;
@Schema(description = "话题标题")
private String title;
@Schema(description = "话题描述")
private String description;
@Schema(description = "原始来源链接")
private String sourceUrl;
@Schema(description = "话题状态")
private String status;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
/**
* 关键词模块数据传输对象包
*/
package com.aigeo.keyword.dto;
\ No newline at end of file
... ...
/**
* 关键词模块实体包
*/
package com.aigeo.keyword.entity;
\ No newline at end of file
... ...
/**
* 关键词模块数据访问包
*/
package com.aigeo.keyword.repository;
\ No newline at end of file
... ...
package com.aigeo.keyword.service.impl;
import com.aigeo.keyword.entity.Keyword;
import com.aigeo.keyword.repository.KeywordRepository;
import com.aigeo.keyword.service.KeywordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 关键词服务实现类
*/
@Service
public class KeywordServiceImpl implements KeywordService {
@Autowired
private KeywordRepository keywordRepository;
@Override
public Keyword save(Keyword keyword) {
return keywordRepository.save(keyword);
}
@Override
public Optional<Keyword> findById(Integer id) {
return keywordRepository.findById(id);
}
@Override
public List<Keyword> findByCompanyId(Integer companyId) {
return keywordRepository.findByCompanyId(companyId);
}
@Override
public List<Keyword> findByKeyword(String keyword) {
return keywordRepository.findByKeyword(keyword);
}
@Override
public List<Keyword> findByCompanyIdAndKeyword(Integer companyId, String keyword) {
return keywordRepository.findByCompanyIdAndKeyword(companyId, keyword);
}
@Override
public List<Keyword> findByStatus(String status) {
return keywordRepository.findByStatus(status);
}
@Override
public List<Keyword> findByCompanyIdAndStatus(Integer companyId, String status) {
return keywordRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<Keyword> findByTagsContaining(String tag) {
return keywordRepository.findByTagsContaining(tag);
}
@Override
public List<Keyword> findAll() {
return keywordRepository.findAll();
}
@Override
public void deleteById(Integer id) {
keywordRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
package com.aigeo.keyword.service.impl;
import com.aigeo.keyword.entity.Topic;
import com.aigeo.keyword.repository.TopicRepository;
import com.aigeo.keyword.service.TopicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 话题服务实现类
*/
@Service
public class TopicServiceImpl implements TopicService {
@Autowired
private TopicRepository topicRepository;
@Override
public Topic save(Topic topic) {
return topicRepository.save(topic);
}
@Override
public Optional<Topic> findById(Integer id) {
return topicRepository.findById(id);
}
@Override
public List<Topic> findByCompanyId(Integer companyId) {
return topicRepository.findByCompanyId(companyId);
}
@Override
public List<Topic> findBySourceTaskId(Integer sourceTaskId) {
return topicRepository.findBySourceTaskId(sourceTaskId);
}
@Override
public List<Topic> findByTitle(String title) {
return topicRepository.findByTitle(title);
}
@Override
public List<Topic> findByCompanyIdAndTitle(Integer companyId, String title) {
return topicRepository.findByCompanyIdAndTitle(companyId, title);
}
@Override
public List<Topic> findByStatus(String status) {
return topicRepository.findByStatus(status);
}
@Override
public List<Topic> findByCompanyIdAndStatus(Integer companyId, String status) {
return topicRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<Topic> findAll() {
return topicRepository.findAll();
}
@Override
public void deleteById(Integer id) {
topicRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 关键词模块业务逻辑包
*/
package com.aigeo.keyword.service;
\ No newline at end of file
... ...
package com.aigeo.landingpage.controller;
import com.aigeo.landingpage.entity.LandingPageProject;
import com.aigeo.landingpage.service.LandingPageProjectService;
import com.aigeo.common.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 落地页项目控制器
*/
@Slf4j
@RestController
@RequestMapping("/api/landing-page-projects")
@Tag(name = "落地页项目管理", description = "落地页项目相关接口")
public class LandingPageProjectController {
@Autowired
private LandingPageProjectService landingPageProjectService;
@PostMapping
@Operation(summary = "创建落地页项目", description = "创建新的落地页项目")
public Result<LandingPageProject> createProject(@RequestBody LandingPageProject project) {
try {
LandingPageProject savedProject = landingPageProjectService.save(project);
return Result.success("项目创建成功", savedProject);
} catch (Exception e) {
log.error("创建落地页项目失败", e);
return Result.error("项目创建失败");
}
}
@GetMapping("/{id}")
@Operation(summary = "获取落地页项目详情", description = "根据ID获取落地页项目详情")
public Result<LandingPageProject> getProjectById(@PathVariable Integer id) {
try {
return landingPageProjectService.findById(id)
.map(project -> Result.success("查询成功", project))
.orElse(Result.error("项目不存在"));
} catch (Exception e) {
log.error("获取落地页项目详情失败, id: {}", id, e);
return Result.error("查询失败");
}
}
@GetMapping
@Operation(summary = "获取落地页项目列表", description = "获取所有落地页项目列表")
public Result<List<LandingPageProject>> getAllProjects() {
try {
List<LandingPageProject> projects = landingPageProjectService.findAll();
return Result.success("查询成功", projects);
} catch (Exception e) {
log.error("获取落地页项目列表失败", e);
return Result.error("查询失败");
}
}
@GetMapping("/company/{companyId}")
@Operation(summary = "根据公司ID获取落地页项目列表", description = "根据公司ID获取落地页项目列表")
public Result<List<LandingPageProject>> getProjectsByCompanyId(@PathVariable Integer companyId) {
try {
List<LandingPageProject> projects = landingPageProjectService.findByCompanyId(companyId);
return Result.success("查询成功", projects);
} catch (Exception e) {
log.error("根据公司ID获取落地页项目列表失败, companyId: {}", companyId, e);
return Result.error("查询失败");
}
}
@GetMapping("/user/{userId}")
@Operation(summary = "根据用户ID获取落地页项目列表", description = "根据用户ID获取落地页项目列表")
public Result<List<LandingPageProject>> getProjectsByUserId(@PathVariable Integer userId) {
try {
List<LandingPageProject> projects = landingPageProjectService.findByUserId(userId);
return Result.success("查询成功", projects);
} catch (Exception e) {
log.error("根据用户ID获取落地页项目列表失败, userId: {}", userId, e);
return Result.error("查询失败");
}
}
@GetMapping("/status/{status}")
@Operation(summary = "根据状态获取落地页项目列表", description = "根据状态获取落地页项目列表")
public Result<List<LandingPageProject>> getProjectsByStatus(@PathVariable String status) {
try {
LandingPageProject.ProjectStatus projectStatus = LandingPageProject.ProjectStatus.fromCode(status);
List<LandingPageProject> projects = landingPageProjectService.findByStatus(projectStatus);
return Result.success("查询成功", projects);
} catch (Exception e) {
log.error("根据状态获取落地页项目列表失败, status: {}", status, e);
return Result.error("查询失败");
}
}
@PutMapping("/{id}")
@Operation(summary = "更新落地页项目", description = "更新落地页项目信息")
public Result<LandingPageProject> updateProject(@PathVariable Integer id, @RequestBody LandingPageProject project) {
try {
if (!landingPageProjectService.findById(id).isPresent()) {
return Result.error("项目不存在");
}
project.setId(id);
LandingPageProject updatedProject = landingPageProjectService.save(project);
return Result.success("项目更新成功", updatedProject);
} catch (Exception e) {
log.error("更新落地页项目失败, id: {}", id, e);
return Result.error("项目更新失败");
}
}
@DeleteMapping("/{id}")
@Operation(summary = "删除落地页项目", description = "删除指定ID的落地页项目")
public Result<String> deleteProject(@PathVariable Integer id) {
try {
if (!landingPageProjectService.findById(id).isPresent()) {
return Result.error("项目不存在");
}
landingPageProjectService.deleteById(id);
return Result.success("项目删除成功");
} catch (Exception e) {
log.error("删除落地页项目失败, id: {}", id, e);
return Result.error("项目删除失败");
}
}
}
\ No newline at end of file
... ...
/**
* 落地页模块控制器包
*/
package com.aigeo.landingpage.controller;
\ No newline at end of file
... ...
package com.aigeo.landingpage.dto;
import com.aigeo.landingpage.entity.LandingPageProject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import java.time.LocalDateTime;
/**
* 落地页项目DTO
*/
@Data
@Schema(description = "落地页项目DTO")
public class LandingPageProjectDTO {
@Schema(description = "项目ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "项目名称")
private String name;
@Schema(description = "域名")
private String domain;
@Schema(description = "状态")
private String status;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
/**
* 将DTO转换为实体类
*/
public LandingPageProject toEntity() {
LandingPageProject entity = new LandingPageProject();
BeanUtils.copyProperties(this, entity);
return entity;
}
/**
* 将实体类转换为DTO
*/
public static LandingPageProjectDTO fromEntity(LandingPageProject entity) {
LandingPageProjectDTO dto = new LandingPageProjectDTO();
BeanUtils.copyProperties(entity, dto);
return dto;
}
}
\ No newline at end of file
... ...
/**
* 落地页模块实体包
*/
package com.aigeo.landingpage.entity;
\ No newline at end of file
... ...
/**
* 落地页模块数据访问包
*/
package com.aigeo.landingpage.repository;
\ No newline at end of file
... ...
package com.aigeo.landingpage.service.impl;
import com.aigeo.landingpage.entity.LandingPageProject;
import com.aigeo.landingpage.repository.LandingPageProjectRepository;
import com.aigeo.landingpage.service.LandingPageProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 落地页项目服务实现类
*/
@Service
public class LandingPageProjectServiceImpl implements LandingPageProjectService {
@Autowired
private LandingPageProjectRepository landingPageProjectRepository;
@Override
public LandingPageProject save(LandingPageProject project) {
return landingPageProjectRepository.save(project);
}
@Override
public Optional<LandingPageProject> findById(Integer id) {
return landingPageProjectRepository.findById(id);
}
@Override
public List<LandingPageProject> findByCompanyId(Integer companyId) {
return landingPageProjectRepository.findByCompanyId(companyId);
}
@Override
public List<LandingPageProject> findByUserId(Integer userId) {
return landingPageProjectRepository.findByUserId(userId);
}
@Override
public List<LandingPageProject> findByStatus(LandingPageProject.ProjectStatus status) {
return landingPageProjectRepository.findByStatus(status);
}
@Override
public List<LandingPageProject> findByCompanyIdAndStatus(Integer companyId, LandingPageProject.ProjectStatus status) {
return landingPageProjectRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<LandingPageProject> findByUserIdAndStatus(Integer userId, LandingPageProject.ProjectStatus status) {
return landingPageProjectRepository.findByUserIdAndStatus(userId, status);
}
@Override
public List<LandingPageProject> findAll() {
return landingPageProjectRepository.findAll();
}
@Override
public void deleteById(Integer id) {
landingPageProjectRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 落地页模块业务逻辑包
*/
package com.aigeo.landingpage.service;
\ No newline at end of file
... ...
/**
* 平台模块控制器包
*/
package com.aigeo.platform.controller;
\ No newline at end of file
... ...
package com.aigeo.platform.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 发布平台DTO
*/
@Data
@Schema(description = "发布平台数据传输对象")
public class PublishingPlatformDTO {
@Schema(description = "平台ID")
private Integer id;
@Schema(description = "平台类型ID")
private Integer typeId;
@Schema(description = "平台名称")
private String name;
@Schema(description = "平台代码")
private String code;
@Schema(description = "平台描述")
private String description;
@Schema(description = "平台图标")
private String icon;
@Schema(description = "认证类型")
private String authType;
@Schema(description = "API配置模板")
private String apiConfigTemplate;
@Schema(description = "字符限制")
private Integer characterLimit;
@Schema(description = "是否启用")
private Boolean isActive;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
/**
* 平台模块数据传输对象包
*/
package com.aigeo.platform.dto;
\ No newline at end of file
... ...
/**
* 平台模块实体包
*/
package com.aigeo.platform.entity;
\ No newline at end of file
... ...
/**
* 平台模块数据访问包
*/
package com.aigeo.platform.repository;
\ No newline at end of file
... ...
package com.aigeo.platform.service.impl;
import com.aigeo.platform.entity.PublishingPlatform;
import com.aigeo.platform.repository.PublishingPlatformRepository;
import com.aigeo.platform.service.PublishingPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 发布平台服务实现类
*/
@Service
public class PublishingPlatformServiceImpl implements PublishingPlatformService {
@Autowired
private PublishingPlatformRepository publishingPlatformRepository;
@Override
public PublishingPlatform save(PublishingPlatform platform) {
return publishingPlatformRepository.save(platform);
}
@Override
public Optional<PublishingPlatform> findById(Integer id) {
return publishingPlatformRepository.findById(id);
}
@Override
public List<PublishingPlatform> findByTypeId(Integer typeId) {
return publishingPlatformRepository.findByTypeId(typeId);
}
@Override
public List<PublishingPlatform> findActivePlatforms() {
return publishingPlatformRepository.findByIsActiveTrue();
}
@Override
public List<PublishingPlatform> findActiveByTypeId(Integer typeId) {
return publishingPlatformRepository.findByTypeIdAndIsActiveTrue(typeId);
}
@Override
public PublishingPlatform findByCode(String code) {
return publishingPlatformRepository.findByCode(code);
}
@Override
public List<PublishingPlatform> findAll() {
return publishingPlatformRepository.findAll();
}
@Override
public void deleteById(Integer id) {
publishingPlatformRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 平台模块业务逻辑包
*/
package com.aigeo.platform.service;
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.article.entity.ArticleGenerationTask;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ArticleGenerationTaskRepository extends JpaRepository<ArticleGenerationTask, Integer> {
List<ArticleGenerationTask> findByCompanyId(Integer companyId);
List<ArticleGenerationTask> findByCompanyIdAndStatus(Integer companyId, String status);
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.company.entity.Company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface CompanyRepository extends JpaRepository<Company, Integer> {
Optional<Company> findByName(String name);
Optional<Company> findByDomain(String domain);
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.ai.entity.DifyApiConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface DifyApiConfigRepository extends JpaRepository<DifyApiConfig, Integer> {
List<DifyApiConfig> findByCompanyId(Integer companyId);
List<DifyApiConfig> findByCompanyIdAndIsActiveTrue(Integer companyId);
Optional<DifyApiConfig> findByCompanyIdAndIsActiveTrueOrderByCreatedAtDesc(Integer companyId);
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.ai.entity.Feature;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface FeatureRepository extends JpaRepository<Feature, Integer> {
List<Feature> findByIsActiveTrue();
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.article.entity.GeneratedArticle;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface GeneratedArticleRepository extends JpaRepository<GeneratedArticle, Integer> {
List<GeneratedArticle> findByTaskId(Integer taskId);
List<GeneratedArticle> findByCompanyId(Integer companyId);
List<GeneratedArticle> findByCompanyIdAndStatus(Integer companyId, String status);
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.landingpage.entity.LandingPageProject;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface LandingPageProjectRepository extends JpaRepository<LandingPageProject, Integer> {
List<LandingPageProject> findByCompanyId(Integer companyId);
List<LandingPageProject> findByCompanyIdAndStatus(Integer companyId, String status);
}
\ No newline at end of file
... ...
package com.aigeo.repository;
import com.aigeo.company.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
\ No newline at end of file
... ...
package com.aigeo.util;
import com.aigeo.company.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* JWT工具类
*/
@Component
public class JwtUtil {
@Value("${jwt.secret:mySecretKeyForAigeoApplicationWhichIsLongEnough}")
private String secret;
@Value("${jwt.expiration:86400}")
private Long expiration;
/**
* 获取签名密钥
*/
private SecretKey getSigningKey() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
return Keys.hmacShaKeyFor(keyBytes);
}
/**
* 从token中获取用户名
*/
public String getUsernameFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getSubject();
}
/**
* 从token中提取用户名(别名方法)
*/
public String extractUsername(String token) {
return getUsernameFromToken(token);
}
/**
* 从token中获取Claims
*/
private Claims getClaimsFromToken(String token) {
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
/**
* 检查token是否过期
*/
private boolean isTokenExpired(String token) {
Date expiredDate = getClaimsFromToken(token).getExpiration();
return expiredDate.before(new Date());
}
public Date extractExpiration(String token) {
return getClaimsFromToken(token).getExpiration();
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getClaimsFromToken(token);
return claimsResolver.apply(claims);
}
public String generateToken(User user) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, user.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.claims(claims)
.subject(subject)
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(getSigningKey())
.compact();
}
public Boolean validateToken(String token, User user) {
if (user == null) {
return false;
}
final String username = getUsernameFromToken(token);
return (username.equals(user.getUsername()) && !isTokenExpired(token));
}
/**
* 获取过期时间(秒)
*/
public Long getExpirationTimeSeconds() {
return expiration;
}
/**
* 获取过期时间(毫秒)
*/
public Long getExpirationTime() {
return expiration * 1000;
}
}
\ No newline at end of file
... ...
/**
* 网站模块控制器包
*/
package com.aigeo.website.controller;
\ No newline at end of file
... ...
package com.aigeo.website.dto;
import com.aigeo.website.entity.WebsiteProject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 网站项目DTO
*/
@Data
@Schema(description = "网站项目数据传输对象")
public class WebsiteProjectDTO {
@Schema(description = "项目ID")
private Integer id;
@Schema(description = "公司ID")
private Integer companyId;
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "网站名称")
private String siteName;
@Schema(description = "项目状态")
private WebsiteProject.ProjectStatus status;
@Schema(description = "创建时间")
private LocalDateTime createdAt;
@Schema(description = "最后更新时间")
private LocalDateTime updatedAt;
}
\ No newline at end of file
... ...
/**
* 网站模块数据传输对象包
*/
package com.aigeo.website.dto;
\ No newline at end of file
... ...
/**
* 网站模块实体包
*/
package com.aigeo.website.entity;
\ No newline at end of file
... ...
/**
* 网站模块数据访问包
*/
package com.aigeo.website.repository;
\ No newline at end of file
... ...
package com.aigeo.website.service.impl;
import com.aigeo.website.entity.WebsiteProject;
import com.aigeo.website.repository.WebsiteProjectRepository;
import com.aigeo.website.service.WebsiteProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 网站项目服务实现类
*/
@Service
public class WebsiteProjectServiceImpl implements WebsiteProjectService {
@Autowired
private WebsiteProjectRepository websiteProjectRepository;
@Override
public WebsiteProject save(WebsiteProject project) {
return websiteProjectRepository.save(project);
}
@Override
public Optional<WebsiteProject> findById(Integer id) {
return websiteProjectRepository.findById(id);
}
@Override
public List<WebsiteProject> findByCompanyId(Integer companyId) {
return websiteProjectRepository.findByCompanyId(companyId);
}
@Override
public List<WebsiteProject> findByUserId(Integer userId) {
return websiteProjectRepository.findByUserId(userId);
}
@Override
public List<WebsiteProject> findByStatus(WebsiteProject.ProjectStatus status) {
return websiteProjectRepository.findByStatus(status);
}
@Override
public List<WebsiteProject> findByCompanyIdAndStatus(Integer companyId, WebsiteProject.ProjectStatus status) {
return websiteProjectRepository.findByCompanyIdAndStatus(companyId, status);
}
@Override
public List<WebsiteProject> findByUserIdAndStatus(Integer userId, WebsiteProject.ProjectStatus status) {
return websiteProjectRepository.findByUserIdAndStatus(userId, status);
}
@Override
public List<WebsiteProject> findAll() {
return websiteProjectRepository.findAll();
}
@Override
public void deleteById(Integer id) {
websiteProjectRepository.deleteById(id);
}
}
\ No newline at end of file
... ...
/**
* 网站模块业务逻辑包
*/
package com.aigeo.website.service;
\ No newline at end of file
... ...
server:
port: 8080
servlet:
context-path: /api
encoding:
charset: UTF-8
enabled: true
force: true
spring:
profiles:
active: dev
application:
name: aigeo
main:
allow-bean-definition-overriding: true
# 数据库配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://115.175.226.205:33062/ai_3?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: sz1234567890
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: HikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# JPA配置
jpa:
hibernate:
ddl-auto: none
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
use_sql_comments: false
open-in-view: false
# Redis配置
data:
redis:
host: 115.175.226.205
port: 6379
database: 0
password: sz123321
timeout: 3000
jedis:
pool:
max-active: 20
max-wait: -1
max-idle: 10
min-idle: 0
# JSON配置
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
default-property-inclusion: NON_NULL
serialization:
write-dates-as-timestamps: false
write-date-timestamps-as-nanoseconds: false
deserialization:
read-date-timestamps-as-nanoseconds: false
# 文件上传配置
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
enabled: true
# 定时任务配置
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: never
properties:
org:
quartz:
scheduler:
instanceName: AigeoScheduler
instanceId: AUTO
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_
isClustered: false
useProperties: false
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
# Security配置
security:
user:
name: admin
password: admin123
sql:
init:
data-locations:
mode:
schema-locations:
# MyBatis Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
# SpringDoc配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/**'
packages-to-scan: com.aigeo
# Knife4j配置
knife4j:
enable: true
production: false
basic:
enable: false
setting:
language: zh_cn
\ No newline at end of file
... ...
-- 初始化数据脚本
-- 插入默认公司
INSERT INTO ai_companies (name, status, created_at, updated_at)
VALUES ('Default Company', 'active', NOW(), NOW());
-- 插入默认用户 (密码为 "password" 的BCrypt哈希)
INSERT INTO ai_users (company_id, username, email, password_hash, role, is_active, created_at, updated_at)
VALUES (1, 'admin', 'admin@aigeo.com', '$2a$10$wQ8vI6jJ2x6Dit4G3E0jVOvH9JqKz3Zs5r1D4r6H7a8B9c0D1e2F3g4', 'admin', 1, NOW(), NOW());
-- 插入AI功能模块
INSERT INTO ai_features (feature_key, name, description, category, is_premium, sort_order, is_active, created_at)
VALUES
('ai_article', 'AI文章生成', '基于关键词和主题自动生成高质量文章', 'content', 0, 1, 1, NOW()),
('ai_landing_page', 'AI落地页生成', '根据业务需求自动生成营销落地页', 'marketing', 0, 2, 1, NOW()),
('ai_website', 'AI网站生成', '一键生成企业官网或电商网站', 'website', 1, 3, 1, NOW());
-- 插入文章类型
INSERT INTO ai_article_types (name, description, is_active, created_at, updated_at)
VALUES
('产品介绍', '产品介绍类文章', 1, NOW(), NOW()),
('新闻稿', '企业新闻稿', 1, NOW(), NOW()),
('博客文章', '技术博客或行业分析文章', 1, NOW(), NOW());
-- 插入落地页模板
INSERT INTO ai_landing_page_templates (name, code, description, is_active, created_at, updated_at)
VALUES
('单栏布局', 'single-column', '简洁的单栏布局模板', 1, NOW(), NOW()),
('两栏布局', 'two-column', '经典的两栏布局模板', 1, NOW(), NOW()),
('产品展示', 'product-showcase', '专注于产品展示的模板', 1, NOW(), NOW());
\ No newline at end of file
... ...
-- 数据库模式初始化脚本
-- ====================================================================================================
-- 1) 核心:公司、用户、权限、订阅
-- ====================================================================================================
-- 创建公司表(多租户根)
CREATE TABLE IF NOT EXISTS `ai_companies` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '公司主键ID',
`name` VARCHAR(255) NOT NULL COMMENT '公司名称',
`domain` VARCHAR(100) DEFAULT NULL COMMENT '公司域名,用于多租户访问',
`status` ENUM('active','suspended','trial') DEFAULT 'trial' COMMENT '公司状态',
`trial_expiry_date` DATE DEFAULT NULL COMMENT '试用到期日',
`default_settings` JSON DEFAULT NULL COMMENT '企业默认设置(JSON)',
`billing_email` VARCHAR(100) DEFAULT NULL COMMENT '账单邮箱',
`contact_phone` VARCHAR(20) DEFAULT NULL COMMENT '联系电话',
`address` TEXT DEFAULT NULL COMMENT '公司地址',
`logo_url` VARCHAR(255) DEFAULT NULL COMMENT '公司Logo URL',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_companies_domain` (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司表(多租户根)';
-- 创建用户表
CREATE TABLE IF NOT EXISTS `ai_users` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`email` VARCHAR(100) NOT NULL COMMENT '邮箱',
`password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
`full_name` VARCHAR(100) DEFAULT NULL COMMENT '用户全名',
`phone` VARCHAR(20) DEFAULT NULL COMMENT '联系电话',
`role` ENUM('admin','editor','viewer') DEFAULT 'editor' COMMENT '用户角色',
`avatar_url` VARCHAR(255) DEFAULT NULL COMMENT '头像URL',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`last_login_at` TIMESTAMP NULL DEFAULT NULL COMMENT '最后登录时间',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_users_username` (`username`),
UNIQUE KEY `uk_users_email` (`email`),
KEY `idx_users_company_id` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
-- 创建AI功能表
CREATE TABLE IF NOT EXISTS `ai_features` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '功能主键ID',
`feature_key` VARCHAR(50) NOT NULL COMMENT '功能标识符',
`name` VARCHAR(100) NOT NULL COMMENT '功能名称',
`description` TEXT DEFAULT NULL COMMENT '功能描述',
`category` VARCHAR(50) DEFAULT NULL COMMENT '功能分类',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`config_schema` JSON DEFAULT NULL COMMENT '配置Schema(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_features_key` (`feature_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI功能表';
-- 创建AI配置表
CREATE TABLE IF NOT EXISTS `ai_dify_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`name` VARCHAR(100) NOT NULL COMMENT '配置名称',
`provider` ENUM('dify','openai','azure','custom') NOT NULL COMMENT 'API提供商',
`api_key` VARCHAR(255) NOT NULL COMMENT 'API密钥',
`api_endpoint` VARCHAR(255) DEFAULT NULL COMMENT 'API端点',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`model_settings` JSON DEFAULT NULL COMMENT '模型设置(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_dify_configs_company_id` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI配置表';
-- 创建文章生成任务表
CREATE TABLE IF NOT EXISTS `article_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`user_id` INT NOT NULL COMMENT '关联用户ID',
`name` VARCHAR(255) NOT NULL COMMENT '任务名称',
`topic` VARCHAR(255) DEFAULT NULL COMMENT '主题',
`keywords` TEXT DEFAULT NULL COMMENT '关键词',
`article_count` INT DEFAULT 1 COMMENT '文章数量',
`platform_type` VARCHAR(50) DEFAULT NULL COMMENT '平台类型',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`settings` JSON DEFAULT NULL COMMENT '生成设置(JSON)',
`result_summary` JSON DEFAULT NULL COMMENT '结果摘要(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_tasks_company_id` (`company_id`),
KEY `idx_tasks_user_id` (`user_id`),
KEY `idx_tasks_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章生成任务表';
-- 创建生成文章表
CREATE TABLE IF NOT EXISTS `generated_articles` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章主键ID',
`task_id` INT NOT NULL COMMENT '关联任务ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`title` VARCHAR(255) NOT NULL COMMENT '文章标题',
`content` LONGTEXT NOT NULL COMMENT '文章内容',
`status` ENUM('draft','selected','published') DEFAULT 'draft' COMMENT '文章状态',
`version` INT DEFAULT 1 COMMENT '版本号',
`is_selected` TINYINT(1) DEFAULT 0 COMMENT '是否选中',
`metadata` JSON DEFAULT NULL COMMENT '元数据(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_articles_task_id` (`task_id`),
KEY `idx_articles_company_id` (`company_id`),
KEY `idx_articles_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成文章表';
-- 创建落地页项目表
CREATE TABLE IF NOT EXISTS `landing_page_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '项目主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`user_id` INT NOT NULL COMMENT '关联用户ID',
`name` VARCHAR(255) NOT NULL COMMENT '项目名称',
`description` TEXT DEFAULT NULL COMMENT '项目描述',
`industry` VARCHAR(100) DEFAULT NULL COMMENT '行业',
`status` ENUM('draft','generating','completed','published') DEFAULT 'draft' COMMENT '项目状态',
`settings` JSON DEFAULT NULL COMMENT '项目设置(JSON)',
`result_summary` JSON DEFAULT NULL COMMENT '结果摘要(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_landing_projects_company_id` (`company_id`),
KEY `idx_landing_projects_user_id` (`user_id`),
KEY `idx_landing_projects_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页项目表';
-- 创建网站项目表
CREATE TABLE IF NOT EXISTS `website_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '项目主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`user_id` INT NOT NULL COMMENT '关联用户ID',
`name` VARCHAR(255) NOT NULL COMMENT '项目名称',
`description` TEXT DEFAULT NULL COMMENT '项目描述',
`industry` VARCHAR(100) DEFAULT NULL COMMENT '行业',
`status` ENUM('draft','generating','completed','published') DEFAULT 'draft' COMMENT '项目状态',
`settings` JSON DEFAULT NULL COMMENT '项目设置(JSON)',
`result_summary` JSON DEFAULT NULL COMMENT '结果摘要(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_website_projects_company_id` (`company_id`),
KEY `idx_website_projects_user_id` (`user_id`),
KEY `idx_website_projects_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站项目表';
-- 创建发布平台表
CREATE TABLE IF NOT EXISTS `publishing_platforms` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '平台主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`name` VARCHAR(100) NOT NULL COMMENT '平台名称',
`type` VARCHAR(50) NOT NULL COMMENT '平台类型',
`config` JSON NOT NULL COMMENT '平台配置(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_platforms_company_id` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='发布平台表';
-- 创建关键词表
CREATE TABLE IF NOT EXISTS `keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`keyword` VARCHAR(255) NOT NULL COMMENT '关键词',
`search_volume` INT DEFAULT NULL COMMENT '搜索量',
`competition` ENUM('low','medium','high') DEFAULT NULL COMMENT '竞争度',
`trend_data` JSON DEFAULT NULL COMMENT '趋势数据(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_keywords_company_keyword` (`company_id`, `keyword`),
KEY `idx_keywords_company_id` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关键词表';
-- 创建主题表
CREATE TABLE IF NOT EXISTS `topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '主题主键ID',
`company_id` INT NOT NULL COMMENT '关联公司ID',
`name` VARCHAR(255) NOT NULL COMMENT '主题名称',
`description` TEXT DEFAULT NULL COMMENT '主题描述',
`related_keywords` JSON DEFAULT NULL COMMENT '相关关键词(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_topics_company_id` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='主题表';
-- ====================================================================================================
-- 2) 订阅与计费系统
-- ====================================================================================================
-- 订阅计划定义表
-- 定义可用的订阅计划及其基本属性。
CREATE TABLE `ai_subscription_plans` (
`id` INT NOT NULL AUTO_INCREMENT,
`plan_key` VARCHAR(50) NOT NULL COMMENT '计划标识符(如 free, basic, premium)',
`name` VARCHAR(100) NOT NULL COMMENT '计划显示名称',
`description` TEXT DEFAULT NULL COMMENT '计划描述',
`price_monthly` DECIMAL(10,2) DEFAULT 0.00 COMMENT '月费价格',
`price_yearly` DECIMAL(10,2) DEFAULT 0.00 COMMENT '年费价格',
`max_users` INT DEFAULT 1 COMMENT '最大用户数',
`max_storage_mb` INT DEFAULT 100 COMMENT '最大存储空间(MB)',
`max_api_calls_per_day` INT DEFAULT 1000 COMMENT '每日API调用限制',
`features` JSON DEFAULT NULL COMMENT '包含的功能列表(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`sort_order` INT DEFAULT 0 COMMENT '排序权重',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plans_plan_key` (`plan_key`),
KEY `idx_plans_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅计划定义表';
-- 公司订阅记录表
-- 记录每个公司的订阅历史和当前状态。
CREATE TABLE `ai_company_subscriptions` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`plan_id` INT NOT NULL COMMENT '订阅计划ID',
`plan_key` VARCHAR(50) NOT NULL COMMENT '冗余字段:计划标识符',
`subscription_type` ENUM('monthly','yearly') DEFAULT 'monthly' COMMENT '订阅类型',
`status` ENUM('active','cancelled','expired','suspended') DEFAULT 'active' COMMENT '订阅状态',
`start_date` DATE NOT NULL COMMENT '订阅开始日期',
`end_date` DATE DEFAULT NULL COMMENT '订阅结束日期',
`next_billing_date` DATE DEFAULT NULL COMMENT '下次计费日期',
`trial_start_date` DATE DEFAULT NULL COMMENT '试用开始日期',
`trial_end_date` DATE DEFAULT NULL COMMENT '试用结束日期',
`amount` DECIMAL(10,2) DEFAULT 0.00 COMMENT '订阅金额',
`payment_method` VARCHAR(50) DEFAULT NULL COMMENT '支付方式',
`payment_status` ENUM('pending','paid','failed','refunded') DEFAULT 'pending' COMMENT '支付状态',
`auto_renew` TINYINT(1) DEFAULT 1 COMMENT '是否自动续费',
`cancel_reason` TEXT DEFAULT NULL COMMENT '取消原因',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_subscriptions_company` (`company_id`),
KEY `idx_subscriptions_status` (`status`),
KEY `idx_subscriptions_next_billing` (`next_billing_date`),
CONSTRAINT `fk_subscription_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_subscription_plan` FOREIGN KEY (`plan_id`) REFERENCES `ai_subscription_plans` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公司订阅记录表';
-- 订阅支付记录表
-- 记录具体的支付交易。
CREATE TABLE `ai_subscription_payments` (
`id` INT NOT NULL AUTO_INCREMENT,
`subscription_id` INT NOT NULL COMMENT '订阅ID',
`company_id` INT NOT NULL COMMENT '公司ID',
`amount` DECIMAL(10,2) NOT NULL COMMENT '支付金额',
`currency` VARCHAR(3) DEFAULT 'CNY' COMMENT '货币类型',
`payment_method` VARCHAR(50) DEFAULT NULL COMMENT '支付方式(如 alipay, wechat, stripe)',
`transaction_id` VARCHAR(255) DEFAULT NULL COMMENT '交易ID',
`payment_status` ENUM('pending','success','failed','refunded') DEFAULT 'pending' COMMENT '支付状态',
`payment_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '支付时间',
`period_start` DATE DEFAULT NULL COMMENT '计费周期开始日期',
`period_end` DATE DEFAULT NULL COMMENT '计费周期结束日期',
`invoice_url` VARCHAR(500) DEFAULT NULL COMMENT '发票URL',
`failure_reason` TEXT DEFAULT NULL COMMENT '失败原因',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_payments_company` (`company_id`),
KEY `idx_payments_subscription` (`subscription_id`),
KEY `idx_payments_status` (`payment_status`),
CONSTRAINT `fk_payment_subscription` FOREIGN KEY (`subscription_id`) REFERENCES `ai_company_subscriptions` (`id`),
CONSTRAINT `fk_payment_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅支付记录表';
-- ====================================================================================================
-- 3) AI功能模块与权限控制
-- ====================================================================================================
-- AI功能模块定义表
-- 定义系统提供的所有AI功能模块。
CREATE TABLE `ai_features` (
`id` INT NOT NULL AUTO_INCREMENT,
`feature_key` VARCHAR(50) NOT NULL COMMENT '功能标识符 (如 ai_copywriting, ai_landing_page)',
`name` VARCHAR(100) NOT NULL COMMENT '功能名称',
`description` TEXT DEFAULT NULL COMMENT '功能描述',
`category` VARCHAR(50) DEFAULT NULL COMMENT '功能分类(如 content, marketing, website)',
`is_premium` TINYINT(1) DEFAULT 0 COMMENT '是否为高级功能',
`sort_order` INT DEFAULT 0 COMMENT '排序权重',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_features_key` (`feature_key`),
KEY `idx_features_category` (`category`),
KEY `idx_features_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI功能模块定义表';
-- 订阅计划功能权限表
-- 定义每个订阅计划对各AI功能的访问权限和使用限制。
CREATE TABLE `ai_plan_features` (
`id` INT NOT NULL AUTO_INCREMENT,
`plan_id` INT NOT NULL COMMENT '订阅计划ID',
`feature_id` INT NOT NULL COMMENT '功能ID',
`is_allowed` TINYINT(1) DEFAULT 1 COMMENT '是否允许使用',
`usage_limit` INT DEFAULT NULL COMMENT '使用限制(如每月次数,NULL为无限制)',
`limit_period` ENUM('daily','monthly','yearly','total') DEFAULT 'monthly' COMMENT '限制周期',
`custom_config` JSON DEFAULT NULL COMMENT '自定义配置(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plan_feature` (`plan_id`, `feature_id`),
CONSTRAINT `fk_planfeature_plan` FOREIGN KEY (`plan_id`) REFERENCES `ai_subscription_plans` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_planfeature_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅计划功能权限表';
-- 功能使用记录表
-- 记录用户对公司功能的具体使用情况,用于计费和分析。
CREATE TABLE `ai_feature_usage` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`user_id` INT DEFAULT NULL COMMENT '用户ID(可选)',
`feature_id` INT NOT NULL COMMENT '功能ID',
`usage_type` VARCHAR(50) DEFAULT NULL COMMENT '使用类型(如 generate, export, analyze)',
`usage_count` INT DEFAULT 1 COMMENT '使用次数',
`related_resource_id` VARCHAR(100) DEFAULT NULL COMMENT '相关资源ID(如文章ID、页面ID)',
`ip_address` VARCHAR(45) DEFAULT NULL COMMENT '客户端IP',
`user_agent` TEXT DEFAULT NULL COMMENT '用户代理',
`metadata` JSON DEFAULT NULL COMMENT '额外元数据',
`used_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '使用时间',
PRIMARY KEY (`id`),
KEY `idx_usage_company_feature` (`company_id`, `feature_id`),
KEY `idx_usage_feature_date` (`feature_id`, `used_at`),
KEY `idx_usage_user` (`user_id`),
CONSTRAINT `fk_usage_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_usage_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='功能使用记录表';
-- 功能使用统计表(用于快速查询)
-- 按日统计功能使用量,提高查询效率。
CREATE TABLE `ai_feature_usage_stats` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT NOT NULL COMMENT '公司ID',
`feature_id` INT NOT NULL COMMENT '功能ID',
`stat_date` DATE NOT NULL COMMENT '统计日期',
`usage_count` INT DEFAULT 0 COMMENT '当日使用次数',
`last_used_at` TIMESTAMP DEFAULT NULL COMMENT '最后使用时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_stats_company_feature_date` (`company_id`, `feature_id`, `stat_date`),
KEY `idx_stats_company` (`company_id`),
KEY `idx_stats_feature` (`feature_id`),
CONSTRAINT `fk_stats_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_stats_feature` FOREIGN KEY (`feature_id`) REFERENCES `ai_features` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='功能使用统计表';
-- ====================================================================================================
-- 4) AI内容生成核心:模型、Prompt、文件
-- ====================================================================================================
-- AI服务配置表
-- 存储连接到不同AI服务(如Dify, OpenAI)的配置信息。
CREATE TABLE `ai_dify_api_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'AI配置主键ID',
`company_id` INT DEFAULT NULL COMMENT '公司ID(NULL 表示共享/通用)',
`provider` ENUM('dify','openai','anthropic','google','azure_openai','other') DEFAULT 'dify' COMMENT 'AI 提供方',
`name` VARCHAR(100) NOT NULL COMMENT '配置名称(便于识别)',
`base_url` VARCHAR(255) DEFAULT NULL COMMENT 'API 基础地址(可选)',
`api_key` VARCHAR(255) DEFAULT NULL COMMENT 'API Key/Token',
`model_name` VARCHAR(100) DEFAULT NULL COMMENT '模型名称',
`temperature` DECIMAL(3,2) DEFAULT 0.70 COMMENT '默认温度值',
`top_p` DECIMAL(3,2) DEFAULT 1.00 COMMENT 'TopP 值',
`max_tokens` INT DEFAULT 2048 COMMENT '最大生成 token 数',
`request_headers` JSON DEFAULT NULL COMMENT '额外请求头(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_dify_company` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI 服务配置(Dify/OpenAI 等)';
-- Prompt 模板表
-- 存储可复用的Prompt模板。
CREATE TABLE `ai_prompt_templates` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT 'Prompt 模板主键ID',
`company_id` INT DEFAULT NULL COMMENT '公司ID(NULL 表示系统模板)',
`name` VARCHAR(100) NOT NULL COMMENT '模板名称',
`description` VARCHAR(255) DEFAULT NULL COMMENT '模板描述',
`language` VARCHAR(20) DEFAULT 'zh' COMMENT '默认语言编码(en/zh 等)',
`content` LONGTEXT NOT NULL COMMENT '模板内容(可含变量占位符)',
`variables` JSON DEFAULT NULL COMMENT '变量说明(JSON)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_prompt_company` (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Prompt 模板表';
-- 上传文件表
-- 管理用户上传的文件,如知识库、图片、视频等。
CREATE TABLE `ai_uploaded_files` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '上传文件主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '上传者用户ID(外键)',
`file_name` VARCHAR(255) NOT NULL COMMENT '原始文件名',
`file_path` VARCHAR(500) NOT NULL COMMENT '服务器存储路径或外部URL',
`file_type` ENUM('knowledge','image','video','document','other') NOT NULL COMMENT '文件类型',
`file_size` BIGINT DEFAULT 0 COMMENT '文件大小(字节)',
`mime_type` VARCHAR(100) DEFAULT NULL COMMENT 'MIME 类型',
`checksum` VARCHAR(64) DEFAULT NULL COMMENT '校验和(可选)',
`version` INT DEFAULT 1 COMMENT '版本号(用于版本控制)',
`status` ENUM('active','archived','deleted') DEFAULT 'active' COMMENT '文件状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
PRIMARY KEY (`id`),
KEY `idx_files_company` (`company_id`),
KEY `idx_files_user` (`user_id`),
CONSTRAINT `fk_file_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_file_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='上传文件表(知识库/媒体等)';
-- ====================================================================================================
-- 5) AI内容生成:文章
-- ====================================================================================================
-- 文章类型表
-- 分类文章,如产品介绍、新闻稿等。
CREATE TABLE `ai_article_types` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章类型主键ID',
`name` VARCHAR(50) NOT NULL COMMENT '文章类型名称(如产品介绍)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '类型说明',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_types_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章类型表';
-- 文章生成配置表
-- 存储文章生成的参数和偏好设置。
CREATE TABLE `ai_article_generation_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章生成配置主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`name` VARCHAR(100) NOT NULL COMMENT '配置名称',
`platform_id` INT DEFAULT NULL COMMENT '适用发布平台ID(可选)',
`article_type_id` INT DEFAULT NULL COMMENT '文章类型ID(外键)',
`writing_language` VARCHAR(20) DEFAULT 'en' COMMENT '写作语言(en/zh)',
`remove_ai_tone` TINYINT(1) DEFAULT 1 COMMENT '是否去除AI味道',
`ai_taste_level` ENUM('colloquial','junior_high','senior_high','professional') DEFAULT 'junior_high' COMMENT 'AI风格等级',
`article_length_min` INT DEFAULT 800 COMMENT '最小长度(字符)',
`article_length_max` INT DEFAULT 1500 COMMENT '最大长度(字符)',
`auto_seo_optimization` TINYINT(1) DEFAULT 1 COMMENT '自动SEO优化',
`keyword_density_min` DECIMAL(5,2) DEFAULT 1.00 COMMENT '关键词密度下限(%)',
`keyword_density_max` DECIMAL(5,2) DEFAULT 2.00 COMMENT '关键词密度上限(%)',
`auto_geo_optimization` TINYINT(1) DEFAULT 1 COMMENT '是否自动GEO优化',
`auto_structured_data` TINYINT(1) DEFAULT 1 COMMENT '是否自动生成结构化数据',
`multi_version_count` INT DEFAULT 3 COMMENT '生成版本数量',
`extra_options` JSON DEFAULT NULL COMMENT '额外选项(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_config_company` (`company_id`),
KEY `idx_config_platform` (`platform_id`),
KEY `idx_config_article_type` (`article_type_id`),
CONSTRAINT `fk_config_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_config_platform` FOREIGN KEY (`platform_id`) REFERENCES `ai_publishing_platforms` (`id`),
CONSTRAINT `fk_config_article_type` FOREIGN KEY (`article_type_id`) REFERENCES `ai_article_types` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI 文章生成配置';
-- 文章生成任务表
-- 记录每次文章生成的请求和状态。
CREATE TABLE `ai_article_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章生成任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID(外键)',
`config_id` INT DEFAULT NULL COMMENT '使用的生成配置ID(外键)',
`article_theme` VARCHAR(255) DEFAULT NULL COMMENT '文章主题/标题(输入)',
`topic_ids` TEXT DEFAULT NULL COMMENT '所选话题ID列表(逗号分隔)',
`reference_urls` TEXT DEFAULT NULL COMMENT '参考URL列表(逗号分隔)',
`reference_content` LONGTEXT DEFAULT NULL COMMENT '高度参考链接抓取到的内容摘要',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`progress` TINYINT DEFAULT 0 COMMENT '进度(0-100)',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID(外键)',
`prompt_template_id` INT DEFAULT NULL COMMENT '使用的 Prompt 模板 ID(外键)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_task_company_status` (`company_id`,`status`),
KEY `idx_task_user` (`user_id`),
KEY `idx_task_config` (`config_id`),
CONSTRAINT `fk_task_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_task_config` FOREIGN KEY (`config_id`) REFERENCES `ai_article_generation_configs` (`id`),
CONSTRAINT `fk_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`),
CONSTRAINT `fk_task_prompt_template` FOREIGN KEY (`prompt_template_id`) REFERENCES `ai_prompt_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章生成任务';
-- 生成的文章表(多版本支持)
-- 存储AI生成的最终文章内容。
CREATE TABLE `ai_generated_articles` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成文章主键ID',
`task_id` INT DEFAULT NULL COMMENT '来源生成任务ID(外键,可空)',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`version` INT DEFAULT 1 COMMENT '文章版本号(用于多版本)',
`title` VARCHAR(255) DEFAULT NULL COMMENT '文章标题',
`content` LONGTEXT DEFAULT NULL COMMENT '文章纯文本内容(不含HTML)',
`html_content` LONGTEXT DEFAULT NULL COMMENT '文章HTML格式内容(含排版)',
`faq_section` JSON DEFAULT NULL COMMENT 'FAQ 部分(JSON)',
`structured_data` JSON DEFAULT NULL COMMENT '结构化数据 JSON-LD(全文)',
`word_count` INT DEFAULT 0 COMMENT '文章字数统计',
`keyword_density` JSON DEFAULT NULL COMMENT '关键词密度分析结果(JSON)',
`is_selected` TINYINT(1) DEFAULT 0 COMMENT '是否被选为最终版本(1是)',
`status` ENUM('draft','approved','archived','deleted') DEFAULT 'draft' COMMENT '文章状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_articles_company_status` (`company_id`,`status`),
KEY `idx_articles_task` (`task_id`),
CONSTRAINT `fk_article_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`),
CONSTRAINT `fk_article_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成的文章表(多版本支持)';
-- 文章FAQ列表
-- 存储文章的FAQ部分。
CREATE TABLE `ai_article_faqs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章 FAQ 主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`question` VARCHAR(255) NOT NULL COMMENT 'FAQ 问题',
`answer` TEXT NOT NULL COMMENT 'FAQ 回答',
PRIMARY KEY (`id`),
KEY `idx_article_faqs_article` (`article_id`),
CONSTRAINT `fk_faq_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章 FAQ 列表';
-- 文章结构化数据
-- 存储文章的结构化数据(JSON-LD)。
CREATE TABLE `ai_article_structured_data` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '结构化数据主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`json_ld` JSON NOT NULL COMMENT 'JSON-LD 结构化数据内容',
PRIMARY KEY (`id`),
KEY `idx_structured_article` (`article_id`),
CONSTRAINT `fk_structured_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章结构化数据(单独表便于管理/更新)';
-- 文章媒体资源
-- 存储文章关联的图片、视频等媒体。
CREATE TABLE `ai_article_media` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章媒体资源主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`media_type` ENUM('image','video','audio') NOT NULL COMMENT '媒体类型',
`url` VARCHAR(500) NOT NULL COMMENT '媒体链接或存储路径',
`prompt` TEXT DEFAULT NULL COMMENT '生成提示语(AI 配图时记录)',
`source_type` ENUM('ai_generated','user_provided','external') DEFAULT 'external' COMMENT '资源来源类型',
`alt_text` VARCHAR(255) DEFAULT NULL COMMENT '图片替代文本(SEO)',
`caption` VARCHAR(255) DEFAULT NULL COMMENT '图片说明/标题',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_media_article` (`article_id`),
CONSTRAINT `fk_media_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章媒体资源(多张图片/多视频)';
-- 文章多语言翻译表
-- 存储文章的不同语言版本。
CREATE TABLE `ai_article_translations` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章翻译主键ID',
`article_id` INT NOT NULL COMMENT '原文章ID(外键)',
`language` VARCHAR(20) NOT NULL COMMENT '翻译目标语言(如 en/zh)',
`title` VARCHAR(255) DEFAULT NULL COMMENT '译文标题',
`content` LONGTEXT DEFAULT NULL COMMENT '译文纯文本内容',
`html_content` LONGTEXT DEFAULT NULL COMMENT '译文 HTML 内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_language` (`article_id`,`language`),
KEY `idx_translations_article` (`article_id`),
CONSTRAINT `fk_translation_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章多语言翻译表';
-- ====================================================================================================
-- 6) AI内容生成:落地页
-- ====================================================================================================
-- 落地页模板表
-- 存储可用的落地页布局模板。
CREATE TABLE `ai_landing_page_templates` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '落地页模板主键ID',
`name` VARCHAR(100) NOT NULL COMMENT '模板名称(如:单栏布局)',
`code` VARCHAR(50) NOT NULL COMMENT '模板代码(如:single-column)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '模板描述',
`preview_image_url` VARCHAR(255) DEFAULT NULL COMMENT '预览图URL',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_templates_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页布局与设计模板';
-- 落地页项目表
-- 代表一个完整的落地页创建流程。
CREATE TABLE `ai_landing_page_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '落地页项目主键ID',
`company_id` INT NOT NULL COMMENT '所属公司ID(外键)',
`user_id` INT NOT NULL COMMENT '创建者用户ID(外键)',
`name` VARCHAR(255) NOT NULL COMMENT '落地页项目名称(用于内部识别)',
`status` ENUM('draft','configuring','generated','published','archived') DEFAULT 'draft' COMMENT '项目状态',
`last_step_completed` INT DEFAULT 0 COMMENT '最后完成的步骤号',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_lp_projects_company` (`company_id`),
KEY `idx_lp_projects_user` (`user_id`),
CONSTRAINT `fk_lp_project_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_lp_project_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI落地页构建项目表';
-- 落地页各步骤配置数据
-- 存储落地页构建过程中用户输入的所有配置信息。
CREATE TABLE `ai_landing_page_step_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID(外键)',
-- Step 1: 目标用户
`target_audience_desc` TEXT COMMENT '目标用户描述',
`user_pain_points` TEXT COMMENT '用户痛点(可JSON或换行分隔)',
`user_expectations` TEXT COMMENT '用户期望结果',
`age_groups` VARCHAR(255) DEFAULT NULL COMMENT '年龄段(逗号分隔)',
`gender_preference` ENUM('male','female','balanced') DEFAULT 'balanced' COMMENT '性别倾向',
`behavior_characteristics` VARCHAR(255) DEFAULT NULL COMMENT '用户行为特征(逗号分隔)',
`decision_making_styles` VARCHAR(255) DEFAULT NULL COMMENT '用户决策方式(逗号分隔)',
-- Step 2: 落地页目标
`industry_primary` VARCHAR(100) DEFAULT NULL COMMENT '一级行业',
`industry_secondary` VARCHAR(100) DEFAULT NULL COMMENT '二级行业',
`industry_tertiary` VARCHAR(100) DEFAULT NULL COMMENT '子分类',
`marketing_goal` VARCHAR(50) DEFAULT NULL COMMENT '营销目标(lead-collection, product-sales等)',
-- Step 3: 风格与配色
`design_style` VARCHAR(50) DEFAULT NULL COMMENT '设计风格(modern, professional等)',
`primary_color` VARCHAR(20) DEFAULT NULL COMMENT '主色调',
`accent_color` VARCHAR(20) DEFAULT NULL COMMENT '辅助色调',
`template_id` INT DEFAULT NULL COMMENT '布局模板ID(外键)',
-- Step 4: 核心卖点
`unique_value_proposition` TEXT COMMENT '独特价值主张',
`core_advantages` JSON DEFAULT NULL COMMENT '核心优势列表(JSON数组)',
`primary_keyword` VARCHAR(255) DEFAULT NULL COMMENT '主要关键词',
`secondary_keywords` JSON DEFAULT NULL COMMENT '次要关键词列表(JSON数组)',
-- Step 5: 页面内容
`content_generation_type` ENUM('ai','custom','upload') DEFAULT 'ai' COMMENT '内容生成方式',
`company_name` VARCHAR(255) DEFAULT NULL COMMENT '公司全称',
`brand_name` VARCHAR(255) DEFAULT NULL COMMENT '品牌名称',
`company_description` TEXT COMMENT '公司介绍',
`video_url` VARCHAR(500) DEFAULT NULL COMMENT '视频链接',
`logo_file_id` INT DEFAULT NULL COMMENT '公司Logo文件ID(关联ai_uploaded_files)',
`contact_info` JSON DEFAULT NULL COMMENT '联系信息(地址、电话、邮箱、工作时间)',
`social_media_links` JSON DEFAULT NULL COMMENT '社交媒体链接(JSON数组)',
-- Step 6: CTA
`primary_cta_text` VARCHAR(100) DEFAULT NULL COMMENT '主要CTA按钮文案',
`secondary_cta_texts` JSON DEFAULT NULL COMMENT '次要CTA按钮文案(JSON数组)',
-- Step 7: 信任元素
`testimonials` JSON DEFAULT NULL COMMENT '客户评价/推荐语(JSON数组,含姓名、职位、内容)',
`social_proofs` JSON DEFAULT NULL COMMENT '社会证明数据(JSON数组,含标签、数值)',
-- Step 8: 表单字段
`form_fields` JSON DEFAULT NULL COMMENT '表单字段配置(JSON对象,key为字段名,value为是否启用)',
-- Step 9: 生成与部署
`page_title` VARCHAR(255) DEFAULT NULL COMMENT '页面SEO标题',
`page_description` TEXT COMMENT '页面SEO描述',
`ga_tracking_code` TEXT COMMENT '谷歌广告跟踪代码',
`deployment_method` ENUM('ftp','link') DEFAULT 'link' COMMENT '部署方式',
`deployment_config` JSON DEFAULT NULL COMMENT '部署配置(FTP信息或子域名)',
`pricing_plan` VARCHAR(50) DEFAULT NULL COMMENT '选择的套餐(basic, pro, enterprise)',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_config_project` (`project_id`),
CONSTRAINT `fk_lp_config_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_lp_config_template` FOREIGN KEY (`template_id`) REFERENCES `ai_landing_page_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页各步骤配置数据';
-- 落地页AI生成任务表
-- 记录落地页生成的请求和状态。
CREATE TABLE `ai_landing_page_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID (外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID (外键)',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`progress` TINYINT DEFAULT 0 COMMENT '进度 (0-100)',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID (外键, 关联 ai_dify_api_configs)',
`prompt_template_id` INT DEFAULT NULL COMMENT '使用的Prompt模板ID (外键, 关联 ai_prompt_templates)',
`final_prompt_snapshot` LONGTEXT DEFAULT NULL COMMENT '发送给AI的最终Prompt快照(用于调试和记录)',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_lp_task_project` (`project_id`),
KEY `idx_lp_task_status` (`status`),
CONSTRAINT `fk_lp_task_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`),
CONSTRAINT `fk_lp_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_lp_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`),
CONSTRAINT `fk_lp_task_prompt_template` FOREIGN KEY (`prompt_template_id`) REFERENCES `ai_prompt_templates` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页AI生成任务表';
-- 最终生成的落地页(支持多版本)
-- 存储AI生成的最终落地页HTML代码。
CREATE TABLE `ai_generated_landing_pages` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成落地页主键ID',
`project_id` INT NOT NULL COMMENT '来源项目ID(外键)',
`version_code` VARCHAR(20) NOT NULL DEFAULT 'A' COMMENT '版本标识(用于A/B测试,如A, B)',
`html_content` LONGTEXT COMMENT '落地页HTML内容',
`status` ENUM('draft','final','published') DEFAULT 'draft' COMMENT '版本状态',
`publish_url` VARCHAR(500) DEFAULT NULL COMMENT '发布后的URL(使用link方式时)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_lp_project_version` (`project_id`, `version_code`),
CONSTRAINT `fk_lp_page_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='最终生成的落地页(支持多版本)';
-- 落地页项目关联的媒体资产
-- 存储落地页项目中使用的图片、Logo等文件。
CREATE TABLE `ai_landing_page_assets` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '资产主键ID',
`project_id` INT NOT NULL COMMENT '落地页项目ID(外键)',
`asset_type` ENUM('product_image','certification_logo','testimonial_avatar') NOT NULL COMMENT '资产类型',
`uploaded_file_id` INT NOT NULL COMMENT '上传文件ID(外键)',
`related_data` JSON DEFAULT NULL COMMENT '相关数据(如关联的产品名或评价人)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_lp_assets_project` (`project_id`),
CONSTRAINT `fk_lp_asset_project` FOREIGN KEY (`project_id`) REFERENCES `ai_landing_page_projects` (`id`),
CONSTRAINT `fk_lp_asset_file` FOREIGN KEY (`uploaded_file_id`) REFERENCES `ai_uploaded_files` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='落地页项目关联的媒体资产';
-- ====================================================================================================
-- 7) AI内容生成:网站 (简化版)
-- ====================================================================================================
-- AI网站构建项目总表
-- 代表一个完整的网站创建流程。
CREATE TABLE `ai_website_projects` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '网站项目主键ID',
`company_id` INT NOT NULL COMMENT '所属公司ID (外键)',
`user_id` INT NOT NULL COMMENT '创建者用户ID (外键)',
`project_name` VARCHAR(255) NOT NULL COMMENT '项目名称 (用于内部识别)',
`site_name` VARCHAR(255) DEFAULT NULL COMMENT '最终生成的网站名称',
`status` ENUM('draft','configuring','generating','completed','published') DEFAULT 'draft' COMMENT '项目状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_website_projects_company` (`company_id`),
CONSTRAINT `fk_website_project_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_website_project_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI网站构建项目总表';
-- AI网站构建器配置(存储站点地图)
-- 存储网站的全局配置和站点地图结构。
CREATE TABLE `ai_website_build_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '配置主键ID',
`project_id` INT NOT NULL COMMENT '网站项目ID (外键)',
`website_type` VARCHAR(50) DEFAULT NULL COMMENT '网站类型 (business, portfolio等)',
`site_identity` JSON DEFAULT NULL COMMENT '网站身份信息 (名称, 标语, 描述, 关键词)',
`design_preferences` JSON DEFAULT NULL COMMENT '设计偏好 (风格, 主色调)',
`sitemap_structure` JSON DEFAULT NULL COMMENT '站点地图结构定义 (JSON, 描述栏目层级和类型)',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_website_config_project` (`project_id`),
CONSTRAINT `fk_website_config_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI网站构建器配置(存储站点地图)';
-- 网站栏目结构表 (支持无限层级)
-- 定义网站的栏目结构。
CREATE TABLE `ai_website_channels` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '网站栏目主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`parent_id` INT DEFAULT NULL COMMENT '父栏目ID (用于实现层级结构)',
`name` VARCHAR(100) NOT NULL COMMENT '栏目名称 (如: 公司介绍, 新闻中心)',
`path` VARCHAR(100) NOT NULL COMMENT 'URL路径 (如: /about, /news)',
`channel_type` ENUM('single_page', 'article_list', 'product_list', 'custom') NOT NULL COMMENT '栏目类型',
`display_order` INT DEFAULT 0 COMMENT '显示顺序',
`is_visible_in_nav` TINYINT(1) DEFAULT 1 COMMENT '是否在主导航中可见',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_channel_project` (`project_id`),
KEY `idx_channel_parent` (`parent_id`),
CONSTRAINT `fk_channel_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_channel_parent` FOREIGN KEY (`parent_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站栏目结构表 (支持无限层级)';
-- 网站文章内容表
-- 存储网站栏目下的文章内容。
CREATE TABLE `ai_website_articles` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`channel_id` INT NOT NULL COMMENT '所属文章栏目ID (外键)',
`title` VARCHAR(255) NOT NULL COMMENT '文章标题',
`summary` TEXT DEFAULT NULL COMMENT '文章摘要',
`content` LONGTEXT COMMENT '文章主体内容 (Markdown或HTML)',
`status` ENUM('draft', 'published') DEFAULT 'draft' COMMENT '发布状态',
`published_at` TIMESTAMP NULL DEFAULT NULL COMMENT '发布时间',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_article_project_channel` (`project_id`, `channel_id`),
CONSTRAINT `fk_website_article_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_article_channel` FOREIGN KEY (`channel_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站文章内容表';
-- 网站产品内容表
-- 存储网站栏目下的产品内容。
CREATE TABLE `ai_website_products` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '产品主键ID',
`project_id` INT NOT NULL COMMENT '所属网站项目ID (外键)',
`channel_id` INT NOT NULL COMMENT '所属产品栏目ID (外键)',
`name` VARCHAR(255) NOT NULL COMMENT '产品名称',
`description` LONGTEXT COMMENT '产品详细描述',
`specifications` JSON DEFAULT NULL COMMENT '产品规格 (JSON格式)',
`main_image_url` VARCHAR(255) DEFAULT NULL COMMENT '产品主图URL',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_product_project_channel` (`project_id`, `channel_id`),
CONSTRAINT `fk_website_product_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_product_channel` FOREIGN KEY (`channel_id`) REFERENCES `ai_website_channels` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站产品内容表';
-- 网站AI生成任务表(支持父子任务)
-- 记录网站生成的请求和状态。
CREATE TABLE `ai_website_generation_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务主键ID',
`project_id` INT NOT NULL COMMENT '网站项目ID (外键)',
`user_id` INT NOT NULL COMMENT '发起用户ID (外键)',
`parent_task_id` INT DEFAULT NULL COMMENT '父任务ID (用于父子任务)',
`task_type` ENUM('full_site', 'generate_shell', 'generate_page_content', 'regenerate_channel') NOT NULL COMMENT '任务类型',
`target_id` INT DEFAULT NULL COMMENT '任务目标ID (如特定页面或栏目ID)',
`status` ENUM('pending','processing','completed','failed', 'waiting_for_children') DEFAULT 'pending' COMMENT '任务状态',
`dify_api_config_id` INT DEFAULT NULL COMMENT '调用的AI配置ID (外键)',
`config_snapshot` JSON DEFAULT NULL COMMENT '生成时刻的配置快照',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '完成时间',
PRIMARY KEY (`id`),
KEY `idx_website_task_project` (`project_id`),
KEY `idx_website_task_parent` (`parent_task_id`),
CONSTRAINT `fk_website_task_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_website_task_parent` FOREIGN KEY (`parent_task_id`) REFERENCES `ai_website_generation_tasks` (`id`),
CONSTRAINT `fk_website_task_ai_config` FOREIGN KEY (`dify_api_config_id`) REFERENCES `ai_dify_api_configs` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='网站AI生成任务表(支持父子任务)';
-- 生成的网站页面(映射到栏目或内容项)
-- 存储AI生成的最终网站页面HTML代码。
CREATE TABLE `ai_generated_website_pages` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '生成页面主键ID',
`project_id` INT NOT NULL COMMENT '来源网站项目ID (外键)',
`task_id` INT NOT NULL COMMENT '来源生成任务ID (外键)',
`pageable_type` VARCHAR(100) NOT NULL COMMENT '关联类型 (Channel, Article, Product)',
`pageable_id` INT NOT NULL COMMENT '关联类型ID',
`file_name` VARCHAR(100) NOT NULL COMMENT '文件名 (如: index.html, news/article-1.html)',
`html_content` LONGTEXT COMMENT '页面的完整HTML内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
PRIMARY KEY (`id`),
KEY `idx_pageable` (`pageable_type`, `pageable_id`),
CONSTRAINT `fk_website_page_project` FOREIGN KEY (`project_id`) REFERENCES `ai_website_projects` (`id`),
CONSTRAINT `fk_website_page_task` FOREIGN KEY (`task_id`) REFERENCES `ai_website_generation_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成的网站页面(映射到栏目或内容项)';
-- ====================================================================================================
-- 8) 内容发布系统
-- ====================================================================================================
-- 目标网站类型表
-- 对目标平台进行大类划分。
CREATE TABLE `ai_publishing_platform_types` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '平台类型主键ID',
`name` VARCHAR(50) NOT NULL COMMENT '平台类型名称(如 Blog, Social, Video)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '类型描述',
`icon` VARCHAR(100) DEFAULT NULL COMMENT '图标标识',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_platform_types_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站类型表';
-- 目标网站表
-- 定义支持发布的目标平台及其API配置模板。
CREATE TABLE `ai_publishing_platforms` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '目标网站主键ID',
`type_id` INT NOT NULL COMMENT '目标网站类型ID(外键)',
`name` VARCHAR(100) NOT NULL COMMENT '目标网站名称(如 WordPress, LinkedIn, 小红书)',
`code` VARCHAR(50) NOT NULL COMMENT '目标网站代码(唯一)',
`description` VARCHAR(255) DEFAULT NULL COMMENT '目标网站说明',
`icon` VARCHAR(100) DEFAULT NULL COMMENT '目标网站图标',
`auth_type` ENUM('oauth','api_key','basic','custom') NOT NULL COMMENT '认证类型',
`api_config_template` JSON DEFAULT NULL COMMENT 'API 配置模板(JSON schema)',
`character_limit` INT DEFAULT NULL COMMENT '目标网站字符限制(如微博)',
`is_active` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_platforms_code` (`code`),
KEY `idx_platforms_type` (`type_id`),
CONSTRAINT `fk_platform_type` FOREIGN KEY (`type_id`) REFERENCES `ai_publishing_platform_types` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站表';
-- 企业在目标网站的配置(API key/Token等)
-- 存储公司对特定平台的授权信息。
CREATE TABLE `ai_company_platform_configs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '企业平台配置主键ID',
`company_id` INT NOT NULL COMMENT '授权公司ID(外键)',
`platform_id` INT NOT NULL COMMENT '目标网站ID(外键)',
`config_data` JSON NOT NULL COMMENT '目标网站API配置信息(如 token、client_id)',
`account_name` VARCHAR(100) DEFAULT NULL COMMENT '企业在该目标网站的账号名/展示名',
`is_enabled` TINYINT(1) DEFAULT 1 COMMENT '是否启用该配置',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_platform` (`company_id`,`platform_id`),
KEY `idx_company_platform_company` (`company_id`),
KEY `idx_company_platform_platform` (`platform_id`),
CONSTRAINT `fk_company_platform_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_company_platform_platform` FOREIGN KEY (`platform_id`) REFERENCES `ai_publishing_platforms` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='企业在目标网站的配置(API key/Token等)';
-- 定时发布任务表
-- 管理计划在未来某个时间点执行的发布任务。
CREATE TABLE `ai_scheduled_publishing_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '定时发布任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`publishable_type` VARCHAR(50) DEFAULT 'article' COMMENT '发布内容类型(article, landing_page)',
`publishable_id` INT NOT NULL COMMENT '发布内容ID',
`article_id` INT DEFAULT NULL COMMENT '要发布的文章ID(外键) - 兼容旧版',
`platform_config_id` INT NOT NULL COMMENT '使用的企业平台配置ID(外键)',
`schedule_time` TIMESTAMP NOT NULL COMMENT '计划发布时间',
`status` ENUM('scheduled','processing','success','failed','cancelled') DEFAULT 'scheduled' COMMENT '任务状态',
`retry_count` INT DEFAULT 0 COMMENT '已重试次数',
`max_retries` INT DEFAULT 3 COMMENT '最大重试次数',
`last_attempt_at` TIMESTAMP NULL DEFAULT NULL COMMENT '最近一次尝试执行时间',
`error_message` TEXT DEFAULT NULL COMMENT '错误信息(失败时记录)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_schedule_company_time` (`company_id`, `schedule_time`),
KEY `idx_schedule_status` (`status`),
CONSTRAINT `fk_schedule_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_schedule_platform_config` FOREIGN KEY (`platform_config_id`) REFERENCES `ai_company_platform_configs` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时发布任务表';
-- 目标网站发布记录表(执行日志)
-- 记录所有发布操作的执行结果。
CREATE TABLE `ai_publishing_records` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '发布记录主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`publishable_type` VARCHAR(50) DEFAULT 'article' COMMENT '发布内容类型(article, landing_page)',
`publishable_id` INT NOT NULL COMMENT '发布内容ID',
`article_id` INT DEFAULT NULL COMMENT '文章ID(外键) - 兼容旧版',
`platform_config_id` INT NOT NULL COMMENT '目标网站配置ID(外键)',
`scheduled_task_id` INT DEFAULT NULL COMMENT '来源的定时任务ID(如果是定时发布则关联)',
`status` ENUM('scheduled','published','failed') DEFAULT 'scheduled' COMMENT '发布记录状态',
`publish_url` VARCHAR(500) DEFAULT NULL COMMENT '发布后目标网站返回的文章URL',
`external_post_id` VARCHAR(255) DEFAULT NULL COMMENT '目标网站返回的外部帖文/文章ID',
`publish_time` TIMESTAMP NULL DEFAULT NULL COMMENT '实际发布时间',
`error_message` TEXT DEFAULT NULL COMMENT '失败原因(若失败)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
PRIMARY KEY (`id`),
KEY `idx_publishing_company_time` (`company_id`,`publish_time`),
KEY `idx_publishing_status` (`status`),
CONSTRAINT `fk_publishing_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_publishing_platform_config` FOREIGN KEY (`platform_config_id`) REFERENCES `ai_company_platform_configs` (`id`),
CONSTRAINT `fk_publishing_scheduled_task` FOREIGN KEY (`scheduled_task_id`) REFERENCES `ai_scheduled_publishing_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='目标网站发布记录表(执行日志)';
-- ====================================================================================================
-- 9) 关键词与话题管理 (SEO/内容规划)
-- ====================================================================================================
-- 关键词表
-- 管理用于内容生成和SEO的关键词。
CREATE TABLE `ai_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`keyword` VARCHAR(255) NOT NULL COMMENT '关键词文本',
`search_volume` INT DEFAULT 0 COMMENT '搜索量估算',
`cpc` DECIMAL(10,2) DEFAULT 0.00 COMMENT '估计每次点击成本',
`difficulty` TINYINT DEFAULT 0 COMMENT '关键词难度评分(0-100)',
`source` ENUM('baidu','google','manual','expansion','import') DEFAULT 'manual' COMMENT '来源类型',
`status` ENUM('pending','planned','generated','published') DEFAULT 'pending' COMMENT '关键词状态',
`tags` VARCHAR(255) DEFAULT NULL COMMENT '关键词标签,逗号分隔',
`usage_count` INT DEFAULT 0 COMMENT '关键词被文章使用次数',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_keyword` (`company_id`,`keyword`),
KEY `idx_keywords_company_status` (`company_id`,`status`),
CONSTRAINT `fk_keyword_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关键词表';
-- 关键词扩展表(保存 related_searches)
-- 存储关键词的扩展词(如相关搜索词)。
CREATE TABLE `ai_keyword_expansions` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '关键词扩展主键ID',
`keyword_id` INT NOT NULL COMMENT '原始关键词ID(外键)',
`related_keyword` VARCHAR(255) NOT NULL COMMENT '扩展关键词(来自 related_searches 等)',
`source` ENUM('baidu','google','import') DEFAULT 'google' COMMENT '扩展来源',
`raw_response` JSON DEFAULT NULL COMMENT 'API 原始返回(便于溯源)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_keyword_exp_keyword` (`keyword_id`),
CONSTRAINT `fk_keyword_expansion_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关键词扩展表(保存 related_searches)';
-- 话题表
-- 管理更宽泛的内容主题。
CREATE TABLE `ai_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`source_task_id` INT DEFAULT NULL COMMENT '来源的抓取任务ID(外键,可空)',
`title` VARCHAR(255) NOT NULL COMMENT '话题标题',
`description` TEXT DEFAULT NULL COMMENT '话题描述或摘要',
`source_url` VARCHAR(500) DEFAULT NULL COMMENT '原始来源链接(可选)',
`status` ENUM('raw','curated','rejected') DEFAULT 'raw' COMMENT '话题状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_topics_company_status` (`company_id`,`status`),
KEY `idx_topics_source_task` (`source_task_id`),
CONSTRAINT `fk_topic_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_topic_source_task` FOREIGN KEY (`source_task_id`) REFERENCES `ai_search_sources_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='话题表';
-- 话题与关键词的多对多映射
-- 建立话题和关键词之间的关联。
CREATE TABLE `ai_topic_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题-关键词关联主键ID',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_topic_keyword` (`topic_id`,`keyword_id`),
KEY `idx_topic_keywords_topic` (`topic_id`),
KEY `idx_topic_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_topic_keyword_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_topic_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='话题与关键词的多对多映射';
-- AI数据源配置表
-- 配置用于抓取话题的外部数据源(如SERP API)。
CREATE TABLE `ai_search_sources_api` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '数据源配置主键ID',
`name` VARCHAR(100) NOT NULL COMMENT '数据来源名称 (如 百度前10、Google also ask)',
`source_type` ENUM('serp_api', 'rss', 'custom_api', 'web_scraping', 'database') NOT NULL COMMENT '来源类型',
`api_config` JSON NOT NULL COMMENT 'API 配置',
`result_parser` JSON NOT NULL COMMENT '结果解析规则',
`is_active` BOOLEAN DEFAULT TRUE COMMENT '是否启用',
`priority` TINYINT UNSIGNED DEFAULT 10 COMMENT '优先级 (1-100, 数字越小优先级越高)',
`rate_limit` JSON COMMENT '限流配置 {"requests": 100, "period": 3600}',
`health_check` JSON COMMENT '健康检查配置',
`metadata` JSON COMMENT '元数据 (描述、版本等)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `idx_source_name` (`name`),
INDEX `idx_source_type` (`source_type`),
INDEX `idx_source_active` (`is_active`),
INDEX `idx_source_priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI数据源配置表';
-- AI数据源抓取任务表
-- 记录从外部数据源抓取话题的任务。
CREATE TABLE `ai_search_sources_tasks` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '话题抓取任务主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '发起任务的用户ID(外键)',
`topic_source_id` INT NOT NULL COMMENT '话题来源配置ID(外键)',
`keywords` TEXT DEFAULT NULL COMMENT '用于本次抓取的关键词快照(逗号分隔)',
`topic_id` INT DEFAULT NULL COMMENT '关联的话题ID(外键,可空)',
`keyword_id` INT DEFAULT NULL COMMENT '关联的关键词ID(外键,可空)',
`status` ENUM('pending','processing','completed','failed') DEFAULT 'pending' COMMENT '任务状态',
`result_count` INT DEFAULT 0 COMMENT '抓取结果数量',
`raw_response` JSON DEFAULT NULL COMMENT 'API 原始返回(JSON)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`completed_at` TIMESTAMP NULL DEFAULT NULL COMMENT '任务完成时间',
PRIMARY KEY (`id`),
KEY `idx_topic_fetch_company` (`company_id`),
KEY `idx_topic_fetch_source` (`topic_source_id`),
KEY `idx_topic_fetch_status` (`status`),
CONSTRAINT `fk_search_task_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_search_task_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`),
CONSTRAINT `fk_search_task_source` FOREIGN KEY (`topic_source_id`) REFERENCES `ai_search_sources_api` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='AI数据源抓取任务表';
-- ====================================================================================================
-- 10) 任务关联表 (连接生成任务与资源)
-- ====================================================================================================
-- 任务参考链接明细(可标注高度参考)
-- 存储文章生成任务中使用的参考链接。
CREATE TABLE `ai_task_references` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务参考链接主键ID',
`task_id` INT NOT NULL COMMENT '对应任务ID(外键)',
`url` VARCHAR(500) NOT NULL COMMENT '参考链接URL',
`title` VARCHAR(255) DEFAULT NULL COMMENT '页面标题(可选)',
`source_engine` VARCHAR(50) DEFAULT NULL COMMENT '来源引擎(google/baidu/zhihu等)',
`position` INT DEFAULT NULL COMMENT '在搜索结果中的排名位置',
`is_high_reference` TINYINT(1) DEFAULT 0 COMMENT '是否标记为高度参考(1是)',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_task_references_task` (`task_id`),
CONSTRAINT `fk_task_reference_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务参考链接明细(可标注高度参考)';
-- 生成任务与关键词映射(规划用)
-- 将生成任务与计划使用的关键词关联。
CREATE TABLE `ai_task_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务-关键词关联主键ID',
`task_id` INT NOT NULL COMMENT '生成任务ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
`is_primary` TINYINT(1) DEFAULT 0 COMMENT '是否主关键词',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_task_keyword` (`task_id`,`keyword_id`),
KEY `idx_task_keywords_task` (`task_id`),
KEY `idx_task_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_task_keyword_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成任务与关键词映射(规划用)';
-- 生成任务与话题映射
-- 将生成任务与相关话题关联。
CREATE TABLE `ai_task_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务-话题关联主键ID',
`task_id` INT NOT NULL COMMENT '生成任务ID(外键)',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_task_topic` (`task_id`,`topic_id`),
KEY `idx_task_topics_task` (`task_id`),
KEY `idx_task_topics_topic` (`topic_id`),
CONSTRAINT `fk_task_topic_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_topic_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='生成任务与话题映射';
-- 任务知识库来源(公司库或上传的解析内容)
-- 指定生成任务使用的知识来源。
CREATE TABLE `ai_task_knowledge_sources` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '任务知识来源主键ID',
`task_id` INT NOT NULL COMMENT '任务ID(外键)',
`knowledge_type` ENUM('company','uploaded') NOT NULL COMMENT '知识来源类型(公司知识库/上传文件)',
`knowledge_id` INT DEFAULT NULL COMMENT '当 knowledge_type=uploaded 时,关联 ai_uploaded_files.id',
`content` LONGTEXT DEFAULT NULL COMMENT '若上传文件被解析,存解析后的文本内容',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_task_knowledge_task` (`task_id`),
KEY `idx_task_knowledge_knowledge` (`knowledge_id`),
CONSTRAINT `fk_task_knowledge_task` FOREIGN KEY (`task_id`) REFERENCES `ai_article_generation_tasks` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_task_knowledge_file` FOREIGN KEY (`knowledge_id`) REFERENCES `ai_uploaded_files` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务知识库来源(公司库或上传的解析内容)';
-- 文章与关键词关联(实际使用)
-- 将最终生成的文章与实际使用的关键词关联。
CREATE TABLE `ai_article_keywords` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章关键词关联主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`keyword_id` INT NOT NULL COMMENT '关键词ID(外键)',
`is_primary` TINYINT(1) DEFAULT 0 COMMENT '是否主关键词(1主/0辅)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_keyword` (`article_id`,`keyword_id`),
KEY `idx_article_keywords_article` (`article_id`),
KEY `idx_article_keywords_keyword` (`keyword_id`),
CONSTRAINT `fk_article_keyword_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_article_keyword_keyword` FOREIGN KEY (`keyword_id`) REFERENCES `ai_keywords` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章与关键词关联(实际使用)';
-- 文章与话题关联
-- 将最终生成的文章与相关话题关联。
CREATE TABLE `ai_article_topics` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '文章话题关联主键ID',
`article_id` INT NOT NULL COMMENT '文章ID(外键)',
`topic_id` INT NOT NULL COMMENT '话题ID(外键)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_article_topic` (`article_id`,`topic_id`),
KEY `idx_article_topics_article` (`article_id`),
KEY `idx_article_topics_topic` (`topic_id`),
CONSTRAINT `fk_article_topic_article` FOREIGN KEY (`article_id`) REFERENCES `ai_generated_articles` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_article_topic_topic` FOREIGN KEY (`topic_id`) REFERENCES `ai_topics` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文章与话题关联';
-- ====================================================================================================
-- 11) 统计与活动日志
-- ====================================================================================================
-- 用户活动日志(审计/分析)
-- 记录用户的常规活动,用于行为分析。
CREATE TABLE `ai_user_activity_logs` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户活动日志主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`user_id` INT NOT NULL COMMENT '用户ID(外键)',
`activity_type` VARCHAR(50) NOT NULL COMMENT '活动类型(如 login/create_article)',
`activity_details` JSON DEFAULT NULL COMMENT '活动详情(JSON)',
`ip_address` VARCHAR(45) DEFAULT NULL COMMENT '操作IP',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
KEY `idx_activity_company_user` (`company_id`,`user_id`),
KEY `idx_activity_type` (`activity_type`),
CONSTRAINT `fk_activity_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`),
CONSTRAINT `fk_activity_user` FOREIGN KEY (`user_id`) REFERENCES `ai_users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户活动日志(审计/分析)';
-- 公司使用统计
-- 统计公司的资源使用情况,用于计费和容量管理。
CREATE TABLE `ai_company_usage_stats` (
`id` INT NOT NULL AUTO_INCREMENT COMMENT '公司用量统计主键ID',
`company_id` INT NOT NULL COMMENT '公司ID(外键)',
`stat_date` DATE NOT NULL COMMENT '统计日期',
`article_count` INT DEFAULT 0 COMMENT '当日生成文章数量',
`ai_token_usage` BIGINT DEFAULT 0 COMMENT '当日 AI 令牌使用量',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '记录时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_company_date` (`company_id`,`stat_date`),
KEY `idx_usage_company` (`company_id`),
CONSTRAINT `fk_usage_stats_company` FOREIGN KEY (`company_id`) REFERENCES `ai_companies` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司使用统计';
SET FOREIGN_KEY_CHECKS = 1;
\ No newline at end of file
... ...
AI落地页生成系统流程详解
1. 项目创建与初始化
目标: 为用户启动一个新的落地页创建项目,记录其基本信息和当前所处的步骤。
涉及表:
ai_landing_page_projects: 存储项目的基本信息(名称、状态、所属公司/用户)。
ai_landing_page_step_configs: 存储项目在不同步骤中用户输入的详细配置。
处理逻辑:
用户在前端界面发起“新建落地页项目”请求。
后端服务创建一条 ai_landing_page_projects 记录,初始状态设为 draft 或 configuring,last_step_completed 设为 0。
前端引导用户逐步完成配置步骤。
2. 步骤式配置 (Step-by-Step Configuration)
目标: 通过引导用户完成一系列配置步骤,收集生成落地页所需的核心信息。
涉及表:
ai_landing_page_step_configs: 存储所有步骤的配置数据。
步骤详解 (基于表结构推断):
Step 1: 目标用户 (Target Audience)
配置项: target_audience_desc, user_pain_points, user_expectations, age_groups, gender_preference, behavior_characteristics, decision_making_styles
目的: 明确落地页是为谁而设计。
Step 2: 落地页目标 (Page Goal)
配置项: industry_primary/secondary/tertiary, marketing_goal
目的: 确定落地页的行业背景和核心营销目的(如收集线索 lead-collection、产品销售 product-sales)。
Step 3: 风格与配色 (Style & Design)
配置项: design_style, primary_color, accent_color, template_id (关联 ai_landing_page_templates)
目的: 选择落地页的视觉风格和布局模板。
Step 4: 核心卖点 (Core Value Proposition)
配置项: unique_value_proposition, core_advantages, primary_keyword, secondary_keywords
目的: 定义落地页要传达的核心信息和优化关键词。
Step 5: 页面内容 (Content Details)
配置项: content_generation_type (AI生成 ai / 自定义 custom / 上传 upload), company_name, brand_name, company_description, video_url
目的: 决定内容来源,并提供基础信息。
Step 6-N: 其他内容模块 (如CTA、表单、信任元素等)
(表结构中未完全体现,但实际应用中通常会有)
Step 9: 生成与部署 (Generation & Deployment)
配置项: page_title, page_description, ga_tracking_code, deployment_method (ftp/link), deployment_config, pricing_plan
目的: 设置SEO信息、跟踪代码和部署方式。
处理逻辑:
每完成一个步骤,前端将该步骤的数据发送到后端。
后端服务将数据存入或更新 ai_landing_page_step_configs 表中对应的项目记录。
更新 ai_landing_page_projects 表中的 last_step_completed 字段。
当所有步骤完成(或达到可生成状态),用户可以触发生成。
3. 内容与资产准备
目标: 根据配置,准备AI生成所需的内容提示(Prompt)和媒体资源。
涉及表:
ai_landing_page_step_configs: 获取配置信息。
ai_landing_page_assets: 获取上传的图片、Logo等。
ai_uploaded_files: 存储实际上传的文件。
处理逻辑:
Prompt构建: 根据 ai_landing_page_step_configs 中的信息(如目标用户、卖点、内容类型等)和 ai_prompt_templates(如果使用模板)构建发送给Dify的Prompt。
资产关联: 如果用户上传了图片等资源,将其存入 ai_uploaded_files,并在 ai_landing_page_assets 中记录与项目的关联关系。
4. AI生成任务创建与执行
目标: 将准备好的信息提交给AI模型(如Dify)进行落地页内容(主要是HTML)的生成。
涉及表:
ai_landing_page_generation_tasks: 记录生成任务。
处理逻辑:
用户点击“生成落地页”按钮。
后端服务创建一条 ai_landing_page_generation_tasks 记录,关联到 ai_landing_page_projects,并记录使用的 dify_api_config_id、prompt_template_id 等。
调用Dify API: 将构建好的Prompt、配置信息、资产链接等发送给Dify API。
异步处理: 与文章生成类似,Dify处理需要时间,应采用异步方式处理任务状态更新。
5. 结果接收与存储
目标: 接收Dify返回的生成结果(HTML代码),并存储。
涉及表:
ai_generated_landing_pages: 存储生成的落地页HTML。
处理逻辑:
通过Dify回调或主动轮询获取生成结果。
将返回的HTML内容存入 ai_generated_landing_pages 表,关联到 project_id 和生成的 version_code (支持A/B测试)。
更新 ai_landing_page_generation_tasks 的状态为 completed。
更新 ai_landing_page_projects 的状态为 generated。
6. 预览、编辑与发布
目标: 允许用户查看生成结果,进行微调,并最终发布。
涉及表:
ai_generated_landing_pages: 提供预览内容。
ai_landing_page_projects: 更新项目状态。
ai_landing_page_step_configs: (如果允许编辑并重新生成)
处理逻辑:
预览: 前端加载 ai_generated_landing_pages 中的HTML进行展示。
编辑: (可选) 提供简单的可视化编辑器,或允许用户修改原始HTML/Markdown,保存为新版本。
发布:
根据 ai_landing_page_step_configs 中的 deployment_method 和 deployment_config 进行部署。
如果是 link 方式,生成一个可访问的链接,并存入 ai_generated_landing_pages.publish_url。
如果是 ftp 方式,则需要后端或前端(通过JS)将HTML文件上传到指定FTP服务器。
更新 ai_landing_page_projects 状态为 published。
更新 ai_generated_landing_pages 状态为 published。
落地页生成开发建议
清晰的步骤引导UI: 前端必须提供清晰、易懂的多步骤表单,引导用户完成配置。
配置数据持久化: 每一步的输入都应及时保存到 ai_landing_page_step_configs,避免用户丢失进度。
模板化Prompt: 为不同类型的落地页(如线索收集、产品销售)设计不同的Prompt模板 (ai_prompt_templates),提高生成质量。
资产管理系统: 完善文件上传、存储 (ai_uploaded_files) 和关联 (ai_landing_page_assets) 逻辑,确保AI能访问到正确的媒体资源链接。
异步任务队列: 落地页生成任务(调用Dify)应使用异步处理,通过任务ID跟踪状态,并及时更新数据库。
版本管理: 利用 ai_generated_landing_pages.version_code 实现A/B测试或多版本迭代。
部署集成: 实现 link 和 ftp 两种部署方式的后端逻辑。link 方式可能需要一个简单的静态文件服务或CDN支持;ftp 方式需要安全地处理FTP凭据。
错误处理与日志: 详细记录每个步骤和API调用的错误,方便排查问题。
SEO预设: 在 ai_landing_page_step_configs 的Step 9中预设SEO信息,并在生成HTML时正确嵌入。
数据校验: 对用户输入的各项配置进行严格校验,确保数据质量和后续流程的顺利进行。
AI文章生成系统开发文档
1. 模块概述
本模块旨在自动化生成高质量文章内容。其核心流程包括:关键词扩展、话题发现、内容生成配置、调用AI模型(如Dify)生成文章、以及对生成内容进行SEO优化和结构化处理。
2. 功能流程详解
2.1 关键词获取与扩展
目标: 基于初始关键词,通过搜索引擎API挖掘相关长尾词,丰富关键词库。
输入:
一个或多个初始关键词(逗号分隔,最多3个)。
企业ID (用于数据隔离和去重)。
可选:用户上传的关键词文件。
处理逻辑:
解析输入: 将逗号分隔的关键词字符串拆分为单个关键词列表。
API调用:
对列表中的每个关键词,分别调用 SearchAPI。
百度API: https://www.searchapi.io/api/v1/search?engine=baidu&q={keyword}&api_key={YOUR_API_KEY}
Google API (简化版): https://www.searchapi.io/api/v1/search?engine=google_light&q={keyword}&api_key={YOUR_API_KEY}
Google API (完整版): https://www.searchapi.io/api/v1/search?engine=google&q={keyword}&api_key={YOUR_API_KEY} (根据需求选择)
注意: 根据实际需求,可能需要设置 gl, hl, lr, domain 等参数以获取特定区域或语言的结果。
数据解析:
从API响应中提取 related_searches 字段(百度/Google Light/Google)。
数据存储:
将提取到的新关键词存入 ai_keywords 表。
使用 company_id 进行关联,并确保 keyword 字段在 company_id 范围内唯一 (uk_company_keyword)。如果关键词已存在,则忽略或更新计数(如 usage_count)。
用户交互:
界面回显: 将成功获取并存储的新关键词列表返回给前端界面展示。
文件导入: 提供接口支持用户上传符合固定格式的关键词文件,解析后批量存入 ai_keywords 表。
关键词加载: 提供接口,按企业ID (company_id) 查询 ai_keywords 表,并根据 usage_count 升序排序返回关键词列表供用户选择。
输出: 更新后的关键词库,前端展示的关键词列表。
2.2 话题发现与参考来源
目标: 根据选中的关键词,利用不同数据源挖掘潜在的文章主题和参考链接。
输入:
用户选中的一个或多个关键词。
用户选择的“话题参考来源”配置(来自 ai_search_sources_api 表)。
处理逻辑:
配置读取: 根据用户选择,从 ai_search_sources_api 表读取对应来源的配置 (name, source_type, api_config, result_parser)。
API请求构建: 根据 api_config 中的规则(如 engine, q 的拼接方式),为每个选中的关键词构建具体的 SearchAPI 请求URL。
示例(根据您提供的配置):
百度前10: engine=baidu&q={keyword}
谷歌前10: engine=google_light&q={keyword} (或 engine=google)
谷歌 also ask: engine=google_light&q={keyword} (解析 related_questions)
百度大家还在搜: engine=baidu&q={keyword} (解析 people_also_search_for - 注意:百度API响应字段可能不同,请核实)
知乎前10: engine=baidu&q=site:zhihu.com {keyword}
维基百科: engine=google_light&q=site:wikipedia.org {keyword} (或 engine=google)
百家号前10: engine=baidu&q=site:baijiahao.baidu.com {keyword}
Quora前10: engine=google_light&q=site:quora.com {keyword} (或 engine=google)
Linkedin前10: engine=google_light&q=site:linkedin.com {keyword} (或 engine=google)
API调用与数据解析:
执行构建好的API请求。
根据 result_parser 中的规则(如提取 organic_results, related_questions, people_also_search_for),解析API响应,提取所需数据(通常是标题、链接)。
结果整合: 将所有来源返回的话题/链接进行整合,去重(基于链接),并可能根据来源权重或相关性进行排序。
输出: 一个包含潜在主题和参考链接的列表。
2.3 内容生成配置
目标: 收集用户对于即将生成文章的具体要求和参数。
输入:
文章主题/标题: 用户手动输入或从上一步话题发现中选择。
参考链接: 用户手动输入或从上一步话题发现中选择并勾选“高度参考”。
生成参数:
写作语言 (e.g., 中文, English)
文章类型 (e.g., 产品介绍) - 关联 ai_article_types 表
适用平台 (e.g., 官网博客)
AI模型 (e.g., GPT-4, Claude) - 与Dify配置关联
文章长度 (e.g., 800-1500字符)
风格要求 (e.g., 口语化, 去除AI味)
SEO选项 (e.g., 自动优化关键词布局, 生成FAQ, 生成结构化数据)
媒体选项 (e.g., AI配图, 自主配图, 视频嵌入)
权威证明 (e.g., 自动化, 自定义)
版本数 (e.g., 生成3个不同版本)
关键词链接: 用户指定主关键词和辅关键词及其对应的内链URL。
知识库: 用户选择引用企业自有知识库或上传本地文档。
处理逻辑:
表单验证: 确保必填项已填写,参数合法。
任务记录: 将用户提交的所有配置信息、选中的关键词、主题、参考链接等存入 ai_article_generation_tasks 表。
关联关系: 在 ai_task_keywords 表中记录任务与关键词的关联关系,并标记主关键词。
知识库处理:
如果选择“引用知识库”,记录关联的知识库ID。
如果选择“参考知识库上传”,调用文件上传服务,将文档解析为文本,并将解析后的文本内容或文件ID记录在任务表的 reference_content 或通过 ai_task_knowledge_files 表关联。
Dify API配置选择:
根据是否使用自有知识库,从 ai_dify_api_configs 表中选择合适的配置 (dify_api_config_id) 关联到任务。
输出: 创建成功的任务记录 (ai_article_generation_tasks ID)。
2.4 调用AI模型生成文章 (Dify)
目标: 将配置好的任务信息发送给Dify API,触发文章生成过程。
输入:
ai_article_generation_tasks 表中的任务记录。
从关联表中获取的关键词、主题、参考链接、生成参数等。
处理逻辑:
数据组装: 根据Dify API的要求,将任务信息、关键词、主题、参考内容、生成参数(如Prompt模板、风格、长度)等组装成API请求体。
API调用: 调用选定的Dify API配置 (ai_dify_api_configs) 对应的接口,发起文章生成请求。
异步处理: Dify处理通常需要时间,应采用异步方式。可以轮询Dify API状态,或等待Dify回调。
输出: Dify返回的生成结果(可能包含多个版本)。
2.5 结果处理与优化
目标: 接收AI生成的原始内容,并根据配置进行后续处理和优化。
输入:
Dify返回的原始文章内容(文本和HTML)、FAQ、结构化数据等。
任务配置中的优化选项。
处理逻辑:
版本存储: 将每个生成的版本分别存入 ai_generated_articles 表,使用相同的 task_id 和不同的 version 号。
关键词关联: 在 ai_article_keywords 表中记录生成文章与实际使用关键词的关联关系。
SEO优化 (可选):
分析文章内容和关键词密度,进行微调(此步骤复杂,通常由AI模型在生成时处理,或作为后处理插件)。
FAQ处理 (可选): 将Dify生成的FAQ部分存入 ai_generated_articles 表的 faq_section 字段(JSON格式)。
结构化数据 (可选): 将Dify生成的JSON-LD结构化数据存入 ai_generated_articles 表的 structured_data 字段,或存入单独的 ai_article_structured_data 表。
媒体处理 (可选):
AI配图: 根据文章内容或用户提示,调用如 Pollinations 等API生成图片,并将图片信息存入 ai_article_media 表。
自主配图/视频: 记录用户提供的图片/视频URL和描述信息到 ai_article_media 表。
权威证明 (可选): 根据配置生成 sameAs 等信息(可能需要嵌入到结构化数据中)。
输出: 存储在数据库中的、经过处理和优化的多个文章版本。
3. 数据库表关系梳理 (基于提供内容)
ai_keywords: 存储关键词及其元数据。
ai_search_sources_api: 存储话题来源的API配置。
ai_article_generation_tasks: 存储每次生成任务的配置和状态。
ai_task_keywords: 任务与关键词的规划关联。
ai_generated_articles: 存储AI生成的最终文章内容(多版本)。
ai_article_keywords: 文章与实际使用关键词的关联。
ai_article_topics: 文章与话题的关联(如果需要)。
ai_article_media: 文章关联的图片、视频等媒体资源。
ai_task_knowledge_files: 任务使用的上传知识库文件。
ai_dify_api_configs: Dify API的配置信息。
ai_prompt_templates: Prompt模板(如果使用)。
ai_article_types: 文章类型定义。
ai_article_structured_data: (可选) 文章结构化数据单独存储。
4. 开发建议
模块化设计:
将流程拆分为独立的服务或函数:关键词扩展服务、话题发现服务、任务创建服务、Dify调用服务、结果处理服务。
异步处理:
话题发现、Dify调用、结果优化等耗时操作应使用消息队列(如 RabbitMQ, Redis Queue)或异步任务框架(如 Celery)处理,避免阻塞用户界面。
API调用容错:
对SearchAPI和Dify API的调用实现重试机制和错误处理(如超时、API限制、返回错误码)。
配置管理:
将API Key (vAvKvXELE3fyDCp6ZXhTGd9e)、Dify配置、SearchAPI参数等敏感信息和可变配置存放在环境变量或配置中心,而非硬编码。
缓存策略:
对于频繁请求的相同关键词的 related_searches 结果,可以考虑使用缓存(如 Redis)来减少API调用次数和成本。
前端交互:
提供清晰的步骤引导用户完成流程。
实现关键词加载、话题列表展示、任务配置表单、生成进度提示、多版本结果展示等功能。
日志记录:
详细记录每个步骤的操作日志和API调用日志,便于调试和问题追踪。
权限控制:
确保用户只能访问和操作其所属企业的数据(基于 company_id)。
数据校验与清洗:
对从API获取的数据(如关键词、链接、文章内容)进行必要的清洗和校验,防止注入攻击或无效数据。
SEO优化深度:
基础的关键词密度检查可以实现,但复杂的SEO优化(如语义分析、可读性评分)建议依赖AI模型能力或集成专业SEO工具。
... ...
# AIGEO 内容生成平台 API 接口文档
本文档为 Vue3 前端开发工程师提供完整的 API 接口说明,包括接口地址、请求方法、参数说明和返回结果等。
## 1. 认证相关接口
### 1.1 用户登录
**接口地址**: `POST /api/auth/login`
**接口说明**: 用户登录认证
**请求参数**:
```json
{
"username": "string", // 用户名或邮箱
"password": "string" // 密码
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"token": "string", // 访问令牌
"refreshToken": "string", // 刷新令牌
"expiresIn": 0, // 过期时间(秒)
"user": {
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string"
}
}
}
```
### 1.2 用户注册
**接口地址**: `POST /api/auth/register`
**接口说明**: 新用户注册
**请求参数**:
```json
{
"username": "string", // 用户名
"email": "string", // 邮箱
"password": "string", // 密码
"fullName": "string" // 姓名
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0
}
}
```
### 1.3 刷新令牌
**接口地址**: `POST /api/auth/refresh`
**接口说明**: 使用刷新令牌获取新的访问令牌
**请求参数**:
```json
{
"refreshToken": "string"
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"token": "string",
"refreshToken": "string",
"expiresIn": 0
}
}
```
## 2. 用户管理接口
### 2.1 分页查询用户列表
**接口地址**: `GET /api/users/list`
**接口说明**: 支持按用户名、邮箱、角色等条件分页查询用户列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
| sortBy | string | 否 | 排序字段 |
| sortDir | string | 否 | 排序方向(asc/desc) |
| username | string | 否 | 用户名筛选 |
| email | string | 否 | 邮箱筛选 |
| role | string | 否 | 角色筛选 |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
### 2.2 获取所有用户
**接口地址**: `GET /api/users`
**接口说明**: 获取所有用户列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 2.3 根据ID获取用户
**接口地址**: `GET /api/users/{id}`
**接口说明**: 根据用户ID获取用户详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 2.4 根据公司ID获取用户列表
**接口地址**: `GET /api/users/company/{companyId}`
**接口说明**: 根据公司ID获取用户列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 2.5 创建用户
**接口地址**: `POST /api/users`
**接口说明**: 创建新用户
**请求参数**:
```json
{
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 2.6 更新用户
**接口地址**: `PUT /api/users/{id}`
**接口说明**: 根据用户ID更新用户信息
**请求参数**:
```json
{
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"username": "string",
"email": "string",
"fullName": "string",
"role": "string",
"companyId": 0,
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 2.7 删除用户
**接口地址**: `DELETE /api/users/{id}`
**接口说明**: 根据用户ID删除用户
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 3. 公司管理接口
### 3.1 分页查询公司列表
**接口地址**: `GET /api/companies/list`
**接口说明**: 支持按公司名称、状态等条件分页查询公司列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
| sortBy | string | 否 | 排序字段 |
| sortDir | string | 否 | 排序方向(asc/desc) |
| name | string | 否 | 公司名称筛选 |
| status | string | 否 | 状态筛选 |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {},
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
### 3.2 获取所有公司
**接口地址**: `GET /api/companies`
**接口说明**: 获取所有公司列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {},
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 3.3 根据ID获取公司
**接口地址**: `GET /api/companies/{id}`
**接口说明**: 根据公司ID获取公司详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {},
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 3.4 创建公司
**接口地址**: `POST /api/companies`
**接口说明**: 创建新公司
**请求参数**:
```json
{
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {}
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {},
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 3.5 更新公司
**接口地址**: `PUT /api/companies/{id}`
**接口说明**: 根据公司ID更新公司信息
**请求参数**:
```json
{
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {}
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"subdomain": "string",
"planType": "string",
"maxUsers": 0,
"maxArticlesPerMonth": 0,
"status": "string",
"trialExpiryDate": "2023-01-01T00:00:00",
"defaultSettings": {},
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 3.6 删除公司
**接口地址**: `DELETE /api/companies/{id}`
**接口说明**: 根据公司ID删除公司
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 4. AI配置管理接口
### 4.1 获取所有AI配置
**接口地址**: `GET /api/ai-configs`
**接口说明**: 获取所有AI配置列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 4.2 分页查询AI配置
**接口地址**: `GET /api/ai-configs/list`
**接口说明**: 分页查询AI配置列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
### 4.3 根据ID获取AI配置
**接口地址**: `GET /api/ai-configs/{id}`
**接口说明**: 根据配置ID获取AI配置详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 4.4 根据公司ID获取AI配置
**接口地址**: `GET /api/ai-configs/company/{companyId}`
**接口说明**: 根据公司ID获取AI配置列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 4.5 获取共享的AI配置
**接口地址**: `GET /api/ai-configs/shared`
**接口说明**: 获取共享的AI配置列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 4.6 获取激活的AI配置
**接口地址**: `GET /api/ai-configs/active`
**接口说明**: 获取激活的AI配置列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 4.7 创建AI配置
**接口地址**: `POST /api/ai-configs`
**接口说明**: 创建新的AI配置
**请求参数**:
```json
{
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 4.8 更新AI配置
**接口地址**: `PUT /api/ai-configs/{id}`
**接口说明**: 根据配置ID更新AI配置
**请求参数**:
```json
{
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"provider": "string",
"name": "string",
"baseUrl": "string",
"apiKey": "string",
"modelName": "string",
"temperature": 0,
"topP": 0,
"maxTokens": 0,
"requestHeaders": {},
"isActive": true,
"isShared": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 4.9 删除AI配置
**接口地址**: `DELETE /api/ai-configs/{id}`
**接口说明**: 根据配置ID删除AI配置
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 5. 文章生成任务管理接口
### 5.1 分页查询文章生成任务列表
**接口地址**: `GET /api/article-tasks/list`
**接口说明**: 支持按任务状态、用户、公司等条件分页查询文章生成任务列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
| sortBy | string | 否 | 排序字段 |
| sortDir | string | 否 | 排序方向(asc/desc) |
| status | string | 否 | 任务状态筛选 |
| userId | integer | 否 | 用户ID筛选 |
| companyId | integer | 否 | 公司ID筛选 |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"title": "string",
"description": "string",
"keywords": "string",
"aiTasteLevel": "string",
"status": "string",
"referenceUrls": [],
"generatedContent": "string",
"errorMessage": "string",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00",
"scheduledAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
## 6. 关键词管理接口
### 6.1 分页查询关键词列表
**接口地址**: `GET /api/keywords/list`
**接口说明**: 支持按关键词、状态、公司等条件分页查询关键词列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
| sortBy | string | 否 | 排序字段 |
| sortDir | string | 否 | 排序方向(asc/desc) |
| keyword | string | 否 | 关键词筛选 |
| status | string | 否 | 状态筛选 |
| companyId | integer | 否 | 公司ID筛选 |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
### 6.2 获取所有关键词
**接口地址**: `GET /api/keywords`
**接口说明**: 获取所有关键词列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 6.3 根据ID获取关键词
**接口地址**: `GET /api/keywords/{id}`
**接口说明**: 根据关键词ID获取关键词详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 6.4 根据公司ID获取关键词列表
**接口地址**: `GET /api/keywords/company/{companyId}`
**接口说明**: 根据公司ID获取关键词列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 6.5 根据公司ID和状态获取关键词列表
**接口地址**: `GET /api/keywords/company/{companyId}/status/{status}`
**接口说明**: 根据公司ID和状态获取关键词列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 6.6 创建关键词
**接口地址**: `POST /api/keywords`
**接口说明**: 创建新的关键词
**请求参数**:
```json
{
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 6.7 更新关键词
**接口地址**: `PUT /api/keywords/{id}`
**接口说明**: 根据关键词ID更新关键词信息
**请求参数**:
```json
{
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"keyword": "string",
"searchVolume": 0,
"competition": "string",
"status": "string",
"source": "string",
"sourceTaskId": 0,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 6.8 删除关键词
**接口地址**: `DELETE /api/keywords/{id}`
**接口说明**: 根据关键词ID删除关键词
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 7. 话题管理接口
### 7.1 获取所有话题
**接口地址**: `GET /api/topics`
**接口说明**: 获取所有话题列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 7.2 根据ID获取话题
**接口地址**: `GET /api/topics/{id}`
**接口说明**: 根据话题ID获取话题详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 7.3 根据公司ID获取话题列表
**接口地址**: `GET /api/topics/company/{companyId}`
**接口说明**: 根据公司ID获取话题列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 7.4 根据公司ID和状态获取话题列表
**接口地址**: `GET /api/topics/company/{companyId}/status/{status}`
**接口说明**: 根据公司ID和状态获取话题列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 7.5 根据来源任务ID获取话题列表
**接口地址**: `GET /api/topics/source-task/{sourceTaskId}`
**接口说明**: 根据来源任务ID获取话题列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 7.6 创建话题
**接口地址**: `POST /api/topics`
**接口说明**: 创建新话题
**请求参数**:
```json
{
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": []
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 7.7 更新话题
**接口地址**: `PUT /api/topics/{id}`
**接口说明**: 根据话题ID更新话题信息
**请求参数**:
```json
{
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": []
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"title": "string",
"description": "string",
"sourceUrl": "string",
"status": "string",
"sourceTaskId": 0,
"keywords": [],
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 7.8 删除话题
**接口地址**: `DELETE /api/topics/{id}`
**接口说明**: 根据话题ID删除话题
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 8. 发布平台管理接口
### 8.1 分页查询发布平台列表
**接口地址**: `GET /api/platforms/list`
**接口说明**: 支持按平台名称、类型、状态等条件分页查询发布平台列表
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| page | integer | 否 | 页码(默认0) |
| size | integer | 否 | 每页大小(默认10) |
| sortBy | string | 否 | 排序字段 |
| sortDir | string | 否 | 排序方向(asc/desc) |
| name | string | 否 | 平台名称筛选 |
| type | string | 否 | 平台类型筛选 |
| status | string | 否 | 状态筛选 |
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"content": [
{
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 10,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"first": true,
"numberOfElements": 0,
"empty": false
}
}
```
### 8.2 获取所有发布平台
**接口地址**: `GET /api/platforms`
**接口说明**: 获取所有发布平台列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 8.3 根据ID获取发布平台
**接口地址**: `GET /api/platforms/{id}`
**接口说明**: 根据发布平台ID获取平台详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 8.4 根据类型ID获取发布平台列表
**接口地址**: `GET /api/platforms/type/{typeId}`
**接口说明**: 根据类型ID获取发布平台列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 8.5 获取激活的发布平台列表
**接口地址**: `GET /api/platforms/active`
**接口说明**: 获取激活的发布平台列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 8.6 根据类型ID获取激活的发布平台列表
**接口地址**: `GET /api/platforms/type/{typeId}/active`
**接口说明**: 根据类型ID获取激活的发布平台列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 8.7 根据编码获取发布平台
**接口地址**: `GET /api/platforms/code/{code}`
**接口说明**: 根据编码获取发布平台
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 8.8 创建发布平台
**接口地址**: `POST /api/platforms`
**接口说明**: 创建新的发布平台
**请求参数**:
```json
{
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 8.9 更新发布平台
**接口地址**: `PUT /api/platforms/{id}`
**接口说明**: 根据发布平台ID更新平台信息
**请求参数**:
```json
{
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"type": "string",
"description": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 8.10 删除发布平台
**接口地址**: `DELETE /api/platforms/{id}`
**接口说明**: 根据发布平台ID删除平台
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 9. 网站项目管理接口
### 9.1 获取所有网站项目
**接口地址**: `GET /api/website-projects`
**接口说明**: 获取所有网站项目列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 9.2 根据ID获取网站项目
**接口地址**: `GET /api/website-projects/{id}`
**接口说明**: 根据网站项目ID获取项目详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 9.3 根据公司ID获取网站项目列表
**接口地址**: `GET /api/website-projects/company/{companyId}`
**接口说明**: 根据公司ID获取网站项目列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 9.4 根据用户ID获取网站项目列表
**接口地址**: `GET /api/website-projects/user/{userId}`
**接口说明**: 根据用户ID获取网站项目列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 9.5 根据状态获取网站项目列表
**接口地址**: `GET /api/website-projects/status/{status}`
**接口说明**: 根据状态获取网站项目列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 9.6 根据公司ID和状态获取网站项目列表
**接口地址**: `GET /api/website-projects/company/{companyId}/status/{status}`
**接口说明**: 根据公司ID和状态获取网站项目列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 9.7 创建网站项目
**接口地址**: `POST /api/website-projects`
**接口说明**: 创建新的网站项目
**请求参数**:
```json
{
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string"
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 9.8 更新网站项目
**接口地址**: `PUT /api/website-projects/{id}`
**接口说明**: 根据网站项目ID更新项目信息
**请求参数**:
```json
{
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string"
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"companyId": 0,
"userId": 0,
"name": "string",
"domain": "string",
"subdomain": "string",
"status": "string",
"templateId": 0,
"seoSettings": {},
"analyticsCode": "string",
"customCss": "string",
"customJs": "string",
"deployedAt": "2023-01-01T00:00:00",
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 9.9 删除网站项目
**接口地址**: `DELETE /api/website-projects/{id}`
**接口说明**: 根据网站项目ID删除项目
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 10. 落地页模板管理接口
### 10.1 获取所有落地页模板
**接口地址**: `GET /api/landing-page-templates`
**接口说明**: 获取所有落地页模板列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 10.2 根据ID获取落地页模板
**接口地址**: `GET /api/landing-page-templates/{id}`
**接口说明**: 根据落地页模板ID获取模板详情
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 10.3 获取激活的落地页模板列表
**接口地址**: `GET /api/landing-page-templates/active`
**接口说明**: 获取激活的落地页模板列表
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": [
{
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
]
}
```
### 10.4 根据编码获取落地页模板
**接口地址**: `GET /api/landing-page-templates/code/{code}`
**接口说明**: 根据编码获取落地页模板
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 10.5 创建落地页模板
**接口地址**: `POST /api/landing-page-templates`
**接口说明**: 创建新的落地页模板
**请求参数**:
```json
{
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 10.6 更新落地页模板
**接口地址**: `PUT /api/landing-page-templates/{id}`
**接口说明**: 根据落地页模板ID更新模板信息
**请求参数**:
```json
{
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true
}
```
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": {
"id": 0,
"name": "string",
"code": "string",
"description": "string",
"previewImageUrl": "string",
"htmlTemplate": "string",
"cssStyles": "string",
"jsScripts": "string",
"configSchema": {},
"isActive": true,
"createdAt": "2023-01-01T00:00:00",
"updatedAt": "2023-01-01T00:00:00"
}
}
```
### 10.7 删除落地页模板
**接口地址**: `DELETE /api/landing-page-templates/{id}`
**接口说明**: 根据落地页模板ID删除模板
**响应结果**:
```json
{
"code": 200,
"message": "操作成功",
"data": null
}
```
## 通用响应格式
所有API接口都使用统一的响应格式:
```json
{
"code": 200, // 状态码
"message": "操作成功", // 消息说明
"data": {} // 返回数据
}
```
### 常用状态码
| 状态码 | 说明 |
| --- | --- |
| 200 | 操作成功 |
| 400 | 请求参数错误 |
| 401 | 未授权访问 |
| 403 | 禁止访问 |
| 404 | 资源未找到 |
| 500 | 系统内部错误 |
## 认证方式
除登录、注册等开放接口外,其他接口都需要在请求头中添加认证信息:
```
Authorization: Bearer {token}
X-Tenant-ID: {tenantId}
```
其中:
- `{token}` 为登录成功后返回的访问令牌
- `{tenantId}` 为租户ID,用于多租户数据隔离
业务概述
Company模块负责管理系统中的公司(租户)信息,是整个多租户架构的核心。每个公司作为一个独立的租户,拥有自己的用户、配置和数据。
处理的具体业务
公司信息管理:创建、查询、更新、删除公司信息
多租户支持:通过子域名识别不同公司
套餐管理:支持不同的套餐类型和配额限制
状态管理:管理公司的试用、激活、暂停等状态
搜索功能:支持按关键词搜索公司
数据表字段
操作的数据表是 ai_companies,包含以下字段:
字段名
类型
说明
id
Integer
主键,自增ID
name
String
公司名称
subdomain
String
子域名,唯一标识
plan_type
PlanType枚举
套餐类型(FREE/TRIAL/BASIC/PREMIUM/ENTERPRISE)
max_users
Integer
最大用户数
max_articles_per_month
Integer
每月最大文章数
status
CompanyStatus枚举
公司状态(TRIAL/ACTIVE/SUSPENDED)
trial_expiry_date
LocalDate
试用期到期日期
default_settings
String (JSON)
默认配置(JSON格式)
created_at
LocalDateTime
创建时间
updated_at
LocalDateTime
更新时间
操作的数据表
主表:ai_companies - 存储公司基本信息
索引:在subdomain字段上建立了唯一索引uk_companies_subdomain
提供的API接口
GET /api/companies/list - 分页查询公司列表
GET /api/companies - 获取所有公司
GET /api/companies/{id} - 根据ID查询公司详情
GET /api/companies/subdomain/{subdomain} - 根据子域名查询公司
GET /api/companies/active - 查询活跃公司列表
POST /api/companies - 创建新公司
PUT /api/companies/{id} - 更新公司信息
PUT /api/companies/batch-status - 批量更新公司状态
DELETE /api/companies/{id} - 删除公司(软删除)
GET /api/companies/search - 搜索公司
这个模块是整个系统多租户架构的基础,所有其他业务模块都会关联到公司(租户)维度进行数据隔离。
\ No newline at end of file
... ...