This commit is contained in:
2025-08-28 00:55:35 +08:00
commit 410f54a65e
93 changed files with 9863 additions and 0 deletions

View File

@ -0,0 +1,10 @@
[package]
name = "migration"
version = "0.1.0"
edition = "2021"
[dependencies]
sea-orm-migration = { version = "1.1.14" }
argon2 = "0.5"
chrono = { version = "0.4", features = ["serde"] }
rand = "0.8"

View File

@ -0,0 +1,34 @@
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_users;
mod m20220101_000002_create_refresh_tokens;
mod m20220101_000003_create_roles;
mod m20220101_000004_create_permissions;
mod m20220101_000005_create_menus;
mod m20220101_000006_create_rbac_relations;
mod m20220101_000007_create_departments;
mod m20220101_000008_add_keep_alive_to_menus;
mod m20220101_000009_create_request_logs;
// 新增岗位与用户岗位关联
mod m20220101_000010_create_positions;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220101_000001_create_users::Migration),
Box::new(m20220101_000002_create_refresh_tokens::Migration),
Box::new(m20220101_000003_create_roles::Migration),
Box::new(m20220101_000004_create_permissions::Migration),
Box::new(m20220101_000005_create_menus::Migration),
Box::new(m20220101_000006_create_rbac_relations::Migration),
Box::new(m20220101_000007_create_departments::Migration),
Box::new(m20220101_000008_add_keep_alive_to_menus::Migration),
Box::new(m20220101_000009_create_request_logs::Migration),
// 注册岗位迁移
Box::new(m20220101_000010_create_positions::Migration),
]
}
}

View File

@ -0,0 +1,65 @@
use sea_orm_migration::prelude::*;
use sea_orm_migration::sea_orm::DatabaseBackend;
use argon2::{Argon2, password_hash::{SaltString, PasswordHasher}};
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Users::Table)
.if_not_exists()
.col(ColumnDef::new(Users::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(Users::Username).string().not_null().unique_key())
.col(ColumnDef::new(Users::PasswordHash).string().not_null())
.col(ColumnDef::new(Users::Nickname).string().null())
.col(ColumnDef::new(Users::Status).integer().not_null().default(1))
.col(ColumnDef::new(Users::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(Users::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
// seed admin user (cross-DB)
let salt = SaltString::generate(&mut rand::thread_rng());
let hash = Argon2::default().hash_password("Admin@123".as_bytes(), &salt).unwrap().to_string();
let backend = manager.get_database_backend();
let conn = manager.get_connection();
match backend {
DatabaseBackend::MySql => {
conn.execute_unprepared(&format!(
"INSERT INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1) ON DUPLICATE KEY UPDATE username=username",
hash
))
.await?;
}
DatabaseBackend::Postgres => {
conn.execute_unprepared(&format!(
"INSERT INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1) ON CONFLICT (username) DO NOTHING",
hash
))
.await?;
}
DatabaseBackend::Sqlite => {
conn.execute_unprepared(&format!(
"INSERT OR IGNORE INTO users (username, password_hash, nickname, status) VALUES ('admin', '{}', 'Administrator', 1)",
hash
))
.await?;
}
}
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(Users::Table).to_owned()).await
}
}
#[derive(Iden)]
enum Users { Table, Id, Username, PasswordHash, Nickname, Status, CreatedAt, UpdatedAt }

View File

@ -0,0 +1,31 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(RefreshTokens::Table)
.if_not_exists()
.col(ColumnDef::new(RefreshTokens::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(RefreshTokens::UserId).big_integer().not_null())
.col(ColumnDef::new(RefreshTokens::TokenHash).string().not_null().unique_key())
.col(ColumnDef::new(RefreshTokens::ExpiresAt).timestamp().not_null())
.col(ColumnDef::new(RefreshTokens::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(RefreshTokens::Table).to_owned()).await
}
}
#[derive(Iden)]
enum RefreshTokens { Table, Id, UserId, TokenHash, ExpiresAt, CreatedAt }

View File

@ -0,0 +1,33 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Roles::Table)
.if_not_exists()
.col(ColumnDef::new(Roles::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(Roles::Name).string().not_null())
.col(ColumnDef::new(Roles::Code).string().not_null().unique_key())
.col(ColumnDef::new(Roles::Description).string().null())
.col(ColumnDef::new(Roles::Status).integer().not_null().default(1))
.col(ColumnDef::new(Roles::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(Roles::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(Roles::Table).to_owned()).await
}
}
#[derive(Iden)]
enum Roles { Table, Id, Name, Code, Description, Status, CreatedAt, UpdatedAt }

View File

@ -0,0 +1,17 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
// 占位迁移:原始迁移文件缺失,但已应用。此处为空实现以满足迁移链完整性。
Ok(())
}
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
// 占位迁移,无需回滚实际变更
Ok(())
}
}

