Merge commit '026c837b919ab4380e8a6e6c052364bbf9bbe8a3' as 'core'
This commit is contained in:
268
core/backend/alembic/versions/001_initial_schema.py
Normal file
268
core/backend/alembic/versions/001_initial_schema.py
Normal file
@@ -0,0 +1,268 @@
|
||||
"""Initial schema - all 14 tables
|
||||
|
||||
Revision ID: 001_initial
|
||||
Revises:
|
||||
Create Date: 2026-04-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "001_initial"
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- roles ---
|
||||
op.create_table(
|
||||
"roles",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("display_name", sa.String(100), nullable=False),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("permissions", sa.Text),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- users ---
|
||||
op.create_table(
|
||||
"users",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("username", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("email", sa.String(100), unique=True),
|
||||
sa.Column("hashed_password", sa.String(200), nullable=False),
|
||||
sa.Column("full_name", sa.String(100)),
|
||||
sa.Column("phone", sa.String(20)),
|
||||
sa.Column("role", sa.String(50), sa.ForeignKey("roles.name"), default="visitor"),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("last_login", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
op.create_index("ix_users_username", "users", ["username"])
|
||||
|
||||
# --- audit_logs ---
|
||||
op.create_table(
|
||||
"audit_logs",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("user_id", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("action", sa.String(50), nullable=False),
|
||||
sa.Column("resource", sa.String(100)),
|
||||
sa.Column("detail", sa.Text),
|
||||
sa.Column("ip_address", sa.String(50)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- device_types ---
|
||||
op.create_table(
|
||||
"device_types",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("code", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("icon", sa.String(100)),
|
||||
sa.Column("data_fields", sa.JSON),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- device_groups ---
|
||||
op.create_table(
|
||||
"device_groups",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("parent_id", sa.Integer, sa.ForeignKey("device_groups.id")),
|
||||
sa.Column("location", sa.String(200)),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- devices ---
|
||||
op.create_table(
|
||||
"devices",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("code", sa.String(100), unique=True, nullable=False),
|
||||
sa.Column("device_type", sa.String(50), sa.ForeignKey("device_types.code"), nullable=False),
|
||||
sa.Column("group_id", sa.Integer, sa.ForeignKey("device_groups.id")),
|
||||
sa.Column("model", sa.String(100)),
|
||||
sa.Column("manufacturer", sa.String(100)),
|
||||
sa.Column("serial_number", sa.String(100)),
|
||||
sa.Column("rated_power", sa.Float),
|
||||
sa.Column("install_date", sa.DateTime(timezone=True)),
|
||||
sa.Column("location", sa.String(200)),
|
||||
sa.Column("protocol", sa.String(50)),
|
||||
sa.Column("connection_params", sa.JSON),
|
||||
sa.Column("collect_interval", sa.Integer, default=15),
|
||||
sa.Column("status", sa.String(20), default="offline"),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("metadata", sa.JSON),
|
||||
sa.Column("last_data_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- energy_data ---
|
||||
op.create_table(
|
||||
"energy_data",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False),
|
||||
sa.Column("timestamp", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("data_type", sa.String(50), nullable=False),
|
||||
sa.Column("value", sa.Float, nullable=False),
|
||||
sa.Column("unit", sa.String(20)),
|
||||
sa.Column("quality", sa.Integer, default=0),
|
||||
sa.Column("raw_data", sa.JSON),
|
||||
)
|
||||
op.create_index("ix_energy_data_device_id", "energy_data", ["device_id"])
|
||||
op.create_index("ix_energy_data_timestamp", "energy_data", ["timestamp"])
|
||||
|
||||
# --- energy_daily_summary ---
|
||||
op.create_table(
|
||||
"energy_daily_summary",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False),
|
||||
sa.Column("date", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("energy_type", sa.String(50), nullable=False),
|
||||
sa.Column("total_consumption", sa.Float, default=0),
|
||||
sa.Column("total_generation", sa.Float, default=0),
|
||||
sa.Column("peak_power", sa.Float),
|
||||
sa.Column("min_power", sa.Float),
|
||||
sa.Column("avg_power", sa.Float),
|
||||
sa.Column("operating_hours", sa.Float),
|
||||
sa.Column("avg_cop", sa.Float),
|
||||
sa.Column("avg_temperature", sa.Float),
|
||||
sa.Column("cost", sa.Float),
|
||||
sa.Column("carbon_emission", sa.Float),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
op.create_index("ix_energy_daily_summary_device_id", "energy_daily_summary", ["device_id"])
|
||||
op.create_index("ix_energy_daily_summary_date", "energy_daily_summary", ["date"])
|
||||
|
||||
# --- alarm_rules ---
|
||||
op.create_table(
|
||||
"alarm_rules",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id")),
|
||||
sa.Column("device_type", sa.String(50)),
|
||||
sa.Column("data_type", sa.String(50), nullable=False),
|
||||
sa.Column("condition", sa.String(20), nullable=False),
|
||||
sa.Column("threshold", sa.Float),
|
||||
sa.Column("threshold_high", sa.Float),
|
||||
sa.Column("threshold_low", sa.Float),
|
||||
sa.Column("duration", sa.Integer, default=0),
|
||||
sa.Column("severity", sa.String(20), default="warning"),
|
||||
sa.Column("notify_channels", sa.JSON),
|
||||
sa.Column("notify_targets", sa.JSON),
|
||||
sa.Column("auto_action", sa.JSON),
|
||||
sa.Column("silence_start", sa.String(10)),
|
||||
sa.Column("silence_end", sa.String(10)),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- alarm_events ---
|
||||
op.create_table(
|
||||
"alarm_events",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("rule_id", sa.Integer, sa.ForeignKey("alarm_rules.id")),
|
||||
sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False),
|
||||
sa.Column("severity", sa.String(20), nullable=False),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("value", sa.Float),
|
||||
sa.Column("threshold", sa.Float),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("acknowledged_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("acknowledged_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("resolved_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("resolve_note", sa.Text),
|
||||
sa.Column("triggered_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- emission_factors ---
|
||||
op.create_table(
|
||||
"emission_factors",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("energy_type", sa.String(50), nullable=False),
|
||||
sa.Column("factor", sa.Float, nullable=False),
|
||||
sa.Column("unit", sa.String(20), nullable=False),
|
||||
sa.Column("region", sa.String(50), default="north_china"),
|
||||
sa.Column("scope", sa.Integer, nullable=False),
|
||||
sa.Column("source", sa.String(200)),
|
||||
sa.Column("year", sa.Integer),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- carbon_emissions ---
|
||||
op.create_table(
|
||||
"carbon_emissions",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("date", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("scope", sa.Integer, nullable=False),
|
||||
sa.Column("category", sa.String(50), nullable=False),
|
||||
sa.Column("emission", sa.Float, nullable=False),
|
||||
sa.Column("reduction", sa.Float, default=0),
|
||||
sa.Column("energy_consumption", sa.Float),
|
||||
sa.Column("energy_unit", sa.String(20)),
|
||||
sa.Column("emission_factor_id", sa.Integer),
|
||||
sa.Column("note", sa.Text),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
op.create_index("ix_carbon_emissions_date", "carbon_emissions", ["date"])
|
||||
|
||||
# --- report_templates ---
|
||||
op.create_table(
|
||||
"report_templates",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("report_type", sa.String(50), nullable=False),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("fields", sa.JSON, nullable=False),
|
||||
sa.Column("filters", sa.JSON),
|
||||
sa.Column("aggregation", sa.String(20), default="sum"),
|
||||
sa.Column("time_granularity", sa.String(20), default="hour"),
|
||||
sa.Column("format_config", sa.JSON),
|
||||
sa.Column("is_system", sa.Boolean, default=False),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- report_tasks ---
|
||||
op.create_table(
|
||||
"report_tasks",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("template_id", sa.Integer, sa.ForeignKey("report_templates.id"), nullable=False),
|
||||
sa.Column("name", sa.String(200)),
|
||||
sa.Column("schedule", sa.String(50)),
|
||||
sa.Column("next_run", sa.DateTime(timezone=True)),
|
||||
sa.Column("last_run", sa.DateTime(timezone=True)),
|
||||
sa.Column("recipients", sa.JSON),
|
||||
sa.Column("export_format", sa.String(20), default="xlsx"),
|
||||
sa.Column("file_path", sa.String(500)),
|
||||
sa.Column("status", sa.String(20), default="pending"),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("report_tasks")
|
||||
op.drop_table("report_templates")
|
||||
op.drop_table("carbon_emissions")
|
||||
op.drop_table("emission_factors")
|
||||
op.drop_table("alarm_events")
|
||||
op.drop_table("alarm_rules")
|
||||
op.drop_table("energy_daily_summary")
|
||||
op.drop_table("energy_data")
|
||||
op.drop_table("devices")
|
||||
op.drop_table("device_groups")
|
||||
op.drop_table("device_types")
|
||||
op.drop_table("audit_logs")
|
||||
op.drop_table("users")
|
||||
op.drop_table("roles")
|
||||
41
core/backend/alembic/versions/002_add_system_settings.py
Normal file
41
core/backend/alembic/versions/002_add_system_settings.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""Add system_settings table
|
||||
|
||||
Revision ID: 002_system_settings
|
||||
Revises: 001_initial
|
||||
Create Date: 2026-04-02
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "002_system_settings"
|
||||
down_revision = "001_initial"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"system_settings",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("key", sa.String(100), unique=True, nullable=False, index=True),
|
||||
sa.Column("value", sa.Text, nullable=False, server_default=""),
|
||||
sa.Column("description", sa.String(255)),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# Seed default settings
|
||||
op.execute("""
|
||||
INSERT INTO system_settings (key, value, description) VALUES
|
||||
('platform_name', '天普零碳园区智慧能源管理平台', '平台名称'),
|
||||
('data_retention_days', '365', '数据保留天数'),
|
||||
('alarm_auto_resolve_minutes', '30', '告警自动解除时间(分钟)'),
|
||||
('simulator_interval_seconds', '15', '模拟器采集间隔(秒)'),
|
||||
('notification_email_enabled', 'false', '是否启用邮件通知'),
|
||||
('notification_email_smtp', '', 'SMTP服务器地址'),
|
||||
('report_auto_schedule_enabled', 'false', '是否启用自动报表'),
|
||||
('timezone', 'Asia/Shanghai', '系统时区')
|
||||
""")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("system_settings")
|
||||
37
core/backend/alembic/versions/003_energy_categories.py
Normal file
37
core/backend/alembic/versions/003_energy_categories.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""Add energy_categories table and devices.category_id
|
||||
|
||||
Revision ID: 003_energy_categories
|
||||
Revises: 002_system_settings
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "003_energy_categories"
|
||||
down_revision = "002_system_settings"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- energy_categories ---
|
||||
op.create_table(
|
||||
"energy_categories",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("code", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("parent_id", sa.Integer, sa.ForeignKey("energy_categories.id")),
|
||||
sa.Column("sort_order", sa.Integer, default=0),
|
||||
sa.Column("icon", sa.String(100)),
|
||||
sa.Column("color", sa.String(20)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# Add category_id column to devices table (batch mode for SQLite compat)
|
||||
with op.batch_alter_table("devices") as batch_op:
|
||||
batch_op.add_column(sa.Column("category_id", sa.Integer, nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("devices", "category_id")
|
||||
op.drop_table("energy_categories")
|
||||
168
core/backend/alembic/versions/004_charging_tables.py
Normal file
168
core/backend/alembic/versions/004_charging_tables.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""Add charging tables
|
||||
|
||||
Revision ID: 004_charging
|
||||
Revises: 003_energy_categories
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "004_charging"
|
||||
down_revision = "003_energy_categories"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- charging_merchants ---
|
||||
op.create_table(
|
||||
"charging_merchants",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("contact_person", sa.String(100)),
|
||||
sa.Column("phone", sa.String(20)),
|
||||
sa.Column("email", sa.String(100)),
|
||||
sa.Column("address", sa.String(500)),
|
||||
sa.Column("business_license", sa.String(100)),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("settlement_type", sa.String(20)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_brands ---
|
||||
op.create_table(
|
||||
"charging_brands",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("brand_name", sa.String(100), nullable=False),
|
||||
sa.Column("logo_url", sa.String(500)),
|
||||
sa.Column("country", sa.String(50)),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_stations ---
|
||||
op.create_table(
|
||||
"charging_stations",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("merchant_id", sa.Integer, sa.ForeignKey("charging_merchants.id")),
|
||||
sa.Column("type", sa.String(50)),
|
||||
sa.Column("address", sa.String(500)),
|
||||
sa.Column("latitude", sa.Float),
|
||||
sa.Column("longitude", sa.Float),
|
||||
sa.Column("price", sa.Float),
|
||||
sa.Column("activity", sa.Text),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("total_piles", sa.Integer, default=0),
|
||||
sa.Column("available_piles", sa.Integer, default=0),
|
||||
sa.Column("total_power_kw", sa.Float, default=0),
|
||||
sa.Column("photo_url", sa.String(500)),
|
||||
sa.Column("operating_hours", sa.String(100)),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_piles ---
|
||||
op.create_table(
|
||||
"charging_piles",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("station_id", sa.Integer, sa.ForeignKey("charging_stations.id"), nullable=False),
|
||||
sa.Column("encoding", sa.String(100), unique=True),
|
||||
sa.Column("name", sa.String(200)),
|
||||
sa.Column("type", sa.String(50)),
|
||||
sa.Column("brand", sa.String(100)),
|
||||
sa.Column("model", sa.String(100)),
|
||||
sa.Column("rated_power_kw", sa.Float),
|
||||
sa.Column("connector_type", sa.String(50)),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("work_status", sa.String(20), default="offline"),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_price_strategies ---
|
||||
op.create_table(
|
||||
"charging_price_strategies",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("strategy_name", sa.String(200), nullable=False),
|
||||
sa.Column("station_id", sa.Integer, sa.ForeignKey("charging_stations.id")),
|
||||
sa.Column("bill_model", sa.String(20)),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("status", sa.String(20), default="inactive"),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_price_params ---
|
||||
op.create_table(
|
||||
"charging_price_params",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("strategy_id", sa.Integer, sa.ForeignKey("charging_price_strategies.id"), nullable=False),
|
||||
sa.Column("start_time", sa.String(10), nullable=False),
|
||||
sa.Column("end_time", sa.String(10), nullable=False),
|
||||
sa.Column("period_mark", sa.String(20)),
|
||||
sa.Column("elec_price", sa.Float, nullable=False),
|
||||
sa.Column("service_price", sa.Float, default=0),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- charging_orders ---
|
||||
op.create_table(
|
||||
"charging_orders",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("order_no", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("user_id", sa.Integer),
|
||||
sa.Column("user_name", sa.String(100)),
|
||||
sa.Column("phone", sa.String(20)),
|
||||
sa.Column("station_id", sa.Integer, sa.ForeignKey("charging_stations.id")),
|
||||
sa.Column("station_name", sa.String(200)),
|
||||
sa.Column("pile_id", sa.Integer, sa.ForeignKey("charging_piles.id")),
|
||||
sa.Column("pile_name", sa.String(200)),
|
||||
sa.Column("start_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("end_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("car_no", sa.String(20)),
|
||||
sa.Column("car_vin", sa.String(50)),
|
||||
sa.Column("charge_method", sa.String(20)),
|
||||
sa.Column("settle_type", sa.String(20)),
|
||||
sa.Column("pay_type", sa.String(20)),
|
||||
sa.Column("settle_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("settle_price", sa.Float),
|
||||
sa.Column("paid_price", sa.Float),
|
||||
sa.Column("discount_amt", sa.Float, default=0),
|
||||
sa.Column("elec_amt", sa.Float),
|
||||
sa.Column("serve_amt", sa.Float),
|
||||
sa.Column("order_status", sa.String(20), default="charging"),
|
||||
sa.Column("charge_duration", sa.Integer),
|
||||
sa.Column("energy", sa.Float),
|
||||
sa.Column("start_soc", sa.Float),
|
||||
sa.Column("end_soc", sa.Float),
|
||||
sa.Column("abno_cause", sa.Text),
|
||||
sa.Column("order_source", sa.String(20)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- occupancy_orders ---
|
||||
op.create_table(
|
||||
"occupancy_orders",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("order_id", sa.Integer, sa.ForeignKey("charging_orders.id")),
|
||||
sa.Column("pile_id", sa.Integer, sa.ForeignKey("charging_piles.id")),
|
||||
sa.Column("start_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("end_time", sa.DateTime(timezone=True)),
|
||||
sa.Column("occupancy_fee", sa.Float, default=0),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("occupancy_orders")
|
||||
op.drop_table("charging_orders")
|
||||
op.drop_table("charging_price_params")
|
||||
op.drop_table("charging_price_strategies")
|
||||
op.drop_table("charging_piles")
|
||||
op.drop_table("charging_stations")
|
||||
op.drop_table("charging_brands")
|
||||
op.drop_table("charging_merchants")
|
||||
53
core/backend/alembic/versions/005_quota_tables.py
Normal file
53
core/backend/alembic/versions/005_quota_tables.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Add quota tables
|
||||
|
||||
Revision ID: 005_quota
|
||||
Revises: 004_charging
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "005_quota"
|
||||
down_revision = "004_charging"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- energy_quotas ---
|
||||
op.create_table(
|
||||
"energy_quotas",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("target_type", sa.String(50), nullable=False),
|
||||
sa.Column("target_id", sa.Integer, nullable=False),
|
||||
sa.Column("energy_type", sa.String(50), nullable=False),
|
||||
sa.Column("period", sa.String(20), nullable=False),
|
||||
sa.Column("quota_value", sa.Float, nullable=False),
|
||||
sa.Column("unit", sa.String(20), default="kWh"),
|
||||
sa.Column("warning_threshold_pct", sa.Float, default=80),
|
||||
sa.Column("alert_threshold_pct", sa.Float, default=95),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- quota_usage ---
|
||||
op.create_table(
|
||||
"quota_usage",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("quota_id", sa.Integer, sa.ForeignKey("energy_quotas.id"), nullable=False),
|
||||
sa.Column("period_start", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("period_end", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("actual_value", sa.Float, default=0),
|
||||
sa.Column("quota_value", sa.Float, nullable=False),
|
||||
sa.Column("usage_rate_pct", sa.Float, default=0),
|
||||
sa.Column("status", sa.String(20), default="normal"),
|
||||
sa.Column("calculated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("quota_usage")
|
||||
op.drop_table("energy_quotas")
|
||||
48
core/backend/alembic/versions/006_pricing_tables.py
Normal file
48
core/backend/alembic/versions/006_pricing_tables.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""Add pricing tables
|
||||
|
||||
Revision ID: 006_pricing
|
||||
Revises: 005_quota
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "006_pricing"
|
||||
down_revision = "005_quota"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- electricity_pricing ---
|
||||
op.create_table(
|
||||
"electricity_pricing",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("energy_type", sa.String(50), default="electricity"),
|
||||
sa.Column("pricing_type", sa.String(20), nullable=False),
|
||||
sa.Column("effective_from", sa.DateTime(timezone=True)),
|
||||
sa.Column("effective_to", sa.DateTime(timezone=True)),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- pricing_periods ---
|
||||
op.create_table(
|
||||
"pricing_periods",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("pricing_id", sa.Integer, sa.ForeignKey("electricity_pricing.id"), nullable=False),
|
||||
sa.Column("period_name", sa.String(50), nullable=False),
|
||||
sa.Column("start_time", sa.String(10), nullable=False),
|
||||
sa.Column("end_time", sa.String(10), nullable=False),
|
||||
sa.Column("price_per_unit", sa.Float, nullable=False),
|
||||
sa.Column("applicable_months", sa.JSON),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("pricing_periods")
|
||||
op.drop_table("electricity_pricing")
|
||||
88
core/backend/alembic/versions/007_maintenance_tables.py
Normal file
88
core/backend/alembic/versions/007_maintenance_tables.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Add maintenance tables
|
||||
|
||||
Revision ID: 007_maintenance
|
||||
Revises: 006_pricing
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "007_maintenance"
|
||||
down_revision = "006_pricing"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- inspection_plans ---
|
||||
op.create_table(
|
||||
"inspection_plans",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("device_group_id", sa.Integer, sa.ForeignKey("device_groups.id")),
|
||||
sa.Column("device_ids", sa.JSON),
|
||||
sa.Column("schedule_type", sa.String(20)),
|
||||
sa.Column("schedule_cron", sa.String(100)),
|
||||
sa.Column("inspector_id", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("checklist", sa.JSON),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("next_run_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- inspection_records ---
|
||||
op.create_table(
|
||||
"inspection_records",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("plan_id", sa.Integer, sa.ForeignKey("inspection_plans.id"), nullable=False),
|
||||
sa.Column("inspector_id", sa.Integer, sa.ForeignKey("users.id"), nullable=False),
|
||||
sa.Column("status", sa.String(20), default="pending"),
|
||||
sa.Column("findings", sa.JSON),
|
||||
sa.Column("started_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("completed_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- repair_orders ---
|
||||
op.create_table(
|
||||
"repair_orders",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("code", sa.String(50), unique=True, nullable=False),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id")),
|
||||
sa.Column("alarm_event_id", sa.Integer, sa.ForeignKey("alarm_events.id")),
|
||||
sa.Column("priority", sa.String(20), default="medium"),
|
||||
sa.Column("status", sa.String(20), default="open"),
|
||||
sa.Column("assigned_to", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("resolution", sa.Text),
|
||||
sa.Column("cost_estimate", sa.Float),
|
||||
sa.Column("actual_cost", sa.Float),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("assigned_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("completed_at", sa.DateTime(timezone=True)),
|
||||
sa.Column("closed_at", sa.DateTime(timezone=True)),
|
||||
)
|
||||
|
||||
# --- duty_schedules ---
|
||||
op.create_table(
|
||||
"duty_schedules",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("user_id", sa.Integer, sa.ForeignKey("users.id"), nullable=False),
|
||||
sa.Column("duty_date", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("shift", sa.String(20)),
|
||||
sa.Column("area_id", sa.Integer, sa.ForeignKey("device_groups.id")),
|
||||
sa.Column("notes", sa.Text),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("duty_schedules")
|
||||
op.drop_table("repair_orders")
|
||||
op.drop_table("inspection_records")
|
||||
op.drop_table("inspection_plans")
|
||||
79
core/backend/alembic/versions/008_management_tables.py
Normal file
79
core/backend/alembic/versions/008_management_tables.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""Add management tables
|
||||
|
||||
Revision ID: 008_management
|
||||
Revises: 007_maintenance
|
||||
Create Date: 2026-04-03
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "008_management"
|
||||
down_revision = "007_maintenance"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# --- regulations ---
|
||||
op.create_table(
|
||||
"regulations",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("category", sa.String(50)),
|
||||
sa.Column("content", sa.Text),
|
||||
sa.Column("effective_date", sa.DateTime(timezone=True)),
|
||||
sa.Column("status", sa.String(20), default="active"),
|
||||
sa.Column("attachment_url", sa.String(500)),
|
||||
sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- standards ---
|
||||
op.create_table(
|
||||
"standards",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("name", sa.String(200), nullable=False),
|
||||
sa.Column("code", sa.String(100)),
|
||||
sa.Column("type", sa.String(50)),
|
||||
sa.Column("description", sa.Text),
|
||||
sa.Column("compliance_status", sa.String(20), default="pending"),
|
||||
sa.Column("review_date", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- process_docs ---
|
||||
op.create_table(
|
||||
"process_docs",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("category", sa.String(50)),
|
||||
sa.Column("content", sa.Text),
|
||||
sa.Column("version", sa.String(20), default="1.0"),
|
||||
sa.Column("approved_by", sa.String(100)),
|
||||
sa.Column("effective_date", sa.DateTime(timezone=True)),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# --- emergency_plans ---
|
||||
op.create_table(
|
||||
"emergency_plans",
|
||||
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
|
||||
sa.Column("title", sa.String(200), nullable=False),
|
||||
sa.Column("scenario", sa.String(100)),
|
||||
sa.Column("steps", sa.JSON),
|
||||
sa.Column("responsible_person", sa.String(100)),
|
||||
sa.Column("review_date", sa.DateTime(timezone=True)),
|
||||
sa.Column("is_active", sa.Boolean, default=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("emergency_plans")
|
||||
op.drop_table("process_docs")
|
||||
op.drop_table("standards")
|
||||
op.drop_table("regulations")
|
||||
Reference in New Issue
Block a user