"""add training models Revision ID: 9245f8845fe1 Revises: 001 Create Date: 2025-09-21 22:11:03.319902 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import mysql # revision identifiers, used by Alembic. revision: str = '9245f8845fe1' down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.create_table('training_scenes', sa.Column('name', sa.String(length=100), nullable=False, comment='场景名称'), sa.Column('description', sa.Text(), nullable=True, comment='场景描述'), sa.Column('category', sa.String(length=50), nullable=False, comment='场景分类'), sa.Column('ai_config', sa.JSON(), nullable=True, comment='AI配置(如Coze Bot ID等)'), sa.Column('prompt_template', sa.Text(), nullable=True, comment='提示词模板'), sa.Column('evaluation_criteria', sa.JSON(), nullable=True, comment='评估标准'), sa.Column('status', sa.Enum('DRAFT', 'ACTIVE', 'INACTIVE', name='trainingscenestatus'), nullable=False, comment='场景状态'), sa.Column('is_public', sa.Boolean(), nullable=False, comment='是否公开'), sa.Column('required_level', sa.Integer(), nullable=True, comment='所需用户等级'), sa.Column('id', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('is_deleted', sa.Boolean(), nullable=False), sa.Column('deleted_at', sa.DateTime(), nullable=True), sa.Column('created_by', sa.Integer(), nullable=True), sa.Column('updated_by', sa.Integer(), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_index(op.f('ix_training_scenes_id'), 'training_scenes', ['id'], unique=False) op.create_table('training_sessions', sa.Column('user_id', sa.Integer(), nullable=False, comment='用户ID'), sa.Column('scene_id', sa.Integer(), nullable=False, comment='场景ID'), sa.Column('coze_conversation_id', sa.String(length=100), nullable=True, comment='Coze会话ID'), sa.Column('start_time', sa.DateTime(), nullable=False, comment='开始时间'), sa.Column('end_time', sa.DateTime(), nullable=True, comment='结束时间'), sa.Column('duration_seconds', sa.Integer(), nullable=True, comment='持续时长(秒)'), sa.Column('status', sa.Enum('CREATED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'ERROR', name='trainingsessionstatus'), nullable=False, comment='会话状态'), sa.Column('session_config', sa.JSON(), nullable=True, comment='会话配置'), sa.Column('total_score', sa.Float(), nullable=True, comment='总分'), sa.Column('evaluation_result', sa.JSON(), nullable=True, comment='评估结果详情'), sa.Column('id', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('created_by', sa.Integer(), nullable=True), sa.Column('updated_by', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['scene_id'], ['training_scenes.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_index(op.f('ix_training_sessions_id'), 'training_sessions', ['id'], unique=False) op.create_index(op.f('ix_training_sessions_user_id'), 'training_sessions', ['user_id'], unique=False) op.create_table('training_messages', sa.Column('session_id', sa.Integer(), nullable=False, comment='会话ID'), sa.Column('role', sa.Enum('USER', 'ASSISTANT', 'SYSTEM', name='messagerole'), nullable=False, comment='消息角色'), sa.Column('type', sa.Enum('TEXT', 'VOICE', 'SYSTEM', name='messagetype'), nullable=False, comment='消息类型'), sa.Column('content', sa.Text(), nullable=False, comment='消息内容'), sa.Column('voice_url', sa.String(length=500), nullable=True, comment='语音文件URL'), sa.Column('voice_duration', sa.Float(), nullable=True, comment='语音时长(秒)'), sa.Column('message_metadata', sa.JSON(), nullable=True, comment='消息元数据'), sa.Column('coze_message_id', sa.String(length=100), nullable=True, comment='Coze消息ID'), sa.Column('id', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['session_id'], ['training_sessions.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_index(op.f('ix_training_messages_id'), 'training_messages', ['id'], unique=False) op.create_table('training_reports', sa.Column('session_id', sa.Integer(), nullable=False, comment='会话ID'), sa.Column('user_id', sa.Integer(), nullable=False, comment='用户ID'), sa.Column('overall_score', sa.Float(), nullable=False, comment='总体得分'), sa.Column('dimension_scores', sa.JSON(), nullable=False, comment='各维度得分'), sa.Column('strengths', sa.JSON(), nullable=False, comment='优势点'), sa.Column('weaknesses', sa.JSON(), nullable=False, comment='待改进点'), sa.Column('suggestions', sa.JSON(), nullable=False, comment='改进建议'), sa.Column('detailed_analysis', sa.Text(), nullable=True, comment='详细分析'), sa.Column('transcript', sa.Text(), nullable=True, comment='对话文本记录'), sa.Column('statistics', sa.JSON(), nullable=True, comment='统计数据'), sa.Column('id', sa.Integer(), nullable=False), sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column('updated_at', sa.DateTime(), nullable=False), sa.Column('created_by', sa.Integer(), nullable=True), sa.Column('updated_by', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['session_id'], ['training_sessions.id'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('session_id') ) op.create_index(op.f('ix_training_reports_id'), 'training_reports', ['id'], unique=False) op.create_index(op.f('ix_training_reports_user_id'), 'training_reports', ['user_id'], unique=False) op.create_table('user_teams', sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('team_id', sa.Integer(), nullable=False), sa.Column('role', sa.String(length=50), nullable=False), sa.Column('joined_at', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(['team_id'], ['teams.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('user_id', 'team_id'), sa.UniqueConstraint('user_id', 'team_id', name='uq_user_team') ) op.alter_column('course_materials', 'course_id', existing_type=mysql.INTEGER(), comment='课程ID', existing_comment='课程ID', existing_nullable=False) op.alter_column('course_materials', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='资料名称', existing_comment='资料å\x90\x8dç§°', existing_nullable=False) op.alter_column('course_materials', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='资料描述', existing_comment='资料æ\x8f\x8fè¿°', existing_nullable=True) op.alter_column('course_materials', 'file_url', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='文件URL', existing_comment='文件URL', existing_nullable=False) op.alter_column('course_materials', 'file_type', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=50), comment='文件类型', existing_comment='文件类型', existing_nullable=False) op.alter_column('course_materials', 'file_size', existing_type=mysql.INTEGER(), comment='文件大小(字节)', existing_comment='文件大å°\x8f(å\xad—节)', existing_nullable=False) op.alter_column('course_materials', 'sort_order', existing_type=mysql.INTEGER(), comment='排序顺序', existing_comment='排åº\x8f顺åº\x8f', existing_nullable=False, existing_server_default=sa.text("'0'")) op.drop_index('idx_course_materials_course_id', table_name='course_materials') op.drop_index('idx_course_materials_is_deleted', table_name='course_materials') op.create_index(op.f('ix_course_materials_id'), 'course_materials', ['id'], unique=False) op.drop_table_comment( 'course_materials', existing_comment='课程资料表', schema=None ) op.alter_column('courses', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='课程名称', existing_comment='课程å\x90\x8dç§°', existing_nullable=False) op.alter_column('courses', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='课程描述', existing_comment='课程æ\x8f\x8fè¿°', existing_nullable=True) op.alter_column('courses', 'category', existing_type=mysql.ENUM('technology', 'management', 'business', 'general', collation='utf8mb4_unicode_ci'), comment='课程分类', existing_comment='课程分类', existing_nullable=False, existing_server_default=sa.text("'general'")) op.alter_column('courses', 'status', existing_type=mysql.ENUM('draft', 'published', 'archived', collation='utf8mb4_unicode_ci'), comment='课程状态', existing_comment='课程状æ€\x81', existing_nullable=False, existing_server_default=sa.text("'draft'")) op.alter_column('courses', 'cover_image', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='封面图片URL', existing_comment='å°\x81é\x9d¢å›¾ç‰‡URL', existing_nullable=True) op.alter_column('courses', 'duration_hours', existing_type=mysql.FLOAT(), comment='课程时长(小时)', existing_comment='课程时长(å°\x8fæ—¶)', existing_nullable=True) op.alter_column('courses', 'difficulty_level', existing_type=mysql.INTEGER(), comment='难度等级(1-5)', existing_comment='难度ç\xad‰çº§(1-5)', existing_nullable=True) op.alter_column('courses', 'tags', existing_type=mysql.JSON(), comment='标签列表', existing_comment='æ\xa0‡ç\xad¾åˆ—表', existing_nullable=True) op.alter_column('courses', 'published_at', existing_type=mysql.DATETIME(), comment='发布时间', existing_comment='å\x8f‘布时间', existing_nullable=True) op.alter_column('courses', 'publisher_id', existing_type=mysql.INTEGER(), comment='发布人ID', existing_comment='å\x8f‘布人ID', existing_nullable=True) op.alter_column('courses', 'sort_order', existing_type=mysql.INTEGER(), comment='排序顺序', existing_comment='排åº\x8f顺åº\x8f', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('courses', 'is_featured', existing_type=mysql.TINYINT(display_width=1), comment='是否推荐', existing_comment='是å\x90¦æŽ¨è\x8d\x90', existing_nullable=False, existing_server_default=sa.text("'0'")) op.drop_index('idx_courses_category', table_name='courses') op.drop_index('idx_courses_is_deleted', table_name='courses') op.drop_index('idx_courses_status', table_name='courses') op.create_index(op.f('ix_courses_id'), 'courses', ['id'], unique=False) op.drop_table_comment( 'courses', existing_comment='课程表', schema=None ) op.alter_column('growth_paths', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='路径名称', existing_comment='路径å\x90\x8dç§°', existing_nullable=False) op.alter_column('growth_paths', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='路径描述', existing_comment='路径æ\x8f\x8fè¿°', existing_nullable=True) op.alter_column('growth_paths', 'target_role', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=100), comment='目标角色', existing_comment='ç›®æ\xa0‡è§’色', existing_nullable=True) op.alter_column('growth_paths', 'courses', existing_type=mysql.JSON(), comment='课程列表[{course_id, order, is_required}]', existing_comment='课程列表[{course_id, order, is_required}]', existing_nullable=True) op.alter_column('growth_paths', 'estimated_duration_days', existing_type=mysql.INTEGER(), comment='预计完成天数', existing_comment='预计完æˆ\x90天数', existing_nullable=True) op.alter_column('growth_paths', 'is_active', existing_type=mysql.TINYINT(display_width=1), comment='是否启用', existing_comment='是å\x90¦å\x90¯ç”¨', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('growth_paths', 'sort_order', existing_type=mysql.INTEGER(), comment='排序顺序', existing_comment='排åº\x8f顺åº\x8f', existing_nullable=False, existing_server_default=sa.text("'0'")) op.drop_index('idx_growth_paths_is_active', table_name='growth_paths') op.drop_index('idx_growth_paths_is_deleted', table_name='growth_paths') op.create_index(op.f('ix_growth_paths_id'), 'growth_paths', ['id'], unique=False) op.drop_table_comment( 'growth_paths', existing_comment='æˆ\x90长路径表', schema=None ) op.alter_column('knowledge_points', 'course_id', existing_type=mysql.INTEGER(), comment='课程ID', existing_comment='课程ID', existing_nullable=False) op.alter_column('knowledge_points', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='知识点名称', existing_comment='知识点å\x90\x8dç§°', existing_nullable=False) op.alter_column('knowledge_points', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='知识点描述', existing_comment='知识点æ\x8f\x8fè¿°', existing_nullable=True) op.alter_column('knowledge_points', 'parent_id', existing_type=mysql.INTEGER(), comment='父知识点ID', existing_comment='父知识点ID', existing_nullable=True) op.alter_column('knowledge_points', 'level', existing_type=mysql.INTEGER(), comment='层级深度', existing_comment='层级深度', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'path', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='路径(如: 1.2.3)', existing_comment='路径(如: 1.2.3)', existing_nullable=True) op.alter_column('knowledge_points', 'sort_order', existing_type=mysql.INTEGER(), comment='排序顺序', existing_comment='排åº\x8f顺åº\x8f', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('knowledge_points', 'weight', existing_type=mysql.FLOAT(), comment='权重', existing_comment='æ\x9dƒé‡\x8d', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'is_required', existing_type=mysql.TINYINT(display_width=1), comment='是否必修', existing_comment='是å\x90¦å¿…ä¿®', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'estimated_hours', existing_type=mysql.FLOAT(), comment='预计学习时间(小时)', existing_comment='预计å\xad¦ä¹\xa0æ—¶é—´(å°\x8fæ—¶)', existing_nullable=True) op.drop_index('idx_knowledge_points_course_id', table_name='knowledge_points') op.drop_index('idx_knowledge_points_is_deleted', table_name='knowledge_points') op.drop_index('idx_knowledge_points_parent_id', table_name='knowledge_points') op.create_index(op.f('ix_knowledge_points_id'), 'knowledge_points', ['id'], unique=False) op.drop_table_comment( 'knowledge_points', existing_comment='知识点表', schema=None ) op.drop_index('ix_teams_is_deleted', table_name='teams') op.drop_index('ix_teams_parent_id', table_name='teams') op.create_foreign_key(None, 'teams', 'users', ['leader_id'], ['id'], ondelete='SET NULL') op.create_foreign_key(None, 'teams', 'teams', ['parent_id'], ['id'], ondelete='CASCADE') op.drop_column('teams', 'deleted_at') op.drop_column('teams', 'created_by') op.drop_column('teams', 'updated_by') op.drop_column('teams', 'is_deleted') op.add_column('users', sa.Column('bio', sa.Text(), nullable=True)) op.add_column('users', sa.Column('is_verified', sa.Boolean(), nullable=False)) op.add_column('users', sa.Column('last_login_at', sa.DateTime(), nullable=True)) op.add_column('users', sa.Column('password_changed_at', sa.DateTime(), nullable=True)) op.alter_column('users', 'username', existing_type=mysql.VARCHAR(length=50), comment=None, existing_comment='用户名', existing_nullable=False) op.alter_column('users', 'email', existing_type=mysql.VARCHAR(length=100), comment=None, existing_comment='邮箱', existing_nullable=False) op.alter_column('users', 'phone', existing_type=mysql.VARCHAR(length=20), comment=None, existing_comment='手机号', existing_nullable=True) op.alter_column('users', 'password_hash', existing_type=mysql.VARCHAR(length=200), comment=None, existing_comment='密码哈希', existing_nullable=False) op.alter_column('users', 'full_name', existing_type=mysql.VARCHAR(length=100), comment=None, existing_comment='全名', existing_nullable=True) op.alter_column('users', 'avatar_url', existing_type=mysql.VARCHAR(length=500), comment=None, existing_comment='头像URL', existing_nullable=True) op.alter_column('users', 'role', existing_type=mysql.VARCHAR(length=20), nullable=False, comment=None, existing_comment='角色: trainee(学员), manager(管理者), admin(管理员)') op.alter_column('users', 'is_active', existing_type=mysql.TINYINT(display_width=1), nullable=False, comment=None, existing_comment='是否激活') op.alter_column('users', 'id', existing_type=mysql.BIGINT(), type_=sa.Integer(), existing_nullable=False, autoincrement=True) op.create_unique_constraint(None, 'users', ['phone']) op.drop_column('users', 'position') op.drop_column('users', 'is_superuser') op.drop_column('users', 'locked_until') op.drop_column('users', 'login_count') op.drop_column('users', 'failed_login_count') op.drop_column('users', 'department') op.drop_column('users', 'created_by') op.drop_column('users', 'updated_by') op.drop_column('users', 'last_login') # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.add_column('users', sa.Column('last_login', mysql.VARCHAR(length=100), nullable=True, comment='最后登录时间')) op.add_column('users', sa.Column('updated_by', mysql.BIGINT(), autoincrement=False, nullable=True)) op.add_column('users', sa.Column('created_by', mysql.BIGINT(), autoincrement=False, nullable=True)) op.add_column('users', sa.Column('department', mysql.VARCHAR(length=100), nullable=True, comment='部门')) op.add_column('users', sa.Column('failed_login_count', mysql.VARCHAR(length=100), nullable=True, comment='失败登录次数')) op.add_column('users', sa.Column('login_count', mysql.VARCHAR(length=100), nullable=True, comment='登录次数')) op.add_column('users', sa.Column('locked_until', mysql.VARCHAR(length=100), nullable=True, comment='锁定到期时间')) op.add_column('users', sa.Column('is_superuser', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True, comment='是否超级管理员')) op.add_column('users', sa.Column('position', mysql.VARCHAR(length=100), nullable=True, comment='职位')) op.drop_constraint(None, 'users', type_='unique') op.alter_column('users', 'id', existing_type=sa.Integer(), type_=mysql.BIGINT(), existing_nullable=False, autoincrement=True) op.alter_column('users', 'is_active', existing_type=mysql.TINYINT(display_width=1), nullable=True, comment='是否激活') op.alter_column('users', 'role', existing_type=mysql.VARCHAR(length=20), nullable=True, comment='角色: trainee(学员), manager(管理者), admin(管理员)') op.alter_column('users', 'avatar_url', existing_type=mysql.VARCHAR(length=500), comment='头像URL', existing_nullable=True) op.alter_column('users', 'full_name', existing_type=mysql.VARCHAR(length=100), comment='全名', existing_nullable=True) op.alter_column('users', 'password_hash', existing_type=mysql.VARCHAR(length=200), comment='密码哈希', existing_nullable=False) op.alter_column('users', 'phone', existing_type=mysql.VARCHAR(length=20), comment='手机号', existing_nullable=True) op.alter_column('users', 'email', existing_type=mysql.VARCHAR(length=100), comment='邮箱', existing_nullable=False) op.alter_column('users', 'username', existing_type=mysql.VARCHAR(length=50), comment='用户名', existing_nullable=False) op.drop_column('users', 'password_changed_at') op.drop_column('users', 'last_login_at') op.drop_column('users', 'is_verified') op.drop_column('users', 'bio') op.add_column('teams', sa.Column('is_deleted', mysql.TINYINT(display_width=1), server_default=sa.text("'0'"), autoincrement=False, nullable=False)) op.add_column('teams', sa.Column('updated_by', mysql.INTEGER(), autoincrement=False, nullable=True)) op.add_column('teams', sa.Column('created_by', mysql.INTEGER(), autoincrement=False, nullable=True)) op.add_column('teams', sa.Column('deleted_at', mysql.DATETIME(), nullable=True)) op.drop_constraint(None, 'teams', type_='foreignkey') op.drop_constraint(None, 'teams', type_='foreignkey') op.create_index('ix_teams_parent_id', 'teams', ['parent_id'], unique=False) op.create_index('ix_teams_is_deleted', 'teams', ['is_deleted'], unique=False) op.create_table_comment( 'knowledge_points', '知识点表', existing_comment=None, schema=None ) op.drop_index(op.f('ix_knowledge_points_id'), table_name='knowledge_points') op.create_index('idx_knowledge_points_parent_id', 'knowledge_points', ['parent_id'], unique=False) op.create_index('idx_knowledge_points_is_deleted', 'knowledge_points', ['is_deleted'], unique=False) op.create_index('idx_knowledge_points_course_id', 'knowledge_points', ['course_id'], unique=False) op.alter_column('knowledge_points', 'estimated_hours', existing_type=mysql.FLOAT(), comment='预计å\xad¦ä¹\xa0æ—¶é—´(å°\x8fæ—¶)', existing_comment='预计学习时间(小时)', existing_nullable=True) op.alter_column('knowledge_points', 'is_required', existing_type=mysql.TINYINT(display_width=1), comment='是å\x90¦å¿…ä¿®', existing_comment='是否必修', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'weight', existing_type=mysql.FLOAT(), comment='æ\x9dƒé‡\x8d', existing_comment='权重', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'sort_order', existing_type=mysql.INTEGER(), comment='排åº\x8f顺åº\x8f', existing_comment='排序顺序', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('knowledge_points', 'path', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='路径(如: 1.2.3)', existing_comment='路径(如: 1.2.3)', existing_nullable=True) op.alter_column('knowledge_points', 'level', existing_type=mysql.INTEGER(), comment='层级深度', existing_comment='层级深度', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('knowledge_points', 'parent_id', existing_type=mysql.INTEGER(), comment='父知识点ID', existing_comment='父知识点ID', existing_nullable=True) op.alter_column('knowledge_points', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='知识点æ\x8f\x8fè¿°', existing_comment='知识点描述', existing_nullable=True) op.alter_column('knowledge_points', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='知识点å\x90\x8dç§°', existing_comment='知识点名称', existing_nullable=False) op.alter_column('knowledge_points', 'course_id', existing_type=mysql.INTEGER(), comment='课程ID', existing_comment='课程ID', existing_nullable=False) op.create_table_comment( 'growth_paths', 'æˆ\x90长路径表', existing_comment=None, schema=None ) op.drop_index(op.f('ix_growth_paths_id'), table_name='growth_paths') op.create_index('idx_growth_paths_is_deleted', 'growth_paths', ['is_deleted'], unique=False) op.create_index('idx_growth_paths_is_active', 'growth_paths', ['is_active'], unique=False) op.alter_column('growth_paths', 'sort_order', existing_type=mysql.INTEGER(), comment='排åº\x8f顺åº\x8f', existing_comment='排序顺序', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('growth_paths', 'is_active', existing_type=mysql.TINYINT(display_width=1), comment='是å\x90¦å\x90¯ç”¨', existing_comment='是否启用', existing_nullable=False, existing_server_default=sa.text("'1'")) op.alter_column('growth_paths', 'estimated_duration_days', existing_type=mysql.INTEGER(), comment='预计完æˆ\x90天数', existing_comment='预计完成天数', existing_nullable=True) op.alter_column('growth_paths', 'courses', existing_type=mysql.JSON(), comment='课程列表[{course_id, order, is_required}]', existing_comment='课程列表[{course_id, order, is_required}]', existing_nullable=True) op.alter_column('growth_paths', 'target_role', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=100), comment='ç›®æ\xa0‡è§’色', existing_comment='目标角色', existing_nullable=True) op.alter_column('growth_paths', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='路径æ\x8f\x8fè¿°', existing_comment='路径描述', existing_nullable=True) op.alter_column('growth_paths', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='路径å\x90\x8dç§°', existing_comment='路径名称', existing_nullable=False) op.create_table_comment( 'courses', '课程表', existing_comment=None, schema=None ) op.drop_index(op.f('ix_courses_id'), table_name='courses') op.create_index('idx_courses_status', 'courses', ['status'], unique=False) op.create_index('idx_courses_is_deleted', 'courses', ['is_deleted'], unique=False) op.create_index('idx_courses_category', 'courses', ['category'], unique=False) op.alter_column('courses', 'is_featured', existing_type=mysql.TINYINT(display_width=1), comment='是å\x90¦æŽ¨è\x8d\x90', existing_comment='是否推荐', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('courses', 'sort_order', existing_type=mysql.INTEGER(), comment='排åº\x8f顺åº\x8f', existing_comment='排序顺序', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('courses', 'publisher_id', existing_type=mysql.INTEGER(), comment='å\x8f‘布人ID', existing_comment='发布人ID', existing_nullable=True) op.alter_column('courses', 'published_at', existing_type=mysql.DATETIME(), comment='å\x8f‘布时间', existing_comment='发布时间', existing_nullable=True) op.alter_column('courses', 'tags', existing_type=mysql.JSON(), comment='æ\xa0‡ç\xad¾åˆ—表', existing_comment='标签列表', existing_nullable=True) op.alter_column('courses', 'difficulty_level', existing_type=mysql.INTEGER(), comment='难度ç\xad‰çº§(1-5)', existing_comment='难度等级(1-5)', existing_nullable=True) op.alter_column('courses', 'duration_hours', existing_type=mysql.FLOAT(), comment='课程时长(å°\x8fæ—¶)', existing_comment='课程时长(小时)', existing_nullable=True) op.alter_column('courses', 'cover_image', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='å°\x81é\x9d¢å›¾ç‰‡URL', existing_comment='封面图片URL', existing_nullable=True) op.alter_column('courses', 'status', existing_type=mysql.ENUM('draft', 'published', 'archived', collation='utf8mb4_unicode_ci'), comment='课程状æ€\x81', existing_comment='课程状态', existing_nullable=False, existing_server_default=sa.text("'draft'")) op.alter_column('courses', 'category', existing_type=mysql.ENUM('technology', 'management', 'business', 'general', collation='utf8mb4_unicode_ci'), comment='课程分类', existing_comment='课程分类', existing_nullable=False, existing_server_default=sa.text("'general'")) op.alter_column('courses', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='课程æ\x8f\x8fè¿°', existing_comment='课程描述', existing_nullable=True) op.alter_column('courses', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='课程å\x90\x8dç§°', existing_comment='课程名称', existing_nullable=False) op.create_table_comment( 'course_materials', '课程资料表', existing_comment=None, schema=None ) op.drop_index(op.f('ix_course_materials_id'), table_name='course_materials') op.create_index('idx_course_materials_is_deleted', 'course_materials', ['is_deleted'], unique=False) op.create_index('idx_course_materials_course_id', 'course_materials', ['course_id'], unique=False) op.alter_column('course_materials', 'sort_order', existing_type=mysql.INTEGER(), comment='排åº\x8f顺åº\x8f', existing_comment='排序顺序', existing_nullable=False, existing_server_default=sa.text("'0'")) op.alter_column('course_materials', 'file_size', existing_type=mysql.INTEGER(), comment='文件大å°\x8f(å\xad—节)', existing_comment='文件大小(字节)', existing_nullable=False) op.alter_column('course_materials', 'file_type', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=50), comment='文件类型', existing_comment='文件类型', existing_nullable=False) op.alter_column('course_materials', 'file_url', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=500), comment='文件URL', existing_comment='文件URL', existing_nullable=False) op.alter_column('course_materials', 'description', existing_type=mysql.TEXT(collation='utf8mb4_unicode_ci'), comment='资料æ\x8f\x8fè¿°', existing_comment='资料描述', existing_nullable=True) op.alter_column('course_materials', 'name', existing_type=mysql.VARCHAR(collation='utf8mb4_unicode_ci', length=200), comment='资料å\x90\x8dç§°', existing_comment='资料名称', existing_nullable=False) op.alter_column('course_materials', 'course_id', existing_type=mysql.INTEGER(), comment='课程ID', existing_comment='课程ID', existing_nullable=False) op.drop_table('user_teams') op.drop_index(op.f('ix_training_reports_user_id'), table_name='training_reports') op.drop_index(op.f('ix_training_reports_id'), table_name='training_reports') op.drop_table('training_reports') op.drop_index(op.f('ix_training_messages_id'), table_name='training_messages') op.drop_table('training_messages') op.drop_index(op.f('ix_training_sessions_user_id'), table_name='training_sessions') op.drop_index(op.f('ix_training_sessions_id'), table_name='training_sessions') op.drop_table('training_sessions') op.drop_index(op.f('ix_training_scenes_id'), table_name='training_scenes') op.drop_table('training_scenes') # ### end Alembic commands ###