View File

@ -0,0 +1,39 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Menus::Table)
.if_not_exists()
.col(ColumnDef::new(Menus::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(Menus::ParentId).big_integer().null())
.col(ColumnDef::new(Menus::Name).string().not_null())
.col(ColumnDef::new(Menus::Path).string().null())
.col(ColumnDef::new(Menus::Component).string().null())
.col(ColumnDef::new(Menus::Type).integer().not_null())
.col(ColumnDef::new(Menus::Icon).string().null())
.col(ColumnDef::new(Menus::OrderNo).integer().not_null().default(0))
.col(ColumnDef::new(Menus::Visible).boolean().not_null().default(true))
.col(ColumnDef::new(Menus::Status).integer().not_null().default(1))
.col(ColumnDef::new(Menus::Perms).string().null())
.col(ColumnDef::new(Menus::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(Menus::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(Menus::Table).to_owned()).await
}
}
#[derive(Iden)]
enum Menus { Table, Id, ParentId, Name, Path, Component, Type, Icon, OrderNo, Visible, Status, Perms, CreatedAt, UpdatedAt }

View File

@ -0,0 +1,46 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// user_roles
manager.create_table(
Table::create()
.table(UserRoles::Table)
.if_not_exists()
.col(ColumnDef::new(UserRoles::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(UserRoles::UserId).big_integer().not_null())
.col(ColumnDef::new(UserRoles::RoleId).big_integer().not_null())
.index(Index::create().name("idx_user_role_uniq").col(UserRoles::UserId).col(UserRoles::RoleId).unique())
.to_owned()
).await?;
// role_menus
manager.create_table(
Table::create()
.table(RoleMenus::Table)
.if_not_exists()
.col(ColumnDef::new(RoleMenus::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(RoleMenus::RoleId).big_integer().not_null())
.col(ColumnDef::new(RoleMenus::MenuId).big_integer().not_null())
.index(Index::create().name("idx_role_menu_uniq").col(RoleMenus::RoleId).col(RoleMenus::MenuId).unique())
.to_owned()
).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(RoleMenus::Table).to_owned()).await?;
manager.drop_table(Table::drop().table(UserRoles::Table).to_owned()).await
}
}
#[derive(Iden)]
enum UserRoles { Table, Id, UserId, RoleId }
#[derive(Iden)]
enum RoleMenus { Table, Id, RoleId, MenuId }

View File

