2026-07-02 05:38:01 +08:00
|
|
|
|
//! 数据库迁移 — 自动建表
|
|
|
|
|
|
|
|
|
|
|
|
use sqlx::MySqlPool;
|
|
|
|
|
|
|
|
|
|
|
|
/// 执行数据库迁移,创建所有必要的数据表
|
|
|
|
|
|
pub async fn run(pool: &MySqlPool) -> Result<(), sqlx::Error> {
|
|
|
|
|
|
let sql = r#"
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS organizations (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
name VARCHAR(100) NOT NULL COMMENT '组织名称',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
organization_id BIGINT NOT NULL,
|
|
|
|
|
|
name VARCHAR(100) NOT NULL COMMENT '项目名称',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS cabinets (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
project_id BIGINT,
|
2026-07-03 02:45:00 +08:00
|
|
|
|
abstract_id VARCHAR(20) NULL UNIQUE COMMENT '平台抽象ID,如10-00000001',
|
2026-07-02 05:38:01 +08:00
|
|
|
|
imei VARCHAR(15) NOT NULL UNIQUE COMMENT '4G模块IMEI',
|
|
|
|
|
|
auth_str VARCHAR(8) COMMENT '签名安全码',
|
|
|
|
|
|
name VARCHAR(100) COMMENT '柜子名称',
|
|
|
|
|
|
status TINYINT DEFAULT 0 COMMENT '0离线 1在线',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS cabin_boards (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
cabinet_id BIGINT NOT NULL,
|
|
|
|
|
|
board_id TINYINT NOT NULL COMMENT '仓控板ID 1-6',
|
|
|
|
|
|
status TINYINT DEFAULT 0,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (cabinet_id) REFERENCES cabinets(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS compartments (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
cabin_board_id BIGINT NOT NULL,
|
|
|
|
|
|
channel_id TINYINT NOT NULL COMMENT '通道ID 1-6',
|
|
|
|
|
|
status TINYINT DEFAULT 0 COMMENT '0空闲 1充电中 2故障 3禁用',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (cabin_board_id) REFERENCES cabin_boards(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
phone VARCHAR(11) NOT NULL UNIQUE COMMENT '手机号',
|
|
|
|
|
|
name VARCHAR(50) COMMENT '姓名',
|
|
|
|
|
|
password VARCHAR(255) NOT NULL,
|
|
|
|
|
|
role TINYINT DEFAULT 0 COMMENT '0普通 1企业管理员 2总管理员',
|
|
|
|
|
|
organization_id BIGINT,
|
|
|
|
|
|
status TINYINT DEFAULT 1 COMMENT '0禁用 1启用',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (organization_id) REFERENCES organizations(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS charge_records (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
compartment_id BIGINT NOT NULL,
|
|
|
|
|
|
cabinet_id BIGINT NOT NULL,
|
2026-07-02 15:18:45 +08:00
|
|
|
|
start_time TIMESTAMP NULL COMMENT '充电开始时间',
|
|
|
|
|
|
end_time TIMESTAMP NULL COMMENT '充电结束时间',
|
2026-07-04 04:03:02 +08:00
|
|
|
|
energy BIGINT NOT NULL DEFAULT 0 COMMENT '充电量(Wh)',
|
|
|
|
|
|
max_temperature BIGINT NOT NULL DEFAULT 0 COMMENT '最高温度(0.1°C)',
|
2026-07-02 05:38:01 +08:00
|
|
|
|
status TINYINT DEFAULT 0 COMMENT '0正常 1异常 2手动停止',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (compartment_id) REFERENCES compartments(id),
|
|
|
|
|
|
FOREIGN KEY (cabinet_id) REFERENCES cabinets(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS device_logs (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
cabinet_id BIGINT NOT NULL,
|
|
|
|
|
|
log_type TINYINT NOT NULL COMMENT '1状态上报 2故障 3告警 4停电',
|
|
|
|
|
|
content TEXT COMMENT '日志内容JSON',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (cabinet_id) REFERENCES cabinets(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS energy_stats (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
cabinet_id BIGINT NOT NULL,
|
|
|
|
|
|
stat_date DATE NOT NULL,
|
2026-07-04 04:03:02 +08:00
|
|
|
|
total_energy BIGINT NOT NULL DEFAULT 0 COMMENT '总能耗(Wh)',
|
2026-07-02 05:38:01 +08:00
|
|
|
|
charge_count INT DEFAULT 0 COMMENT '充电次数',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (cabinet_id) REFERENCES cabinets(id),
|
|
|
|
|
|
UNIQUE KEY uk_cabinet_date (cabinet_id, stat_date)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS operation_logs (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
user_id BIGINT NOT NULL,
|
|
|
|
|
|
action VARCHAR(100) NOT NULL COMMENT '操作动作',
|
|
|
|
|
|
target_type VARCHAR(50) COMMENT '操作对象类型',
|
|
|
|
|
|
target_id BIGINT COMMENT '操作对象ID',
|
|
|
|
|
|
detail TEXT COMMENT '操作详情',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS roles (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
name VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称',
|
|
|
|
|
|
description VARCHAR(200) COMMENT '角色描述',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS permissions (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
code VARCHAR(50) NOT NULL UNIQUE COMMENT '权限码,如device:view',
|
|
|
|
|
|
name VARCHAR(100) NOT NULL COMMENT '权限名称',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS role_permissions (
|
|
|
|
|
|
role_id BIGINT NOT NULL,
|
|
|
|
|
|
permission_id BIGINT NOT NULL,
|
|
|
|
|
|
PRIMARY KEY (role_id, permission_id),
|
|
|
|
|
|
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
|
|
|
|
|
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS user_roles (
|
|
|
|
|
|
user_id BIGINT NOT NULL,
|
|
|
|
|
|
role_id BIGINT NOT NULL,
|
|
|
|
|
|
PRIMARY KEY (user_id, role_id),
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
|
|
|
|
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS user_scopes (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
user_id BIGINT NOT NULL,
|
|
|
|
|
|
scope_type TINYINT NOT NULL COMMENT '1组织 2项目 3设备',
|
|
|
|
|
|
scope_id BIGINT NOT NULL COMMENT '对应组织/项目/设备ID',
|
|
|
|
|
|
permission_type TINYINT NOT NULL COMMENT '1查看 2操作',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS download_tasks (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
user_id BIGINT NOT NULL,
|
|
|
|
|
|
task_type VARCHAR(50) NOT NULL COMMENT 'charge_records/energy_stats/device_logs',
|
|
|
|
|
|
status TINYINT DEFAULT 0 COMMENT '0排队 1处理中 2完成 3失败',
|
|
|
|
|
|
file_path VARCHAR(500) COMMENT '文件路径',
|
|
|
|
|
|
file_name VARCHAR(200) COMMENT '文件名',
|
|
|
|
|
|
progress INT DEFAULT 0 COMMENT '进度百分比',
|
|
|
|
|
|
error_message TEXT,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
2026-07-02 15:18:45 +08:00
|
|
|
|
completed_at TIMESTAMP NULL COMMENT '完成时间',
|
2026-07-02 05:38:01 +08:00
|
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
2026-07-03 02:45:00 +08:00
|
|
|
|
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS abstract_bindings (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
abstract_id VARCHAR(20) NOT NULL UNIQUE COMMENT '平台抽象ID,如10-00000001',
|
|
|
|
|
|
cabinet_id BIGINT NOT NULL UNIQUE COMMENT '柜子ID',
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
FOREIGN KEY (cabinet_id) REFERENCES cabinets(id) ON DELETE CASCADE
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
2026-07-02 05:38:01 +08:00
|
|
|
|
"#;
|
|
|
|
|
|
|
|
|
|
|
|
// 逐条执行,避免多语句执行问题
|
|
|
|
|
|
for statement in sql.split(';').map(|s| s.trim()).filter(|s| !s.is_empty()) {
|
|
|
|
|
|
sqlx::query(statement).execute(pool).await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-03 02:45:00 +08:00
|
|
|
|
// 兼容已有数据库:将 abstract_id 改为可空
|
|
|
|
|
|
let _ = sqlx::query(r#"ALTER TABLE cabinets MODIFY abstract_id VARCHAR(20) NULL"#)
|
|
|
|
|
|
.execute(pool).await;
|
|
|
|
|
|
|
2026-07-02 05:38:01 +08:00
|
|
|
|
// 创建关键索引(IF NOT EXISTS 避免重复)
|
|
|
|
|
|
create_indexes(pool).await?;
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化默认权限码(INSERT IGNORE 避免重复插入)
|
|
|
|
|
|
seed_permissions(pool).await?;
|
|
|
|
|
|
// 初始化默认角色
|
|
|
|
|
|
seed_roles(pool).await?;
|
|
|
|
|
|
|
|
|
|
|
|
tracing::info!("数据库迁移完成");
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 创建关键查询索引(幂等,已存在则跳过)
|
|
|
|
|
|
async fn create_indexes(pool: &MySqlPool) -> Result<(), sqlx::Error> {
|
|
|
|
|
|
/// 辅助:检查索引是否存在,不存在则创建
|
|
|
|
|
|
async fn ensure_index(
|
|
|
|
|
|
pool: &MySqlPool,
|
|
|
|
|
|
table: &str,
|
|
|
|
|
|
index: &str,
|
|
|
|
|
|
columns: &str,
|
|
|
|
|
|
) -> Result<(), sqlx::Error> {
|
|
|
|
|
|
let exists: (i64,) = sqlx::query_as(
|
|
|
|
|
|
"SELECT COUNT(*) FROM information_schema.statistics \
|
|
|
|
|
|
WHERE table_schema = DATABASE() AND table_name = ? AND index_name = ?",
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(table)
|
|
|
|
|
|
.bind(index)
|
|
|
|
|
|
.fetch_one(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
if exists.0 == 0 {
|
|
|
|
|
|
let ddl = format!("CREATE INDEX {} ON {}({})", index, table, columns);
|
|
|
|
|
|
sqlx::query(&ddl).execute(pool).await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ensure_index(pool, "cabinets", "idx_cabinets_project", "project_id").await?;
|
|
|
|
|
|
ensure_index(pool, "cabin_boards", "idx_cabin_boards_cabinet", "cabinet_id").await?;
|
|
|
|
|
|
ensure_index(pool, "compartments", "idx_compartments_board", "cabin_board_id").await?;
|
|
|
|
|
|
ensure_index(pool, "charge_records", "idx_charge_records_cabinet", "cabinet_id").await?;
|
|
|
|
|
|
ensure_index(pool, "device_logs", "idx_device_logs_cabinet", "cabinet_id").await?;
|
|
|
|
|
|
|
|
|
|
|
|
tracing::info!("数据库索引创建完成");
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 插入默认权限码
|
|
|
|
|
|
async fn seed_permissions(pool: &MySqlPool) -> Result<(), sqlx::Error> {
|
|
|
|
|
|
let perms: Vec<(&str, &str)> = vec![
|
|
|
|
|
|
("device:view", "查看设备"),
|
|
|
|
|
|
("device:operate", "操作设备"),
|
|
|
|
|
|
("device:create", "添加设备"),
|
|
|
|
|
|
("device:edit", "编辑设备"),
|
|
|
|
|
|
("device:delete", "删除设备"),
|
|
|
|
|
|
("charge:start", "开始充电"),
|
|
|
|
|
|
("charge:stop", "停止充电"),
|
|
|
|
|
|
("charge:open_door", "开门"),
|
|
|
|
|
|
("charge_record:view", "查看充电记录"),
|
|
|
|
|
|
("charge_record:export", "导出充电记录"),
|
|
|
|
|
|
("device_log:view", "查看设备日志"),
|
|
|
|
|
|
("energy:view", "查看能耗"),
|
|
|
|
|
|
("energy:export", "导出能耗"),
|
|
|
|
|
|
("user:view", "查看用户"),
|
|
|
|
|
|
("user:create", "创建用户"),
|
|
|
|
|
|
("user:edit", "编辑用户"),
|
|
|
|
|
|
("user:delete", "删除用户"),
|
|
|
|
|
|
("role:view", "查看角色"),
|
|
|
|
|
|
("role:create", "创建角色"),
|
|
|
|
|
|
("role:edit", "编辑角色"),
|
|
|
|
|
|
("role:delete", "删除角色"),
|
|
|
|
|
|
("operation_log:view", "查看操作日志"),
|
|
|
|
|
|
// 组织管理
|
|
|
|
|
|
("org:view", "查看组织"),
|
|
|
|
|
|
("org:create", "创建组织"),
|
|
|
|
|
|
("org:edit", "编辑组织"),
|
|
|
|
|
|
("org:delete", "删除组织"),
|
|
|
|
|
|
// 项目管理
|
|
|
|
|
|
("project:view", "查看项目"),
|
|
|
|
|
|
("project:create", "创建项目"),
|
|
|
|
|
|
("project:edit", "编辑项目"),
|
|
|
|
|
|
("project:delete", "删除项目"),
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
for (code, name) in perms {
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO permissions (code, name) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(code)
|
|
|
|
|
|
.bind(name)
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tracing::info!("默认权限码初始化完成");
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 插入默认角色并分配权限
|
|
|
|
|
|
async fn seed_roles(pool: &MySqlPool) -> Result<(), sqlx::Error> {
|
|
|
|
|
|
// 创建总管理员角色
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO roles (name, description) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind("super_admin")
|
|
|
|
|
|
.bind("总管理员 — 全部权限")
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建企业管理员角色
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO roles (name, description) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind("org_admin")
|
|
|
|
|
|
.bind("企业管理员 — 管理本组织下项目/设备/人员")
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建普通用户角色
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO roles (name, description) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind("normal_user")
|
|
|
|
|
|
.bind("普通用户 — 查看/操作指定范围设备")
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
// 为总管理员分配所有权限
|
|
|
|
|
|
let super_admin_id: Option<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM roles WHERE name = 'super_admin'"
|
|
|
|
|
|
)
|
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
if let Some((role_id,)) = super_admin_id {
|
|
|
|
|
|
// 查询所有权限ID
|
|
|
|
|
|
let perm_ids: Vec<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM permissions"
|
|
|
|
|
|
)
|
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
for (perm_id,) in perm_ids {
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(role_id)
|
|
|
|
|
|
.bind(perm_id)
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为企业管理员分配非系统管理权限
|
|
|
|
|
|
let org_admin_id: Option<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM roles WHERE name = 'org_admin'"
|
|
|
|
|
|
)
|
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
let org_perm_codes = [
|
|
|
|
|
|
"device:view", "device:operate", "device:create", "device:edit",
|
|
|
|
|
|
"charge:start", "charge:stop", "charge:open_door",
|
|
|
|
|
|
"charge_record:view", "charge_record:export",
|
|
|
|
|
|
"device_log:view", "energy:view", "energy:export",
|
|
|
|
|
|
"user:view", "user:edit",
|
|
|
|
|
|
"operation_log:view",
|
|
|
|
|
|
// 组织管理
|
|
|
|
|
|
"org:view", "org:create", "org:edit", "org:delete",
|
|
|
|
|
|
// 项目管理
|
|
|
|
|
|
"project:view", "project:create", "project:edit", "project:delete",
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
if let Some((role_id,)) = org_admin_id {
|
|
|
|
|
|
for code in &org_perm_codes {
|
|
|
|
|
|
let perm: Option<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM permissions WHERE code = ?"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(code)
|
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
if let Some((perm_id,)) = perm {
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(role_id)
|
|
|
|
|
|
.bind(perm_id)
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为普通用户分配查看和操作权限
|
|
|
|
|
|
let normal_id: Option<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM roles WHERE name = 'normal_user'"
|
|
|
|
|
|
)
|
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
let normal_perm_codes = [
|
|
|
|
|
|
"device:view", "device:operate",
|
|
|
|
|
|
"charge:start", "charge:stop", "charge:open_door",
|
|
|
|
|
|
"charge_record:view", "device_log:view", "energy:view",
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
if let Some((role_id,)) = normal_id {
|
|
|
|
|
|
for code in &normal_perm_codes {
|
|
|
|
|
|
let perm: Option<(i64,)> = sqlx::query_as(
|
|
|
|
|
|
"SELECT id FROM permissions WHERE code = ?"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(code)
|
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
if let Some((perm_id,)) = perm {
|
|
|
|
|
|
sqlx::query(
|
|
|
|
|
|
"INSERT IGNORE INTO role_permissions (role_id, permission_id) VALUES (?, ?)"
|
|
|
|
|
|
)
|
|
|
|
|
|
.bind(role_id)
|
|
|
|
|
|
.bind(perm_id)
|
|
|
|
|
|
.execute(pool)
|
|
|
|
|
|
.await?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tracing::info!("默认角色及权限分配完成");
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|