safeLoad(); $dsn = sprintf( 'mysql:host=%s;port=%s;dbname=%s;charset=%s', $_ENV['DB_HOST'] ?? '127.0.0.1', $_ENV['DB_PORT'] ?? '3306', $_ENV['DB_DATABASE'] ?? '', $_ENV['DB_CHARSET'] ?? 'utf8mb4' ); $pdo = new PDO( $dsn, $_ENV['DB_USERNAME'] ?? '', $_ENV['DB_PASSWORD'] ?? '', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); function hasTable(PDO $pdo, string $table): bool { $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?'); $stmt->execute([$table]); return (int)$stmt->fetchColumn() > 0; } function hasPermission(PDO $pdo, string $code): bool { $stmt = $pdo->prepare('SELECT COUNT(*) FROM admin_permissions WHERE code = ?'); $stmt->execute([$code]); return (int)$stmt->fetchColumn() > 0; } if (!hasTable($pdo, 'enterprise_customers')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_customers ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, customer_code VARCHAR(64) NOT NULL, customer_name VARCHAR(128) NOT NULL DEFAULT '', contact_name VARCHAR(64) NOT NULL DEFAULT '', contact_mobile VARCHAR(32) NOT NULL DEFAULT '', contact_email VARCHAR(128) NOT NULL DEFAULT '', settlement_type VARCHAR(32) NOT NULL DEFAULT 'monthly', user_id BIGINT UNSIGNED NULL DEFAULT NULL, webhook_url VARCHAR(500) NOT NULL DEFAULT '', webhook_enabled TINYINT(1) NOT NULL DEFAULT 0, status VARCHAR(32) NOT NULL DEFAULT 'enabled', remark VARCHAR(500) NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_enterprise_customers_code (customer_code), KEY idx_enterprise_customers_status (status), KEY idx_enterprise_customers_user_id (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='大客户资料' SQL); echo "CREATE_TABLE enterprise_customers\n"; } if (!hasTable($pdo, 'enterprise_customer_apps')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_customer_apps ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, customer_id BIGINT UNSIGNED NOT NULL, app_name VARCHAR(128) NOT NULL DEFAULT '', app_key VARCHAR(64) NOT NULL, app_secret_cipher TEXT NULL, secret_last4 VARCHAR(8) NOT NULL DEFAULT '', status VARCHAR(32) NOT NULL DEFAULT 'enabled', last_used_at DATETIME NULL DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_enterprise_customer_apps_key (app_key), KEY idx_enterprise_customer_apps_customer_id (customer_id), KEY idx_enterprise_customer_apps_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='大客户开放接口应用' SQL); echo "CREATE_TABLE enterprise_customer_apps\n"; } if (!hasTable($pdo, 'enterprise_api_nonces')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_api_nonces ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, app_key VARCHAR(64) NOT NULL, nonce VARCHAR(128) NOT NULL, request_timestamp BIGINT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_enterprise_api_nonces_key_nonce (app_key, nonce), KEY idx_enterprise_api_nonces_created_at (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='开放接口防重放Nonce' SQL); echo "CREATE_TABLE enterprise_api_nonces\n"; } if (!hasTable($pdo, 'enterprise_customer_order_refs')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_customer_order_refs ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, customer_id BIGINT UNSIGNED NOT NULL, external_order_no VARCHAR(128) NOT NULL, order_id BIGINT UNSIGNED NOT NULL, order_no VARCHAR(64) NOT NULL DEFAULT '', appraisal_no VARCHAR(64) NOT NULL DEFAULT '', payload_hash VARCHAR(64) NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_enterprise_customer_order_refs_external (customer_id, external_order_no), UNIQUE KEY uk_enterprise_customer_order_refs_order_id (order_id), KEY idx_enterprise_customer_order_refs_order_no (order_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='大客户外部订单映射' SQL); echo "CREATE_TABLE enterprise_customer_order_refs\n"; } if (!hasTable($pdo, 'enterprise_order_events')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_order_events ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, customer_id BIGINT UNSIGNED NOT NULL, order_id BIGINT UNSIGNED NOT NULL, external_order_no VARCHAR(128) NOT NULL DEFAULT '', event_code VARCHAR(64) NOT NULL, event_text VARCHAR(128) NOT NULL DEFAULT '', status_code VARCHAR(64) NOT NULL DEFAULT '', status_text VARCHAR(128) NOT NULL DEFAULT '', payload_json JSON NULL, occurred_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_enterprise_order_events_customer_id (customer_id), KEY idx_enterprise_order_events_order_id (order_id), KEY idx_enterprise_order_events_event_code (event_code), KEY idx_enterprise_order_events_created_at (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='大客户订单事件' SQL); echo "CREATE_TABLE enterprise_order_events\n"; } if (!hasTable($pdo, 'enterprise_webhook_deliveries')) { $pdo->exec(<<<'SQL' CREATE TABLE enterprise_webhook_deliveries ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, event_id BIGINT UNSIGNED NOT NULL, customer_id BIGINT UNSIGNED NOT NULL, webhook_url VARCHAR(500) NOT NULL DEFAULT '', app_key VARCHAR(64) NOT NULL DEFAULT '', attempt_no INT NOT NULL DEFAULT 1, delivery_status VARCHAR(32) NOT NULL DEFAULT 'pending', http_status INT NOT NULL DEFAULT 0, response_body TEXT NULL, error_message VARCHAR(500) NOT NULL DEFAULT '', is_manual TINYINT(1) NOT NULL DEFAULT 0, sent_at DATETIME NULL DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_enterprise_webhook_deliveries_event_id (event_id), KEY idx_enterprise_webhook_deliveries_customer_id (customer_id), KEY idx_enterprise_webhook_deliveries_status (delivery_status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='大客户Webhook推送记录' SQL); echo "CREATE_TABLE enterprise_webhook_deliveries\n"; } $now = date('Y-m-d H:i:s'); if (!hasPermission($pdo, 'customers.manage')) { $stmt = $pdo->prepare('INSERT INTO admin_permissions (name, code, module, action, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)'); $stmt->execute(['管理客户', 'customers.manage', 'customers', 'manage', $now, $now]); echo "ADD_PERMISSION customers.manage\n"; } $permissionId = (int)$pdo->query("SELECT id FROM admin_permissions WHERE code = 'customers.manage'")->fetchColumn(); $superRoleId = (int)$pdo->query("SELECT id FROM admin_roles WHERE code = 'super_admin'")->fetchColumn(); if ($permissionId > 0 && $superRoleId > 0) { $stmt = $pdo->prepare('SELECT COUNT(*) FROM admin_role_permissions WHERE role_id = ? AND permission_id = ?'); $stmt->execute([$superRoleId, $permissionId]); if ((int)$stmt->fetchColumn() === 0) { $insert = $pdo->prepare('INSERT INTO admin_role_permissions (role_id, permission_id, created_at) VALUES (?, ?, ?)'); $insert->execute([$superRoleId, $permissionId, $now]); echo "ADD_SUPER_ADMIN_PERMISSION customers.manage\n"; } } echo "SCHEMA_UPGRADE_OK\n";