@ -0,0 +1,53 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// departments
manager
.create_table(
Table::create()
.table(Departments::Table)
.if_not_exists()
.col(ColumnDef::new(Departments::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(Departments::ParentId).big_integer().null())
.col(ColumnDef::new(Departments::Name).string().not_null())
.col(ColumnDef::new(Departments::OrderNo).integer().not_null().default(0))
.col(ColumnDef::new(Departments::Status).integer().not_null().default(1))
.col(ColumnDef::new(Departments::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(Departments::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
// user_departments
manager
.create_table(
Table::create()
.table(UserDepartments::Table)
.if_not_exists()
.col(ColumnDef::new(UserDepartments::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(UserDepartments::UserId).big_integer().not_null())
.col(ColumnDef::new(UserDepartments::DepartmentId).big_integer().not_null())
.index(Index::create().name("idx_user_department_uniq").col(UserDepartments::UserId).col(UserDepartments::DepartmentId).unique())
.to_owned()
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(UserDepartments::Table).to_owned()).await?;
manager.drop_table(Table::drop().table(Departments::Table).to_owned()).await
}
}
#[derive(Iden)]
enum Departments { Table, Id, ParentId, Name, OrderNo, Status, CreatedAt, UpdatedAt }
#[derive(Iden)]
enum UserDepartments { Table, Id, UserId, DepartmentId }

View File

@ -0,0 +1,35 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(Menus::Table)
.add_column(ColumnDef::new(Menus::KeepAlive).boolean().not_null().default(true))
.to_owned()
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(Menus::Table)
.drop_column(Menus::KeepAlive)
.to_owned()
)
.await
}
}
#[derive(DeriveIden)]
enum Menus {
Table,
KeepAlive,
}

View File

@ -0,0 +1,49 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(RequestLogs::Table)
.if_not_exists()
.col(ColumnDef::new(RequestLogs::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(RequestLogs::Path).string().not_null())
.col(ColumnDef::new(RequestLogs::Method).string().not_null())
.col(ColumnDef::new(RequestLogs::RequestParams).text().null())
.col(ColumnDef::new(RequestLogs::ResponseParams).text().null())
.col(ColumnDef::new(RequestLogs::StatusCode).integer().not_null().default(200))
.col(ColumnDef::new(RequestLogs::UserId).big_integer().null())
.col(ColumnDef::new(RequestLogs::Username).string().null())
.col(ColumnDef::new(RequestLogs::RequestTime).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(RequestLogs::DurationMs).big_integer().not_null().default(0))
.col(ColumnDef::new(RequestLogs::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(RequestLogs::Table).to_owned()).await
}
}
#[derive(Iden)]
enum RequestLogs {
Table,
Id,
Path,
Method,
RequestParams,
ResponseParams,
StatusCode,
UserId,
Username,
RequestTime,
DurationMs,
CreatedAt,
}

View File

@ -0,0 +1,52 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// positions
manager
.create_table(
Table::create()
.table(Positions::Table)
.if_not_exists()
.col(ColumnDef::new(Positions::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(Positions::Name).string().not_null())
.col(ColumnDef::new(Positions::Code).string().not_null().unique_key())
.col(ColumnDef::new(Positions::Description).string().null())
.col(ColumnDef::new(Positions::Status).integer().not_null().default(1))
.col(ColumnDef::new(Positions::OrderNo).integer().not_null().default(0))
.col(ColumnDef::new(Positions::CreatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.col(ColumnDef::new(Positions::UpdatedAt).timestamp().not_null().default(Expr::current_timestamp()))
.to_owned()
)
.await?;
// user_positions
manager.create_table(
Table::create()
.table(UserPositions::Table)
.if_not_exists()
.col(ColumnDef::new(UserPositions::Id).big_integer().not_null().auto_increment().primary_key())
.col(ColumnDef::new(UserPositions::UserId).big_integer().not_null())
.col(ColumnDef::new(UserPositions::PositionId).big_integer().not_null())
.index(Index::create().name("idx_user_position_uniq").col(UserPositions::UserId).col(UserPositions::PositionId).unique())
.to_owned()
).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager.drop_table(Table::drop().table(UserPositions::Table).to_owned()).await?;
manager.drop_table(Table::drop().table(Positions::Table).to_owned()).await
}
}
#[derive(Iden)]
enum Positions { Table, Id, Name, Code, Description, Status, OrderNo, CreatedAt, UpdatedAt }
#[derive(Iden)]
enum UserPositions { Table, Id, UserId, PositionId }