功能修复: 1. 患者创建空名称验证:后端添加 name.trim().is_empty() 检查 2. 仪表盘统计容错:单个查询失败返回零值而非 500 3. FHIR 路由修复:从 /fhir 移到 /api/v1/fhir 保持一致 4. 冻结模块后端中间件:新增 frozen_module_middleware 拦截冻结路径 5. 积分端点权限码:health.health-data.list → health.points.list 6. 角色权限迁移:护士补充 devices.list,运营补充 points.list/manage 7. 测试结果文档:R01-R05 角色测试 + T00/T10 结果归档 Clippy 全 workspace 清零(14→0 errors): - erp-core: 修复 empty doc line、collapsible if、redundant closure 等 9 处 - erp-health: 修复 too_many_arguments、unused var、unnecessary parens 等 58 处 - erp-ai: 修复 dead_code、unused import 等 11 处 - erp-plugin: 修复 too_many_arguments、wildcard pattern 等 11 处 - erp-server-migration: 修复 enum_variant_names 5 处 - erp-auth/config/workflow/message: 各 1-3 处 工程改进: - lint-staged 配置迁移到 .lintstagedrc.js(函数式避免文件列表传给 clippy) - cargo fmt 统一格式化
75 lines
2.8 KiB
Rust
75 lines
2.8 KiB
Rust
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> {
|
||
// 分区表必须用 raw SQL,SeaORM schema builder 不支持 PARTITION BY
|
||
let sql = r#"
|
||
CREATE TABLE IF NOT EXISTS device_readings (
|
||
id UUID NOT NULL DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL,
|
||
patient_id UUID NOT NULL,
|
||
device_id VARCHAR(64),
|
||
device_type VARCHAR(32) NOT NULL,
|
||
device_model VARCHAR(64),
|
||
raw_value JSONB NOT NULL,
|
||
measured_at TIMESTAMPTZ NOT NULL,
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
deleted_at TIMESTAMPTZ
|
||
) PARTITION BY RANGE (measured_at);
|
||
"#;
|
||
manager.get_connection().execute_unprepared(sql).await?;
|
||
|
||
// 分区表主键必须包含分区键
|
||
manager
|
||
.get_connection()
|
||
.execute_unprepared("ALTER TABLE device_readings ADD PRIMARY KEY (id, measured_at);")
|
||
.await?;
|
||
|
||
// 核心查询索引
|
||
manager.get_connection().execute_unprepared(
|
||
"CREATE INDEX idx_dr_tenant_patient ON device_readings (tenant_id, patient_id, measured_at DESC);"
|
||
).await?;
|
||
|
||
manager.get_connection().execute_unprepared(
|
||
"CREATE INDEX idx_dr_device_type ON device_readings (tenant_id, device_type, measured_at DESC);"
|
||
).await?;
|
||
|
||
// 创建初始分区(当前月 + 未来 3 个月)
|
||
for (suffix, start, end) in [
|
||
("2026_05", "2026-05-01", "2026-06-01"),
|
||
("2026_06", "2026-06-01", "2026-07-01"),
|
||
("2026_07", "2026-07-01", "2026-08-01"),
|
||
("2026_08", "2026-08-01", "2026-09-01"),
|
||
] {
|
||
let partition_sql = format!(
|
||
"CREATE TABLE IF NOT EXISTS device_readings_{suffix} PARTITION OF device_readings FOR VALUES FROM ('{start}') TO ('{end}');"
|
||
);
|
||
manager
|
||
.get_connection()
|
||
.execute_unprepared(&partition_sql)
|
||
.await?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||
for suffix in ["2026_05", "2026_06", "2026_07", "2026_08"] {
|
||
manager
|
||
.get_connection()
|
||
.execute_unprepared(&format!("DROP TABLE IF EXISTS device_readings_{suffix};"))
|
||
.await
|
||
.ok();
|
||
}
|
||
manager
|
||
.get_connection()
|
||
.execute_unprepared("DROP TABLE IF EXISTS device_readings;")
|
||
.await?;
|
||
Ok(())
|
||
}
|
||
}
|