CREATE TABLE IF NOT EXISTS tenants (
    id BIGINT NOT NULL,
    name VARCHAR(100) NOT NULL,
    slug VARCHAR(50) NOT NULL,
    plan VARCHAR(20) NOT NULL DEFAULT 'free',
    status TINYINT NOT NULL DEFAULT 1,
    credits DECIMAL(18, 4) NOT NULL DEFAULT 0,
    frozen_credits DECIMAL(18, 4) NOT NULL DEFAULT 0,
    suspended_at TIMESTAMP,
    suspended_by BIGINT,
    suspended_reason VARCHAR(500),
    notes VARCHAR(1000),
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (slug)
);

CREATE TABLE IF NOT EXISTS users (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    phone VARCHAR(20),
    avatar_url VARCHAR(500),
    password_hash VARCHAR(255) NOT NULL,
    role VARCHAR(20) NOT NULL DEFAULT 'member',
    status TINYINT NOT NULL DEFAULT 1,
    last_login_at TIMESTAMP,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (email),
    UNIQUE (username, tenant_id)
);

CREATE TABLE IF NOT EXISTS tenant_members (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    role VARCHAR(20) NOT NULL DEFAULT 'member',
    position VARCHAR(100),
    joined_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (tenant_id, user_id)
);

CREATE TABLE IF NOT EXISTS projects (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    name VARCHAR(200) NOT NULL,
    description CLOB,
    status VARCHAR(20) NOT NULL DEFAULT 'draft',
    style VARCHAR(50),
    aspect_ratio VARCHAR(20),
    resolution VARCHAR(20),
    cover_key VARCHAR(500),
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS project_assets (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    name VARCHAR(255) NOT NULL,
    original_name VARCHAR(255) NOT NULL,
    asset_type VARCHAR(50) NOT NULL DEFAULT 'other',
    mime_type VARCHAR(100),
    file_size BIGINT,
    tos_key VARCHAR(500) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS outlines (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    title VARCHAR(255),
    genre VARCHAR(100),
    episode_count INT,
    synopsis CLOB,
    raw_json CLOB,
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS episodes (
    id BIGINT NOT NULL,
    outline_id BIGINT,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    episode_number INT NOT NULL,
    title VARCHAR(255),
    summary CLOB,
    script CLOB,
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS characters (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    name VARCHAR(100) NOT NULL,
    role_type VARCHAR(50),
    gender VARCHAR(20),
    age VARCHAR(50),
    personality CLOB,
    background CLOB,
    costume CLOB,
    visual_hint CLOB,
    image_prompt CLOB,
    image_url VARCHAR(1024),
    image_tos_key VARCHAR(512),
    front_image_url VARCHAR(1024),
    front_image_tos_key VARCHAR(512),
    side_image_url VARCHAR(1024),
    side_image_tos_key VARCHAR(512),
    back_image_url VARCHAR(1024),
    back_image_tos_key VARCHAR(512),
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS character_states (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    character_id BIGINT NOT NULL,
    name VARCHAR(128) NOT NULL,
    state_type VARCHAR(32) DEFAULT 'costume',
    description CLOB,
    prompt CLOB,
    reference_image_key VARCHAR(512),
    image_url VARCHAR(1024),
    image_tos_key VARCHAR(512),
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS scenes (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    name VARCHAR(120) NOT NULL,
    scene_type VARCHAR(50),
    description CLOB,
    image_prompt CLOB,
    image_url VARCHAR(1024),
    image_tos_key VARCHAR(512),
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS storyboards (
    id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    episode_id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    sequence_num INT NOT NULL,
    scene_number VARCHAR(50),
    short_description VARCHAR(255),
    detailed_description CLOB,
    characters CLOB,
    dialogues CLOB,
    camera_direction CLOB,
    composition_guide CLOB,
    duration_seconds INT,
    motion_script CLOB,
    start_frame_prompt CLOB,
    end_frame_prompt CLOB,
    scene_ref VARCHAR(255),
    video_prompt CLOB,
    notes CLOB,
    character_image_keys CLOB,
    scene_image_key VARCHAR(512),
    prop_image_keys CLOB,
    style_image_key VARCHAR(512),
    status VARCHAR(32) NOT NULL DEFAULT 'draft',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_outlines_project ON outlines (project_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_episodes_project ON episodes (project_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_characters_project ON characters (project_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_scenes_project ON scenes (project_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_storyboards_episode ON storyboards (episode_id, tenant_id);

CREATE TABLE IF NOT EXISTS shot_assets (
    id BIGINT NOT NULL,
    storyboard_id BIGINT NOT NULL,
    project_id BIGINT,
    episode_id BIGINT,
    tenant_id BIGINT NOT NULL,
    asset_type VARCHAR(32) NOT NULL,
    tos_key VARCHAR(512),
    external_url VARCHAR(1024),
    source_task_id BIGINT,
    prompt CLOB,
    model_provider VARCHAR(64),
    model_id VARCHAR(128),
    asset_version INT NOT NULL DEFAULT 1,
    characters CLOB,
    meta_json CLOB,
    error_message CLOB,
    status VARCHAR(32) NOT NULL DEFAULT 'pending',
    is_active TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_shot_assets_storyboard ON shot_assets (storyboard_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_shot_assets_project ON shot_assets (project_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_shot_assets_task ON shot_assets (source_task_id);

CREATE TABLE IF NOT EXISTS tenant_balances (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    balance DECIMAL(18, 4) NOT NULL DEFAULT 0,
    total_recharged DECIMAL(18, 4) NOT NULL DEFAULT 0,
    total_spent DECIMAL(18, 4) NOT NULL DEFAULT 0,
    version INT NOT NULL DEFAULT 0,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (tenant_id)
);

CREATE TABLE IF NOT EXISTS billing_records (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    project_id BIGINT,
    user_id BIGINT,
    created_by_admin_id BIGINT,
    operation VARCHAR(64) NOT NULL,
    modality VARCHAR(16),
    model_provider VARCHAR(64),
    model_id VARCHAR(128),
    model_name VARCHAR(128),
    unit_count INT,
    success BOOLEAN,
    billing_meta CLOB,
    credits DECIMAL(18, 4) NOT NULL DEFAULT 0,
    billing_mode VARCHAR(16) NOT NULL DEFAULT 'SOFT',
    ref_id VARCHAR(128),
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS customer_tickets (
    id BIGINT NOT NULL,
    ticket_no VARCHAR(64) NOT NULL,
    tenant_id BIGINT NOT NULL,
    requester_user_id BIGINT,
    category VARCHAR(64) NOT NULL,
    priority VARCHAR(32) NOT NULL,
    status VARCHAR(32) NOT NULL,
    assignee VARCHAR(64),
    source VARCHAR(64),
    subject VARCHAR(200) NOT NULL,
    description CLOB,
    related_ref VARCHAR(128),
    first_response_at TIMESTAMP,
    resolved_at TIMESTAMP,
    due_at TIMESTAMP,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (ticket_no)
);

CREATE INDEX IF NOT EXISTS idx_customer_tickets_tenant_status ON customer_tickets (tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_customer_tickets_due ON customer_tickets (due_at, status);

CREATE TABLE IF NOT EXISTS customer_scripts (
    id BIGINT NOT NULL,
    title VARCHAR(200) NOT NULL,
    category VARCHAR(64),
    scene VARCHAR(200),
    target_role VARCHAR(64),
    trigger_keywords CLOB,
    reply_template CLOB,
    handoff_rule CLOB,
    tags VARCHAR(255),
    updated_by VARCHAR(64),
    status VARCHAR(32) NOT NULL DEFAULT '待审核',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_customer_scripts_category_status ON customer_scripts (category, status);
CREATE INDEX IF NOT EXISTS idx_customer_scripts_status_updated ON customer_scripts (status, updated_at);

CREATE TABLE IF NOT EXISTS content_articles (
    id BIGINT NOT NULL,
    content_type VARCHAR(32) NOT NULL,
    title VARCHAR(240) NOT NULL,
    category VARCHAR(80),
    scope VARCHAR(80),
    version VARCHAR(32),
    owner VARCHAR(64),
    article_type VARCHAR(64),
    publish_at TIMESTAMP,
    read_mode VARCHAR(64),
    status VARCHAR(32) NOT NULL DEFAULT '待发布',
    summary CLOB,
    content CLOB,
    front_template VARCHAR(80),
    front_audience VARCHAR(80),
    publish_targets VARCHAR(255),
    read_count INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_content_articles_type_status ON content_articles (content_type, status);
CREATE INDEX IF NOT EXISTS idx_content_articles_publish ON content_articles (content_type, publish_at);

CREATE TABLE IF NOT EXISTS system_settings (
    id BIGINT NOT NULL,
    setting_key VARCHAR(128) NOT NULL,
    setting_name VARCHAR(160),
    setting_group VARCHAR(64),
    setting_value CLOB,
    value_type VARCHAR(32) NOT NULL DEFAULT 'text',
    scope VARCHAR(80) NOT NULL DEFAULT '全平台',
    status VARCHAR(32) NOT NULL DEFAULT '启用',
    effective_at TIMESTAMP,
    change_reason CLOB,
    description CLOB,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by BIGINT,
    PRIMARY KEY (id),
    UNIQUE (setting_key)
);

CREATE TABLE IF NOT EXISTS admin_users (
    id BIGINT NOT NULL,
    username VARCHAR(64) NOT NULL,
    password_hash VARCHAR(255),
    display_name VARCHAR(128),
    email VARCHAR(255),
    role VARCHAR(32) NOT NULL DEFAULT 'OPERATOR',
    status TINYINT NOT NULL DEFAULT 1,
    must_change_password TINYINT NOT NULL DEFAULT 0,
    last_login_at TIMESTAMP,
    last_login_ip VARCHAR(45),
    created_by BIGINT,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (username)
);

CREATE INDEX IF NOT EXISTS idx_admin_users_role_status ON admin_users (role, status);

CREATE TABLE IF NOT EXISTS admin_audit_logs (
    id BIGINT NOT NULL,
    admin_user_id BIGINT NOT NULL,
    admin_username VARCHAR(64),
    action VARCHAR(64) NOT NULL,
    resource_type VARCHAR(32),
    resource_id VARCHAR(64),
    before_value CLOB,
    after_value CLOB,
    ip VARCHAR(45),
    user_agent VARCHAR(255),
    request_id VARCHAR(64),
    status VARCHAR(16) NOT NULL DEFAULT 'SUCCESS',
    error_message CLOB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_admin_time ON admin_audit_logs (admin_user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_resource ON admin_audit_logs (resource_type, resource_id);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_action_time ON admin_audit_logs (action, created_at);

CREATE TABLE IF NOT EXISTS plans (
    id BIGINT NOT NULL,
    code VARCHAR(32) NOT NULL,
    name VARCHAR(64) NOT NULL,
    price_monthly DECIMAL(10, 2) DEFAULT 0,
    monthly_credits INT DEFAULT 0,
    max_members INT DEFAULT 1,
    max_projects INT DEFAULT 0,
    max_concurrent_tasks INT DEFAULT 1,
    features CLOB,
    is_active TINYINT NOT NULL DEFAULT 1,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by BIGINT,
    PRIMARY KEY (id),
    UNIQUE (code)
);

CREATE TABLE IF NOT EXISTS tenant_quotas (
    tenant_id BIGINT NOT NULL,
    max_members INT,
    max_projects INT,
    max_monthly_credits INT,
    max_concurrent_tasks INT,
    monthly_budget_limit DECIMAL(18, 4),
    notes CLOB,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_by BIGINT,
    PRIMARY KEY (tenant_id)
);

CREATE TABLE IF NOT EXISTS admin_menus (
    id BIGINT NOT NULL,
    parent_id BIGINT NOT NULL DEFAULT 0,
    title VARCHAR(64) NOT NULL,
    path VARCHAR(128),
    icon VARCHAR(64),
    allowed_roles VARCHAR(255),
    sort_order INT NOT NULL DEFAULT 0,
    status TINYINT NOT NULL DEFAULT 1,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_admin_menus_parent_sort ON admin_menus (parent_id, sort_order);
CREATE INDEX IF NOT EXISTS idx_admin_menus_status_sort ON admin_menus (status, sort_order);

CREATE TABLE IF NOT EXISTS admin_page_data (
    page_key VARCHAR(64) NOT NULL,
    payload_json CLOB NOT NULL,
    status TINYINT NOT NULL DEFAULT 1,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (page_key)
);

CREATE TABLE IF NOT EXISTS permission_policies (
    code VARCHAR(64) NOT NULL,
    name VARCHAR(80) NOT NULL,
    category VARCHAR(40) NOT NULL,
    scope VARCHAR(80) NOT NULL,
    description VARCHAR(255) NOT NULL,
    default_roles VARCHAR(120),
    status TINYINT NOT NULL DEFAULT 1,
    sort_order INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (code)
);

CREATE INDEX IF NOT EXISTS idx_permission_category ON permission_policies (category, status, sort_order);

CREATE TABLE IF NOT EXISTS tenant_member_permissions (
    id BIGINT NOT NULL AUTO_INCREMENT,
    tenant_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    policy_code VARCHAR(64) NOT NULL,
    permission_level VARCHAR(24) NOT NULL DEFAULT '允许',
    data_scope VARCHAR(80) NOT NULL DEFAULT '本企业',
    grant_source VARCHAR(80) NOT NULL DEFAULT '运营配置',
    status TINYINT NOT NULL DEFAULT 1,
    granted_by BIGINT,
    granted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    revoked_at TIMESTAMP,
    remark VARCHAR(255),
    PRIMARY KEY (id),
    UNIQUE (tenant_id, user_id, policy_code)
);

CREATE INDEX IF NOT EXISTS idx_tenant_policy ON tenant_member_permissions (tenant_id, policy_code, status);
CREATE INDEX IF NOT EXISTS idx_user_policy ON tenant_member_permissions (user_id, policy_code, status);

CREATE TABLE IF NOT EXISTS admin_report_definitions (
    code VARCHAR(64) NOT NULL,
    name VARCHAR(128) NOT NULL,
    scope VARCHAR(255) NOT NULL,
    data_source VARCHAR(255) NOT NULL,
    owner VARCHAR(64) NOT NULL DEFAULT '系统',
    status VARCHAR(32) NOT NULL DEFAULT '已生成',
    sort_order INT NOT NULL DEFAULT 0,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (code)
);

CREATE TABLE IF NOT EXISTS admin_report_rules (
    code VARCHAR(64) NOT NULL,
    name VARCHAR(128) NOT NULL,
    scope CLOB NOT NULL,
    formula CLOB NOT NULL,
    owner VARCHAR(64) NOT NULL DEFAULT '系统',
    editable VARCHAR(255) NOT NULL DEFAULT '需管理员确认',
    notes CLOB,
    status TINYINT NOT NULL DEFAULT 1,
    sort_order INT NOT NULL DEFAULT 0,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (code)
);

MERGE INTO admin_users KEY(username)
VALUES (
    1,
    'admin',
    '$2a$10$c.oWvJrAswv3JS3uOk/YhemH82j5CLPar1etsaY6CdVB.i6eMU7wC',
    '超级管理员',
    'admin@yaoai.com',
    'SUPER_ADMIN',
    1,
    0,
    NULL,
    NULL,
    NULL,
    CURRENT_TIMESTAMP,
    CURRENT_TIMESTAMP
);

MERGE INTO plans KEY(code) VALUES
    (1, 'FREE', '免费版', 0.00, 100, 1, 3, 1, '{"watermark":true,"libraries":["personal"]}', 1, CURRENT_TIMESTAMP, NULL),
    (2, 'PRO', '专业版', 99.00, 3000, 5, 20, 3, '{"watermark":false,"libraries":["personal","team"]}', 1, CURRENT_TIMESTAMP, NULL),
    (3, 'TEAM', '团队版', 499.00, 20000, 20, 100, 5, '{"watermark":false,"libraries":["personal","team"],"api":true}', 1, CURRENT_TIMESTAMP, NULL),
    (4, 'ENTERPRISE', '企业版', 0.00, 0, 0, 0, 10, '{"watermark":false,"libraries":["personal","team","market"],"api":true,"sla":true,"private_deploy":true}', 1, CURRENT_TIMESTAMP, NULL);

MERGE INTO admin_menus KEY(id) VALUES
    (100, 0, '仪表盘', '/dashboard', 'DataBoard', NULL, 100, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (200, 0, '企业', NULL, 'OfficeBuilding', NULL, 200, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (201, 200, '企业列表', '/tenants', 'OfficeBuilding', 'SUPER_ADMIN,OPERATOR,FINANCE,READONLY', 201, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (202, 200, '团队管理', '/users', 'UserFilled', 'SUPER_ADMIN,OPERATOR,READONLY', 202, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (204, 200, '权限配置', '/permission-config', 'Key', 'SUPER_ADMIN,OPERATOR', 204, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (205, 200, '模型配置', '/model-config', 'Setting', 'SUPER_ADMIN,OPERATOR,READONLY', 205, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (206, 200, '用量统计', '/enterprise-usage', 'Histogram', 'SUPER_ADMIN,OPERATOR,FINANCE,READONLY', 206, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (400, 0, '工具', NULL, 'Operation', NULL, 300, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (401, 400, '运营预警', '/warnings', 'Warning', 'SUPER_ADMIN,OPERATOR,READONLY', 301, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (402, 400, '数据报表', '/reports', 'Histogram', 'SUPER_ADMIN,OPERATOR,FINANCE,READONLY', 302, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (711, 400, '运营账号', '/admin-users', 'Key', 'SUPER_ADMIN', 303, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (721, 400, '全局参数', '/global-settings', 'SetUp', 'SUPER_ADMIN', 304, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (300, 0, '费用', NULL, 'Wallet', NULL, 400, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (311, 300, '计费记录', '/billing/records', 'Coin', 'SUPER_ADMIN,OPERATOR,FINANCE,READONLY', 401, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (312, 300, '计费规则', '/billing/costs', 'Money', 'SUPER_ADMIN', 402, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (313, 300, '套餐管理', '/plans', 'Wallet', 'SUPER_ADMIN', 403, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (321, 300, '订单与发票', '/orders-invoices', 'CreditCard', 'SUPER_ADMIN,FINANCE,OPERATOR', 404, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (315, 300, '订单操作记录', '/order-operation-logs', 'Memo', 'SUPER_ADMIN,FINANCE,OPERATOR,READONLY', 405, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (500, 0, '支持', NULL, 'Headset', 'SUPER_ADMIN,OPERATOR,READONLY', 500, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (501, 500, '工单工作台', '/tickets', 'Tickets', 'SUPER_ADMIN,OPERATOR', 501, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (502, 500, '话术库', '/script-library', 'ChatDotSquare', 'SUPER_ADMIN,OPERATOR', 502, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (503, 500, '客服绩效', '/support-performance', 'TrendCharts', 'SUPER_ADMIN,OPERATOR,READONLY', 503, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (700, 0, '备案', NULL, 'Finished', NULL, 600, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (203, 700, '入驻审核', '/tenant-audits', 'Finished', 'SUPER_ADMIN,OPERATOR', 701, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (712, 700, '操作日志', '/audit-logs', 'Memo', 'SUPER_ADMIN,READONLY', 702, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (600, 0, '文档', NULL, 'Guide', 'SUPER_ADMIN,OPERATOR,READONLY', 700, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (601, 600, '使用手册', '/manuals', 'Guide', 'SUPER_ADMIN,OPERATOR', 701, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    (602, 600, '政策与新闻', '/announcements', 'Bell', 'SUPER_ADMIN,OPERATOR', 702, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);

MERGE INTO permission_policies KEY(code) VALUES
    ('TEAM_MANAGE', '团队管理', '企业配置', '企业成员与组织关系', '邀请、编辑、禁用成员并维护组织角色。', 'owner,admin', 1, 10, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('USAGE_VIEW', '用量统计', '企业配置', '资源流水与模型消耗', '查看企业用量、积分流水、模型消耗和导出统计。', 'owner,admin,member', 1, 20, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('MODEL_CONFIG', '模型配置', '企业配置', '模型供应商与默认模型', '维护企业接入的模型供应商、模型清单和默认模型。', 'owner,admin', 1, 30, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('PROJECT_MANAGE', '项目管理', '创作工具', '短剧项目与任务', '创建、编辑、删除项目并管理生成任务。', 'owner,admin,member', 1, 40, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('ASSET_MANAGE', '资产管理', '创作工具', '角色、场景、素材资产', '上传、复用和管理企业资产库。', 'owner,admin,member', 1, 50, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('BILLING_MANAGE', '费用管理', '费用', '套餐、订单与发票', '管理套餐、充值、发票与退款处理。', 'owner,admin', 1, 60, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('SECURITY_AUDIT', '安全审计', '备案', '操作记录与合规确认', '查看企业侧关键操作记录和政策确认状态。', 'owner', 1, 70, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);

MERGE INTO admin_report_definitions KEY(code) VALUES
    ('conversion_funnel', '付费转化漏斗', '注册企业 / 付费企业 / 复购企业', 'tenants, billing_records', '系统', '已生成', 10, CURRENT_TIMESTAMP),
    ('resource_consumption', '资源消耗结构', '模型 / 模态 / 成功调用 / 积分消耗', 'billing_records', '系统', '已生成', 20, CURRENT_TIMESTAMP),
    ('tenant_activity', '企业活跃度分层', '登录 / 项目更新 / 任务流水', 'tenants, users, projects, billing_records', '系统', '已生成', 30, CURRENT_TIMESTAMP),
    ('billing_aov', '订单客单与充值', '充值笔数 / 充值积分 / 平均单笔', 'billing_records, tenant_balances', '财务运营', '已生成', 40, CURRENT_TIMESTAMP),
    ('quota_capacity', '套餐容量与配额', '成员 / 项目 / 月积分 / 并发上限', 'plans, tenant_quotas, tenants', '运营负责人', '已生成', 50, CURRENT_TIMESTAMP);

MERGE INTO admin_report_rules KEY(code) VALUES
    ('paid_conversion_rate', '付费转化率', '衡量全部有效企业中产生过真实充值流水的比例。排除已删除租户，充值以 billing_records 中 operation=recharge 或 modality=RECHARGE 且 credits>0 为准。', '付费转化率 = 付费企业数 / 有效企业数 * 100%', '运营负责人', '可调整排除条件', '用于销售漏斗、入驻质量和套餐转化分析。', 1, 10, CURRENT_TIMESTAMP),
    ('repurchase_rate', '复购率', '同一企业产生 2 笔及以上真实充值流水即记为复购。赠送、补偿和失败流水不计入。', '复购率 = 复购企业数 / 已付费企业数 * 100%', '计费负责人', '可调整复购窗口', '当前开发库未单独建订单表，先以资源充值流水承载付费订单口径。', 1, 20, CURRENT_TIMESTAMP),
    ('resource_consumption', '资源消耗结构', '按成功模型调用流水统计，充值、失败任务、取消或回滚流水不纳入消耗。', '模型消耗 = SUM(billing_records.credits WHERE 非充值 AND success=true)', '财务运营', '只允许调整维度分组', '用于模型成本复盘和资源包定价。', 1, 30, CURRENT_TIMESTAMP),
    ('tenant_activity', '企业活跃分层', '按最近登录、项目更新、模型调用三类行为综合判断企业活跃度。', '活跃企业 = 近7天登录 OR 近14天项目更新 OR 近14天有资源流水；沉睡企业 = 30天无有效行为', '客服主管', '可调整天数阈值', '沉睡企业可进入运营预警和客服回访。', 1, 40, CURRENT_TIMESTAMP),
    ('average_recharge', '平均单笔充值积分', '仅统计 credits>0 的真实充值流水，作为当前资源包订单的金额替代口径。', '平均单笔充值积分 = 充值积分合计 / 充值笔数', '财务运营', '可在接入订单表后替换为实付金额', '正式订单/发票表上线后应迁移为 paid_amount 口径。', 1, 50, CURRENT_TIMESTAMP),
    ('monthly_report', '月报生成规则', '每月 1 日生成上月数据，支持人工重算；规则版本和操作者需要进入审计日志。', '月报 = 按规则快照汇总 tenants / billing_records / users / projects / tenant_quotas', '系统', '需管理员确认', '规则变更后建议重算最近一个自然月。', 1, 60, CURRENT_TIMESTAMP);

MERGE INTO admin_page_data KEY(page_key) VALUES
('tenantAudits', '{"title":"入驻审核中心","desc":"企业入驻资料、营业执照、法人身份与试用开通统一核验","primary":"新建入驻申请","workflow":["资料提交","证照核验","法人核身","试用开通","审计归档"],"metrics":[{"label":"待初审","value":"4","hint":"平均等待 1.2 小时"},{"label":"证照异常","value":"2","hint":"执照或法人信息不一致"},{"label":"今日通过","value":"9","hint":"已开通试用 7 家"},{"label":"需补件","value":"3","hint":"授权书/身份证缺失"}],"filters":["审核状态","证照状态","法人核身","试用包"],"columns":[{"prop":"company","label":"企业名称","minWidth":180},{"prop":"creditCode","label":"统一社会信用代码","minWidth":190},{"prop":"legalPerson","label":"法人","width":100},{"prop":"licenseStatus","label":"营业执照","width":120,"tag":true},{"prop":"identityStatus","label":"身份核验","width":120,"tag":true},{"prop":"contact","label":"联系人","width":110},{"prop":"trialPlan","label":"拟开通套餐","width":130,"tag":true},{"prop":"risk","label":"风险结论","width":120,"tag":true},{"prop":"status","label":"审核状态","width":120,"tag":true}],"rows":[{"id":"AUD20260526001","company":"星火互动文化","creditCode":"91310115MA1K4X2C8Q","legalPerson":"李敏","licenseStatus":"已验真","identityStatus":"人证一致","contact":"李女士","phone":"138****1001","submittedAt":"2026-05-26 09:12","businessScope":"广播电视节目制作、数字内容服务","trialPlan":"专业版试用","risk":"低风险","status":"待复核"},{"id":"AUD20260525018","company":"青石影像工作室","creditCode":"92440106MA9Y8N3L2G","legalPerson":"王磊","licenseStatus":"待补件","identityStatus":"身份证缺失","contact":"王先生","phone":"136****3001","submittedAt":"2026-05-25 18:30","businessScope":"摄影扩印、影视策划","trialPlan":"免费版","risk":"需人工确认","status":"需退回"},{"id":"AUD20260525007","company":"环声传媒","creditCode":"91440300MA5G9P6W1R","legalPerson":"赵晴","licenseStatus":"已验真","identityStatus":"人脸通过","contact":"赵女士","phone":"139****2001","submittedAt":"2026-05-25 14:05","businessScope":"文化传媒、短视频制作、广告投放","trialPlan":"团队版试用","risk":"低风险","status":"待开通"}],"cards":[{"title":"入驻核验清单","value":"营业执照 / 法人身份 / 授权关系","items":["统一社会信用代码需通过格式与重复校验","法人姓名需与证照主体一致","非法人经办需上传企业授权书"]},{"title":"通过后动作","value":"开通租户 + 试用资源 + 审计留痕","items":["生成企业租户与 Owner 账号","按试用包配置额度和并发上限","记录审核人、审核意见和开通时间"]}]}', 1, CURRENT_TIMESTAMP),
('ordersInvoices', '{"title":"订单与发票","desc":"交易订单、退款审批、发票申请统一处理","primary":"新建线下订单","workflow":["订单创建","支付核验","资源入账","开票归档"],"metrics":[{"label":"今日订单","value":"56","hint":"已支付 42 笔"},{"label":"待退款审批","value":"2","hint":"涉及 ¥3,498"},{"label":"待开票","value":"4","hint":"最早申请 09:20"}],"filters":["订单状态","支付时间","发票状态","企业名称"],"columns":[{"prop":"orderNo","label":"订单号","minWidth":170},{"prop":"company","label":"所属企业","minWidth":180},{"prop":"package","label":"资源包","width":130},{"prop":"amount","label":"实付金额","width":120},{"prop":"invoice","label":"发票状态","width":120,"tag":true},{"prop":"status","label":"支付状态","width":120,"tag":true}],"rows":[{"orderNo":"O202605260091","company":"星火互动文化","package":"专业版","amount":"¥1,999","invoice":"待开具","status":"已支付"},{"orderNo":"O202605250218","company":"环声传媒","package":"积分加油包","amount":"¥299","invoice":"无需发票","status":"已支付"},{"orderNo":"O202605240087","company":"青石影像工作室","package":"团队版","amount":"¥4,999","invoice":"已邮寄","status":"退款中"}],"cards":[{"title":"财务处理","value":"退款与开票","items":["退款需二次确认并记录原因","发票支持录入抬头与快递单号","订单状态联动资源台账"]}]}', 1, CURRENT_TIMESTAMP),
('warnings', '{"title":"运营预警表","desc":"沉睡客户、资源不足、即将过期与欠费风险集中干预","primary":"导出预警名单","workflow":["风险扫描","生成预警","负责人跟进","关闭风险"],"metrics":[{"label":"沉睡客户","value":"23","hint":"30 天未登录"},{"label":"资源不足","value":"15","hint":"低于阈值 20%"},{"label":"即将过期","value":"8","hint":"7 天内到期"},{"label":"欠费预警","value":"3","hint":"存在逾期订单"}],"filters":["预警类型","风险等级","客户阶段","负责人"],"columns":[{"prop":"company","label":"企业名称","minWidth":180},{"prop":"type","label":"预警类型","width":130,"tag":true},{"prop":"level","label":"风险等级","width":110,"tag":true},{"prop":"reason","label":"触发原因","minWidth":220},{"prop":"owner","label":"负责人","width":110}],"rows":[{"company":"灵感短剧社","type":"资源不足","level":"高","reason":"剩余积分 12%，最近 7 天消耗加速","owner":"陈运营"},{"company":"星轨传媒","type":"即将过期","level":"中","reason":"企业版 3 天后到期","owner":"周商务"},{"company":"南风影业","type":"沉睡客户","level":"中","reason":"45 天未登录，近 60 天无项目产出","owner":"林客服"}],"cards":[{"title":"干预建议","value":"3 类动作","items":["资源不足客户优先推送续费包","沉睡客户进入客服回访队列","欠费订单同步商务跟进"]}]}', 1, CURRENT_TIMESTAMP),
('reports', '{"title":"数据报表中心","desc":"留存、活跃、消耗、销售漏斗的多维分析与算法口径管理","primary":"生成月报","workflow":["数据汇总","指标计算","规则校验","趋势分析","月报输出"],"metrics":[{"label":"付费转化率","value":"18.6%","hint":"注册到付费企业"},{"label":"复购率","value":"31.4%","hint":"90 天内二次购买"},{"label":"平均客单价","value":"¥2,810","hint":"已支付订单均值"},{"label":"积分消耗","value":"826万","hint":"成功模型调用合计"}],"filters":["时间范围","资源包","行业","销售归属"],"columns":[{"prop":"name","label":"报表名称","minWidth":180},{"prop":"scope","label":"统计口径","minWidth":180},{"prop":"dataSource","label":"数据来源","minWidth":180},{"prop":"updatedAt","label":"更新时间","minWidth":150},{"prop":"owner","label":"负责人","minWidth":110},{"prop":"status","label":"状态","minWidth":110,"tag":true}],"rows":[{"name":"付费转化漏斗","scope":"注册 / 试用 / 付费 / 复购","dataSource":"租户、订单、资源流水","updatedAt":"2026-05-26 08:00","owner":"系统","status":"已生成"},{"name":"资源消耗结构","scope":"剧本 / 图片 / 视频 / 配音 / 素材","dataSource":"模型调用流水、任务表","updatedAt":"2026-05-26 08:00","owner":"系统","status":"已生成"},{"name":"企业活跃度分层","scope":"DAU / WAU / MAU / 沉睡客户","dataSource":"登录日志、项目、任务","updatedAt":"2026-05-25 23:30","owner":"系统","status":"计算中"},{"name":"销售归因与客单价","scope":"销售负责人 / 套餐 / 订单金额","dataSource":"租户、订单与发票","updatedAt":"2026-05-25 20:00","owner":"财务运营","status":"已生成"}],"logicRules":[{"name":"付费转化率","scope":"衡量注册企业在统计周期内完成首笔支付的比例。排除测试租户、已删除租户和退款全额冲销订单。","formula":"付费转化率 = 首次支付企业数 / 新注册企业数 * 100%","owner":"运营负责人","editable":"可调整排除条件","notes":"常用于销售漏斗与投放质量评估。"},{"name":"复购率","scope":"企业首次付费后 90 天内产生第二笔已支付订单即记为复购。积分赠送、手工补偿不计入复购。","formula":"复购率 = 90天内复购企业数 / 已付费企业数 * 100%","owner":"计费负责人","editable":"可调整观察窗口","notes":"默认窗口为 90 天，企业版可单独分析。"},{"name":"资源消耗结构","scope":"按实际成功的模型调用流水统计，失败任务、取消任务和回滚流水不纳入消耗。","formula":"模型消耗 = SUM(resource_ledger.amount where operation = consume and success = true)","owner":"财务运营","editable":"只允许调整维度分组","notes":"用于模型成本复盘和资源包定价。"},{"name":"企业活跃分层","scope":"按登录、项目编辑、任务生成三类行为综合判断企业活跃度。","formula":"活跃企业 = 近7天登录或近14天有项目/任务行为；沉睡企业 = 30天无有效行为","owner":"客服主管","editable":"可调整天数阈值","notes":"沉睡企业会进入运营预警与客服回访。"},{"name":"平均客单价","scope":"仅统计已支付订单金额，退款中订单按原金额计入，已全额退款订单剔除。","formula":"平均客单价 = 已支付订单实付金额合计 / 已支付订单数","owner":"财务运营","editable":"可调整退款处理口径","notes":"用于套餐定价和销售归因分析。"},{"name":"月报生成规则","scope":"每月 1 日生成上月数据，支持人工重算。重算会记录操作者、时间和规则版本。","formula":"月报 = 按规则快照汇总 tenants / orders / ledger / tasks / tickets","owner":"系统","editable":"需管理员确认","notes":"规则变更后建议重算最近一个自然月。"}],"cards":[{"title":"规则管理","value":"6 个核心算法口径","items":["转化、复购、客单价、活跃分层、资源消耗和月报生成均有明确公式","每条规则标注负责人和可调整范围","规则变更后进入审计日志并可触发报表重算"]},{"title":"数据来源","value":"租户 / 订单 / 流水 / 任务 / 工单","items":["模型消耗来自资源流水而非前端展示值","活跃度同时参考登录、项目和任务行为","财务指标默认排除测试租户和全额退款订单"]}]}', 1, CURRENT_TIMESTAMP),
('tickets', '{"title":"工单工作台","desc":"企业咨询、问题反馈、转派与 SLA 跟踪","primary":"新建工单","workflow":["待分配","处理中","已解决","已关闭"],"metrics":[{"label":"待分配","value":"9","hint":"紧急 2 条"},{"label":"处理中","value":"18","hint":"平均 1.4 小时"},{"label":"今日解决","value":"31","hint":"解决率 93%"},{"label":"超时风险","value":"3","hint":"需立即跟进"}],"filters":["工单状态","优先级","工单分类","处理人"],"columns":[{"prop":"ticketNo","label":"工单号","minWidth":150},{"prop":"company","label":"企业","minWidth":160},{"prop":"category","label":"分类","width":110,"tag":true},{"prop":"priority","label":"优先级","width":110,"tag":true},{"prop":"assignee","label":"处理人","width":110},{"prop":"status","label":"状态","width":110,"tag":true}],"rows":[{"ticketNo":"TK20260526001","company":"星火互动文化","category":"资源","priority":"紧急","assignee":"林客服","status":"处理中"},{"ticketNo":"TK20260526002","company":"南风影业","category":"账号","priority":"普通","assignee":"待分配","status":"待分配"},{"ticketNo":"TK20260525018","company":"环声传媒","category":"功能","priority":"加急","assignee":"陈客服","status":"已解决"}],"cards":[{"title":"流转规则","value":"待分配 -> 处理中 -> 已解决 -> 已关闭","items":["支持人工转派","可调用话术库快速回复","超时自动进入预警"]}]}', 1, CURRENT_TIMESTAMP),
('scriptLibrary', '{"title":"话术库管理","desc":"面向 AI 短剧 SaaS 的客服标准回复、升级规则与工单处理知识库","primary":"新增话术","workflow":["创建草稿","质检审核","发布启用","工单调用","效果复盘"],"metrics":[{"label":"话术总数","value":"9","hint":"覆盖入驻/计费/生成/发票"},{"label":"已发布","value":"7","hint":"可在工单中调用"},{"label":"待审核","value":"2","hint":"本周新增"},{"label":"命中场景","value":"6","hint":"客服高频问题"}],"filters":["分类","适用场景","启用状态","关键词"],"columns":[{"prop":"title","label":"话术标题","minWidth":220},{"prop":"category","label":"分类","minWidth":120,"tag":true},{"prop":"scene","label":"适用场景","minWidth":150},{"prop":"targetRole","label":"适用对象","minWidth":120,"tag":true},{"prop":"triggerKeywords","label":"触发关键词","minWidth":220},{"prop":"updatedBy","label":"维护人","minWidth":110},{"prop":"status","label":"状态","minWidth":100,"tag":true}],"rows":[{"title":"入驻资料补件说明","category":"入驻审核","scene":"证照/法人资料缺失","targetRole":"企业管理员","triggerKeywords":"营业执照、法人身份证、授权书、补件","replyTemplate":"您好，当前入驻资料还缺少必要核验材料。请补充营业执照清晰图片、法人身份证正反面或经办人授权书。资料提交后运营会在 1 个工作小时内复核，审核通过后会自动开通试用资源。","handoffRule":"涉及证照主体不一致时转运营审核；客户催办超过 30 分钟转客服主管。","updatedBy":"林客服","status":"已发布"},{"title":"积分消耗异常解释","category":"计费结算","scene":"客户质疑积分扣减","targetRole":"企业管理员","triggerKeywords":"积分少了、扣费、消耗异常、账单不对","replyTemplate":"您好，平台积分会按实际调用的模型、输入素材与输出时长记录流水。您可以在企业后台的资源流水中按项目、模型和日期核对。若发现重复扣减，请提供项目名和任务时间，我们会提交财务与技术联合复核。","handoffRule":"单笔差异超过 5000 积分或涉及退款时转财务值班。","updatedBy":"陈客服","status":"已发布"},{"title":"视频生成排队说明","category":"生成任务","scene":"视频任务等待过久","targetRole":"企业成员","triggerKeywords":"排队、生成慢、一直等待、任务卡住","replyTemplate":"您好，视频生成会根据当前并发额度和模型队列依次处理。企业版/团队版支持更高并发；如果任务超过 30 分钟没有进入执行，请提供项目 ID，我们会检查任务状态并协助重试。","handoffRule":"任务失败或等待超过 30 分钟转技术值班。","updatedBy":"周客服","status":"已发布"},{"title":"模型生成失败安抚与重试","category":"生成任务","scene":"图片/视频/剧本生成失败","targetRole":"企业成员","triggerKeywords":"失败、报错、重试、生成不了","replyTemplate":"您好，生成失败通常与素材格式、提示词安全策略或上游模型临时波动有关。系统不会对失败任务重复扣减成功消耗积分。请先检查素材格式和提示词；如仍失败，我们可以协助发起一次任务重试。","handoffRule":"连续失败 2 次以上转技术值班并关联任务 ID。","updatedBy":"周客服","status":"已发布"},{"title":"发票开具与退款进度说明","category":"订单发票","scene":"开票/退款咨询","targetRole":"企业管理员","triggerKeywords":"发票、退款、付款、订单、抬头","replyTemplate":"您好，发票申请会在支付核验后进入财务处理，专票需确认纳税人识别号、注册地址和开户行信息。退款申请需要先冻结对应资源额度，再由财务在 1-3 个工作日内处理。","handoffRule":"退款中状态超过 2 个工作日转财务值班。","updatedBy":"赵财务","status":"已发布"},{"title":"成员邀请失败处理","category":"账号组织","scene":"组织成员无法加入","targetRole":"企业管理员","triggerKeywords":"邀请失败、成员、邮箱、权限、加入团队","replyTemplate":"您好，请确认成员邮箱或手机号未加入其他企业，并检查当前套餐成员上限。若成员上限不足，可先移除不再使用的账号或升级套餐。我们也可以协助您核对账号归属。","handoffRule":"跨租户账号归属问题转运营人员处理。","updatedBy":"陈客服","status":"已发布"},{"title":"套餐升级权益说明","category":"套餐资源","scene":"升级/扩容咨询","targetRole":"企业管理员","triggerKeywords":"升级、套餐、并发、成员上限、资源包","replyTemplate":"您好，套餐升级后会同步提升成员数、项目数、月积分和并发任务上限。升级前已购买的资源余额会保留，系统会按新套餐规则继续累计消耗。","handoffRule":"企业版报价或合同条款转商务跟进。","updatedBy":"周商务","status":"待审核"},{"title":"内容安全拦截说明","category":"风控合规","scene":"提示词或素材被拦截","targetRole":"企业成员","triggerKeywords":"敏感、违规、审核不通过、内容安全","replyTemplate":"您好，平台会对提示词、素材和生成结果进行内容安全校验。若出现拦截，请调整涉及暴力、色情、侵权、真实人物冒用等内容。若您认为误判，可提交项目 ID 由运营复核。","handoffRule":"客户申诉误判时转内容运营复核。","updatedBy":"内容运营","status":"待审核"},{"title":"API 调用额度说明","category":"开放接口","scene":"API 接入/额度咨询","targetRole":"技术管理员","triggerKeywords":"API、接口、密钥、额度、限流","replyTemplate":"您好，API 调用与企业后台任务共用积分余额，并受套餐并发和频控限制。请在企业后台查看 API Key、调用日志和模型消耗明细；若需要更高限流，请联系商务配置企业版额度。","handoffRule":"接口报错附 requestId 转技术值班。","updatedBy":"技术支持","status":"已发布"}],"cards":[{"title":"管理规则","value":"审核后发布 + 工单调用","items":["新增话术先进入草稿/待审核状态","发布后可在工单工作台按分类和关键词检索","话术需包含升级规则，避免客服停留在手工判断"]},{"title":"覆盖场景","value":"入驻 / 计费 / 生成 / 财务 / 风控","items":["入驻审核资料补件","模型消耗与资源流水解释","视频生成排队、失败与重试","订单发票与退款处理"]}]}', 1, CURRENT_TIMESTAMP),
('supportPerformance', '{"title":"客服绩效看板","desc":"响应时效、处理量、解决率与超时风险统计","primary":"导出绩效","workflow":["工单进入","首响统计","解决统计","SLA 复盘"],"metrics":[{"label":"平均首响","value":"11 分钟","hint":"SLA 达成 96%"},{"label":"平均解决","value":"2.6 小时","hint":"环比 -8%"},{"label":"解决率","value":"93%","hint":"近 30 天"},{"label":"满意度","value":"4.8","hint":"满分 5 分"}],"filters":["客服人员","时间范围","工单分类","优先级"],"columns":[{"prop":"agent","label":"客服","width":120},{"prop":"handled","label":"处理量","width":110},{"prop":"firstResponse","label":"首响时长","width":130},{"prop":"resolution","label":"解决率","width":110},{"prop":"risk","label":"超时风险","width":120,"tag":true}],"rows":[{"agent":"林客服","handled":"86","firstResponse":"9 分钟","resolution":"95%","risk":"低"},{"agent":"陈客服","handled":"72","firstResponse":"13 分钟","resolution":"91%","risk":"中"},{"agent":"周客服","handled":"64","firstResponse":"16 分钟","resolution":"89%","risk":"中"}],"cards":[{"title":"绩效口径","value":"处理量 / 首响 / 解决率","items":["支持按人员与团队查看","超时工单进入预警表","导出用于月度复盘"]}]}', 1, CURRENT_TIMESTAMP),
('manuals', '{"title":"使用手册管理","desc":"企业侧创作手册与运营侧处理手册统一维护、发布和复盘","primary":"新建文档","workflow":["编辑文档","版本校对","发布上线","阅读分析"],"metrics":[{"label":"文档总数","value":"8","hint":"企业侧 5 篇 / 运营侧 3 篇"},{"label":"已发布","value":"6","hint":"可在帮助中心查看"},{"label":"待发布","value":"2","hint":"运营流程补充中"},{"label":"本周阅读","value":"326","hint":"计费文档最高"}],"filters":["目录","发布状态","适用端","关键词"],"columns":[{"prop":"title","label":"文档标题","minWidth":220},{"prop":"category","label":"目录","minWidth":130,"tag":true},{"prop":"scope","label":"适用端","minWidth":110,"tag":true},{"prop":"version","label":"版本","minWidth":100},{"prop":"owner","label":"负责人","minWidth":110},{"prop":"updatedAt","label":"更新时间","minWidth":150},{"prop":"status","label":"状态","minWidth":100,"tag":true}],"rows":[{"title":"企业端：创建 AI 短剧项目","category":"创作入门","scope":"企业侧","version":"v1.0","owner":"内容运营","updatedAt":"2026-05-26 09:30","summary":"说明从新建项目、导入剧本到选择画幅和清晰度的完整流程。","content":"1. 进入项目页创建短剧项目；2. 上传 doc、docx、txt、pdf 或 md 剧本；3. 选择 Agent 模式或人工模式；4. 设置画幅、分辨率和预览风格；5. 创建任务后在项目列表查看生成进度。","status":"已发布"},{"title":"企业端：剧本生成与改写","category":"剧本生产","scope":"企业侧","version":"v1.0","owner":"内容运营","updatedAt":"2026-05-26 09:40","summary":"介绍剧本生短剧、人工模式、提示词安全和结果二次编辑。","content":"支持上传原始剧本后自动拆解剧情、角色和分镜。生成前请避免真实人物冒用、侵权情节和敏感内容。结果可进入人工模式修改分镜、台词和镜头说明。","status":"已发布"},{"title":"企业端：资产与素材管理","category":"资产管理","scope":"企业侧","version":"v1.0","owner":"产品运营","updatedAt":"2026-05-25 16:20","summary":"说明角色图、配音素材、品牌素材和项目资产的复用规则。","content":"资产可按项目沉淀并复用。建议统一命名角色、场景、Logo 和配音文件。素材上传后会进入项目资产库，视频生成时可作为输入素材参与模型调用。","status":"已发布"},{"title":"企业端：积分消耗与模型计费","category":"计费结算","scope":"企业侧","version":"v1.1","owner":"财务运营","updatedAt":"2026-05-26 10:00","summary":"解释资源流水、模型维度消耗、失败任务和发票申请。","content":"积分按实际模型调用、素材输入和输出时长计量。可在资源流水中按项目、用户、模型、日期筛选。失败任务不会按成功结果重复计费；开票需在订单支付完成后提交发票信息。","status":"已发布"},{"title":"企业端：成员与权限配置","category":"团队协作","scope":"企业侧","version":"v1.0","owner":"产品运营","updatedAt":"2026-05-24 14:10","summary":"说明 Owner、管理员、成员的权限差异和邀请限制。","content":"Owner 可管理套餐、资源和成员；管理员可管理项目和资产；成员主要负责创作任务。邀请成员前请确认套餐成员上限，跨企业账号需先解除原企业绑定。","status":"已发布"},{"title":"运营端：入驻审核处理规范","category":"运营审核","scope":"运营侧","version":"v0.9","owner":"运营主管","updatedAt":"2026-05-26 11:00","summary":"规范营业执照、法人身份、授权书、风险结论和试用开通动作。","content":"审核需检查统一社会信用代码、营业执照主体、法人姓名和经办人授权。低风险客户可开通试用包；证照不一致或授权缺失需退回补件；审核结果写入审计日志。","status":"待发布"},{"title":"运营端：订单发票与退款处理","category":"订单计费","scope":"运营侧","version":"v0.8","owner":"财务运营","updatedAt":"2026-05-25 18:30","summary":"规范线下订单、支付核验、资源入账、发票和退款流程。","content":"线下订单需上传支付凭证并核对企业名称。支付确认后资源入账；专票需校验税号、开户行和地址电话；退款需冻结对应资源额度并记录退款原因。","status":"待发布"},{"title":"运营端：预警与客服工单联动","category":"客户服务","scope":"运营侧","version":"v1.0","owner":"客服主管","updatedAt":"2026-05-24 19:00","summary":"说明资源不足、沉睡客户、超时工单和话术库调用规则。","content":"资源不足客户进入续费提醒；沉睡客户进入回访队列；超时工单同步预警表。客服处理时优先调用话术库，无法解决时按升级规则转交运营、财务或技术。","status":"已发布"}],"cards":[{"title":"发布管理","value":"版本 + 状态 + 适用端","items":["文档按企业侧/运营侧区分展示","待发布文档经校对后再上线","版本更新保留负责人和更新时间"]},{"title":"内容范围","value":"创作流程 + 运营流程","items":["企业端覆盖项目、剧本、素材、计费和团队协作","运营端覆盖入驻审核、订单发票、预警和工单联动","文档可挂载附件或封面图"]}]}', 1, CURRENT_TIMESTAMP),
('announcements', '{"title":"政策与新闻","desc":"公告、政策、计费变更与强制阅读配置","primary":"发布公告","workflow":["撰写公告","设置策略","发布通知","阅读确认"],"metrics":[{"label":"已发布","value":"36","hint":"本月 4 篇"},{"label":"定时发布","value":"3","hint":"最近 06-01"},{"label":"强制阅读","value":"2","hint":"需企业确认"}],"filters":["公告类型","发布状态","是否强制","发布时间"],"columns":[{"prop":"title","label":"标题","minWidth":240},{"prop":"type","label":"类型","width":110,"tag":true},{"prop":"publishAt","label":"发布时间","minWidth":150},{"prop":"readMode","label":"阅读要求","width":120,"tag":true},{"prop":"status","label":"状态","width":100,"tag":true}],"rows":[{"title":"视频生成计费规则更新说明","type":"政策","publishAt":"2026-05-26 10:00","readMode":"强制确认","status":"已发布"},{"title":"端午节服务保障公告","type":"新闻","publishAt":"2026-05-25 18:00","readMode":"普通阅读","status":"定时中"},{"title":"企业版套餐权益调整","type":"政策","publishAt":"2026-05-21 09:00","readMode":"强制确认","status":"已发布"}],"cards":[{"title":"发布策略","value":"立即 / 定时 / 强制确认","items":["重大政策可要求登录确认","支持分类归档","发布动作进入审计日志"]}]}', 1, CURRENT_TIMESTAMP),
('globalSettings', '{"title":"全局参数配置","desc":"预警阈值、灰度开关、积分单价与平台安全策略","primary":"保存配置","workflow":["配置编辑","风险校验","保存生效","审计留痕"],"metrics":[{"label":"预警阈值","value":"20%","hint":"资源不足触发线"},{"label":"到期提醒","value":"7 天","hint":"二次提醒 3 天"},{"label":"灰度开关","value":"3","hint":"2 个已启用"}],"filters":["配置分组","状态","维护人","关键词"],"columns":[{"prop":"key","label":"配置项","minWidth":200},{"prop":"group","label":"分组","width":120,"tag":true},{"prop":"value","label":"当前值","minWidth":140},{"prop":"owner","label":"维护人","width":110},{"prop":"status","label":"状态","width":100,"tag":true}],"rows":[{"key":"资源不足预警阈值","group":"预警","value":"20%","owner":"超级管理员","status":"启用"},{"key":"资源到期提醒天数","group":"预警","value":"7 / 3 天","owner":"超级管理员","status":"启用"},{"key":"新版计费订单灰度","group":"灰度","value":"企业版白名单","owner":"超级管理员","status":"启用"}],"cards":[{"title":"安全要求","value":"高危配置二次确认","items":["配置变更记录快照","支持灰度开关","影响资损的规则需审批"]}]}', 1, CURRENT_TIMESTAMP);

CREATE TABLE IF NOT EXISTS ai_tasks (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    episode_id BIGINT,
    storyboard_id BIGINT,
    task_type VARCHAR(64) NOT NULL,
    external_task_id VARCHAR(255),
    status VARCHAR(32) NOT NULL DEFAULT 'pending',
    input_image_key VARCHAR(512),
    prompt CLOB,
    result_video_url VARCHAR(1024),
    result_tos_key VARCHAR(512),
    error_message CLOB,
    character_image_key VARCHAR(512),
    character_image_keys CLOB,
    scene_image_key VARCHAR(512),
    prop_image_keys CLOB,
    style_image_key VARCHAR(512),
    user_prompt CLOB,
    video_duration INT,
    video_ratio VARCHAR(10),
    generate_audio BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_ai_tasks_tenant_project ON ai_tasks (tenant_id, project_id);
CREATE INDEX IF NOT EXISTS idx_ai_tasks_episode ON ai_tasks (episode_id);
CREATE INDEX IF NOT EXISTS idx_ai_tasks_external ON ai_tasks (external_task_id);
CREATE INDEX IF NOT EXISTS idx_ai_tasks_storyboard ON ai_tasks (storyboard_id);

CREATE TABLE IF NOT EXISTS team_groups (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    name VARCHAR(128) NOT NULL,
    description CLOB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS group_members (
    group_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    PRIMARY KEY (group_id, user_id)
);

CREATE TABLE IF NOT EXISTS global_assets (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    creator_user_id BIGINT NOT NULL,
    name VARCHAR(256) NOT NULL,
    asset_type VARCHAR(32) NOT NULL,
    library_type VARCHAR(16) NOT NULL DEFAULT 'personal',
    tags VARCHAR(512),
    image_tos_key VARCHAR(512),
    image_url VARCHAR(1024),
    description CLOB,
    is_favorite TINYINT NOT NULL DEFAULT 0,
    source_project_id BIGINT,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_global_assets_tenant_type ON global_assets (tenant_id, asset_type, library_type);
CREATE INDEX IF NOT EXISTS idx_global_assets_creator ON global_assets (creator_user_id);

CREATE TABLE IF NOT EXISTS graph_runs (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    goal CLOB NOT NULL,
    status VARCHAR(16) NOT NULL DEFAULT 'PENDING',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_graph_runs_project ON graph_runs (project_id);
CREATE INDEX IF NOT EXISTS idx_graph_runs_tenant_project ON graph_runs (tenant_id, project_id);

CREATE TABLE IF NOT EXISTS graph_steps (
    id BIGINT NOT NULL,
    run_id BIGINT NOT NULL,
    step_key VARCHAR(64) NOT NULL,
    step_name VARCHAR(128) NOT NULL,
    agent_type VARCHAR(16) NOT NULL,
    status VARCHAR(16) NOT NULL DEFAULT 'PENDING',
    score CHAR(1),
    score_detail CLOB,
    output CLOB,
    duration_ms BIGINT,
    started_at TIMESTAMP,
    done_at TIMESTAMP,
    seq INT NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    UNIQUE (run_id, step_key)
);

CREATE INDEX IF NOT EXISTS idx_graph_steps_run ON graph_steps (run_id);

CREATE TABLE IF NOT EXISTS script_understandings (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    asset_id BIGINT,
    understanding_json CLOB,
    evidence_hash VARCHAR(64),
    coverage_report_json CLOB,
    quality_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
    quality_issues_json CLOB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_script_understandings_tenant_project ON script_understandings (tenant_id, project_id);
CREATE INDEX IF NOT EXISTS idx_script_understandings_asset ON script_understandings (asset_id);

CREATE TABLE IF NOT EXISTS project_consistency_bibles (
    id BIGINT NOT NULL,
    tenant_id BIGINT NOT NULL,
    project_id BIGINT NOT NULL,
    bible_json CLOB,
    source_version VARCHAR(64),
    locked_fields_json CLOB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (tenant_id, project_id)
);

CREATE TABLE IF NOT EXISTS agent_run_plans (
    id BIGINT NOT NULL,
    run_id BIGINT NOT NULL,
    run_mode VARCHAR(64) NOT NULL,
    reasoning_summary CLOB,
    planned_steps_json CLOB,
    skipped_steps_json CLOB,
    step_inputs_json CLOB,
    quality_rules_json CLOB,
    model_policy_json CLOB,
    context_options_json CLOB,
    idempotency_key VARCHAR(128),
    plan_version VARCHAR(32) NOT NULL DEFAULT 'v1',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE (run_id)
);

CREATE INDEX IF NOT EXISTS idx_agent_run_plans_idempotency ON agent_run_plans (idempotency_key);

CREATE TABLE IF NOT EXISTS agent_prompt_snapshots (
    id BIGINT NOT NULL,
    run_id BIGINT NOT NULL,
    step_key VARCHAR(64) NOT NULL,
    prompt_role VARCHAR(64) NOT NULL,
    system_prompt_version VARCHAR(64),
    context_hash VARCHAR(64),
    context_summary CLOB,
    request_json CLOB,
    response_raw CLOB,
    parsed_output_json CLOB,
    validation_result_json CLOB,
    model_provider VARCHAR(64),
    model_id VARCHAR(128),
    latency_ms BIGINT,
    error_message CLOB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

CREATE INDEX IF NOT EXISTS idx_agent_prompt_snapshots_run_step ON agent_prompt_snapshots (run_id, step_key);

MERGE INTO system_settings (id, setting_key, setting_value, updated_at, updated_by) KEY(setting_key) VALUES
(2401, 'warnings.rules', '{"creditLowPercent":20,"creditCriticalPercent":10,"dormantDays":30,"expireSoonDays":7,"taskFailRatePercent":15,"ticketSlaHours":4,"invoicePendingDays":3,"auditPendingHours":2,"contentBlockTimes":3,"channels":["站内信","短信","邮件","企业微信"],"remindTimes":["09:30","16:30"],"escalationOwners":["运营一组","财务值班","技术值班","客服主管","内容运营"]}', CURRENT_TIMESTAMP, 1);

UPDATE admin_page_data
   SET payload_json = '{"title":"运营预警表","desc":"资源、任务、审核、工单、发票、内容安全与到期风险统一扫描和闭环处理","primary":"新增预警","workflow":["规则扫描","阈值命中","通知负责人","升级/关闭","复盘归档"],"metrics":[{"label":"待处理预警","value":"8","hint":"覆盖 8 类运营场景"},{"label":"严重预警","value":"2","hint":"任务失败与内容安全"},{"label":"今日新增","value":"5","hint":"按参数自动命中"},{"label":"已升级","value":"3","hint":"同步提醒负责人"}],"filters":["预警类型","风险等级","处理状态","负责人"],"columns":[{"prop":"company","label":"企业名称","minWidth":170},{"prop":"type","label":"预警类型","minWidth":140,"tag":true},{"prop":"level","label":"风险等级","minWidth":110,"tag":true},{"prop":"reason","label":"触发原因","minWidth":240},{"prop":"triggerValue","label":"触发值","minWidth":120},{"prop":"threshold","label":"触发阈值","minWidth":120},{"prop":"owner","label":"负责人","minWidth":110,"tag":true},{"prop":"channels","label":"提醒渠道","minWidth":150},{"prop":"nextAction","label":"下一步动作","minWidth":180},{"prop":"status","label":"处理状态","minWidth":110,"tag":true}],"rows":[{"id":"WARN20260527001","company":"星火互动文化","type":"资源不足","level":"高","reason":"剩余积分低于资源不足阈值，最近 7 天消耗加速","triggerValue":"剩余 12%","threshold":"<20%","owner":"财务值班","channels":"站内信、企业微信","nextAction":"推送续费包并同步商务跟进","status":"待处理"},{"id":"WARN20260527002","company":"环声传媒","type":"任务失败率","level":"严重","reason":"近 24 小时视频生成失败率超过任务健康阈值","triggerValue":"28%","threshold":">15%","owner":"技术值班","channels":"站内信、短信、企业微信","nextAction":"检查上游模型、素材格式与失败任务日志","status":"已升级"},{"id":"WARN20260527003","company":"青石影像工作室","type":"入驻审核超时","level":"中","reason":"入驻资料待处理时间超过审核 SLA，需要复核营业执照和法人材料","triggerValue":"3.6 小时","threshold":">2 小时","owner":"运营一组","channels":"企业微信","nextAction":"复核营业执照、法人身份与授权书","status":"处理中"},{"id":"WARN20260527004","company":"灵感短剧社","type":"沉睡客户","level":"中","reason":"超过沉睡客户天数未登录，近 60 天无项目产出","triggerValue":"35 天","threshold":">30 天","owner":"客服主管","channels":"邮件、企业微信","nextAction":"进入客服回访队列并发送案例模板","status":"待处理"},{"id":"WARN20260527005","company":"南风影业","type":"工单 SLA","level":"高","reason":"加急工单超过 SLA 未解决，客户反馈视频任务卡住","triggerValue":"5.2 小时","threshold":">4 小时","owner":"客服主管","channels":"短信、企业微信","nextAction":"转主管介入并补充技术排查记录","status":"已升级"},{"id":"WARN20260527006","company":"星轨传媒","type":"发票待处理","level":"中","reason":"已付款订单超过开票处理天数未归档","triggerValue":"4 天","threshold":">3 天","owner":"财务值班","channels":"站内信、企业微信","nextAction":"核验发票抬头、税号并完成开票","status":"待处理"},{"id":"WARN20260527007","company":"北辰影视","type":"内容安全","level":"严重","reason":"同租户连续触发敏感素材拦截，需暂停相关任务并复核项目内容","triggerValue":"3 次","threshold":">=3 次","owner":"内容运营","channels":"站内信、短信","nextAction":"暂停任务、复核素材并记录风控结论","status":"处理中"},{"id":"WARN20260527008","company":"云幕传媒","type":"套餐到期","level":"中","reason":"企业版套餐即将到期，需提前触达管理员","triggerValue":"5 天","threshold":"<=7 天","owner":"商务负责人","channels":"邮件、企业微信","nextAction":"发送续费提醒并确认资源余额","status":"待处理"}],"cards":[{"title":"预警场景","value":"8 类核心运营风险","items":["资源不足、套餐到期、沉睡客户进入商业化与客服闭环","任务失败率、内容安全、工单 SLA 进入技术与客服升级链路","入驻审核超时和发票待处理分别绑定运营与财务负责人"]},{"title":"提醒策略","value":"阈值 + 渠道 + 升级负责人","items":["阈值参数从 system_settings.warnings.rules 读取","提醒渠道支持站内信、短信、邮件和企业微信多选","严重预警自动纳入升级负责人待办"]},{"title":"处置闭环","value":"待处理 / 处理中 / 已升级 / 已关闭","items":["行内处理会回写状态和处理时间","新增与编辑记录保存在 admin_page_data 页面业务数据中","删除业务记录需要二次确认，避免误删"]}],"logicRules":[{"name":"资源不足预警","scope":"按租户余额与月度消耗速度判断资源风险。","formula":"剩余比例 = tenant_balances.balance / tenant_quotas.monthly_credits；低于配置阈值触发。","owner":"财务运营","editable":"可在预警参数中调整阈值","notes":"默认 20% 提醒，10% 严重。"},{"name":"任务失败率预警","scope":"按近 24 小时任务失败率识别模型或素材异常。","formula":"失败率 = 失败任务数 / 总任务数 * 100%，超过配置阈值触发。","owner":"技术值班","editable":"可调整失败率阈值","notes":"正式任务表接入后替换当前页面记录。"},{"name":"客户沉睡预警","scope":"按登录、项目更新和资源流水综合判断客户是否沉睡。","formula":"沉睡客户 = 连续 N 天无登录、无项目更新、无资源流水。","owner":"客服主管","editable":"可调整沉睡天数","notes":"默认 N=30 天。"},{"name":"SLA 与业务待办预警","scope":"覆盖入驻审核、工单处理和发票开具的待办超时。","formula":"超时时长 = 当前时间 - 待办创建时间；超过配置小时/天数触发。","owner":"运营一组 / 财务值班 / 客服主管","editable":"可调整审核、开票和工单阈值","notes":"用于把分散待办收口到统一预警表。"}]}',
       updated_at = CURRENT_TIMESTAMP
 WHERE page_key = 'warnings';

UPDATE billing_records
   SET billing_mode = 'SOFT'
 WHERE billing_mode IS NULL
    OR billing_mode = ''
    OR LOWER(billing_mode) IN ('true', 'false');

UPDATE billing_records
   SET modality = 'RECHARGE'
 WHERE modality IS NULL
   AND operation = 'recharge';

UPDATE billing_records
   SET success = TRUE
 WHERE success IS NULL
   AND (operation = 'recharge' OR modality = 'RECHARGE');

UPDATE billing_records
   SET unit_count = 1
 WHERE unit_count IS NULL;

UPDATE billing_records
   SET model_provider = 'volcengine',
       model_id = 'doubao-seed-2-0-code-preview-260215',
       model_name = '豆包 Pro 文本生成'
 WHERE model_provider = 'qwen'
    OR model_id IN ('qwen-plus', 'qwen-turbo');

UPDATE billing_records
   SET model_id = 'doubao-seedance-2-0-fast-260128',
       model_name = 'Seedance 图生视频'
 WHERE model_provider = 'volcengine'
   AND model_id = 'seedance-1-0';

UPDATE billing_records
   SET model_id = 'doubao-seedream-5-0-260128',
       model_name = 'Seedream 文生图'
 WHERE model_provider = 'volcengine'
   AND model_id = 'seedream-3-0';
