feat(models): Task/Product 模型扩充 + 4个Alembic迁移
Task 模型: - 新增 received_at, completed_at, reject_reason, is_rework - 新增 TaskRecord 模型 (remark + images JSON) - 状态常量 PENDING/WIP/COMPLETED/REJECTED/ARCHIVED - 全部时间字段改用北京时间 (get_beijing_time) Product 模型: - order_id → 可选; 新增 external_serial, current_location_id - 新增 material_name/spec_model/category/material_type 快照字段 - 新增 overall_status (备货/生产/测试/维修/在库) 迁移: - b2c3: HEX计数器Sequence + external_serial + order_id nullable - c3d4: material快照4列 - d4e5: overall_status - e5f6: task_records表
This commit is contained in:
@ -0,0 +1,44 @@
|
||||
"""product hex counter + material fields + optional order
|
||||
|
||||
Revision ID: b2c3d4e5f6a7
|
||||
Revises: a1b2c3d4e5f6
|
||||
Create Date: 2026-08-04 15:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = 'b2c3d4e5f6a7'
|
||||
down_revision: Union[str, Sequence[str], None] = 'a1b2c3d4e5f6'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# === 16进制计数器 Sequence ===
|
||||
op.execute("CREATE SEQUENCE IF NOT EXISTS product_hex_counter START 1;")
|
||||
|
||||
# === products 表: order_id → 可选 ===
|
||||
op.alter_column('products', 'order_id',
|
||||
existing_type=sa.UUID(),
|
||||
nullable=True,
|
||||
existing_comment='所属订单ID(可选)')
|
||||
|
||||
# === products 表: 新增 external_serial ===
|
||||
op.add_column('products', sa.Column(
|
||||
'external_serial',
|
||||
sa.String(length=64),
|
||||
nullable=True,
|
||||
comment='用户自定义产品序列号(可选)',
|
||||
))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('products', 'external_serial')
|
||||
op.alter_column('products', 'order_id',
|
||||
existing_type=sa.UUID(),
|
||||
nullable=False)
|
||||
op.execute("DROP SEQUENCE IF EXISTS product_hex_counter;")
|
||||
@ -0,0 +1,35 @@
|
||||
"""add product material snapshot fields
|
||||
|
||||
Revision ID: c3d4e5f6a7b8
|
||||
Revises: b2c3d4e5f6a7
|
||||
Create Date: 2026-08-05 10:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = 'c3d4e5f6a7b8'
|
||||
down_revision: Union[str, Sequence[str], None] = 'b2c3d4e5f6a7'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column('products', sa.Column(
|
||||
'material_name', sa.String(length=255), nullable=True, comment='物料名称快照'))
|
||||
op.add_column('products', sa.Column(
|
||||
'spec_model', sa.String(length=255), nullable=True, comment='规格型号快照'))
|
||||
op.add_column('products', sa.Column(
|
||||
'category', sa.String(length=255), nullable=True, comment='物料分类快照'))
|
||||
op.add_column('products', sa.Column(
|
||||
'material_type', sa.String(length=100), nullable=True, comment='物料类型快照'))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('products', 'material_type')
|
||||
op.drop_column('products', 'category')
|
||||
op.drop_column('products', 'spec_model')
|
||||
op.drop_column('products', 'material_name')
|
||||
@ -0,0 +1,30 @@
|
||||
"""add product overall_status
|
||||
|
||||
Revision ID: d4e5f6a7b8c9
|
||||
Revises: c3d4e5f6a7b8
|
||||
Create Date: 2026-08-05 12:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = 'd4e5f6a7b8c9'
|
||||
down_revision: Union[str, Sequence[str], None] = 'c3d4e5f6a7b8'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column('products', sa.Column(
|
||||
'overall_status',
|
||||
sa.String(length=20),
|
||||
nullable=True,
|
||||
comment='宏观状态: 备货/生产/测试/维修/在库',
|
||||
))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('products', 'overall_status')
|
||||
35
backend/alembic/versions/e5f6a7b8c9d0_add_task_records.py
Normal file
35
backend/alembic/versions/e5f6a7b8c9d0_add_task_records.py
Normal file
@ -0,0 +1,35 @@
|
||||
"""add task_records table
|
||||
|
||||
Revision ID: e5f6a7b8c9d0
|
||||
Revises: d4e5f6a7b8c9
|
||||
Create Date: 2026-08-06 10:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
|
||||
|
||||
revision: str = 'e5f6a7b8c9d0'
|
||||
down_revision: Union[str, Sequence[str], None] = 'd4e5f6a7b8c9'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table('task_records',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('task_id', UUID(as_uuid=True), sa.ForeignKey('tasks.id'), nullable=False, comment='所属任务ID'),
|
||||
sa.Column('remark', sa.String(length=2000), nullable=True, comment='备注文本'),
|
||||
sa.Column('images', sa.String(length=4000), nullable=True, comment='图片URL列表(JSON字符串)'),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, comment='记录时间'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
op.create_index(op.f('ix_task_records_task_id'), 'task_records', ['task_id'], unique=False)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(op.f('ix_task_records_task_id'), table_name='task_records')
|
||||
op.drop_table('task_records')
|
||||
Reference in New Issue
Block a user