<?php
try {
    require_once __DIR__ . '/../MPHX/common.php';
    require_once __DIR__ . '/../MPHX/UpgradeManager.php';
} catch (Exception $e) {
    header('Content-Type: application/json; charset=UTF-8');
    exit(json_encode(['code' => 500, 'message' => '加载失败: ' . $e->getMessage()]));
}

header('Content-Type: application/json; charset=UTF-8');

$egn = isset($_POST['egn']) ? $_POST['egn'] : (isset($_GET['egn']) ? $_GET['egn'] : '');

// 格式化字节大小函数
function formatBytes($bytes, $precision = 2) {
    $units = array('B', 'KB', 'MB', 'GB', 'TB');
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= pow(1024, $pow);
    return round($bytes, $precision) . ' ' . $units[$pow];
}

function admin_get_table_columns($DB, $table) {
    static $cache = array();
    if (isset($cache[$table])) {
        return $cache[$table];
    }
    $columns = array();
    $table_escaped = $DB->escape($table);
    $res = $DB->query("SHOW COLUMNS FROM `{$table_escaped}`");
    if ($res) {
        while ($row = $DB->fetch($res)) {
            if (!empty($row['Field'])) {
                $columns[] = $row['Field'];
            }
        }
    }
    $cache[$table] = $columns;
    return $columns;
}

function admin_build_insert_sql($table, $data, $columns) {
    $fields = array();
    $values = array();
    foreach ($data as $key => $value) {
        if (in_array($key, $columns)) {
            $fields[] = "`{$key}`";
            $values[] = "'" . daddslashes($value) . "'";
        }
    }
    if (empty($fields)) {
        return '';
    }
    return "INSERT INTO `{$table}` (" . implode(',', $fields) . ") VALUES (" . implode(',', $values) . ")";
}

function admin_delete_zj_record($DB, $id) {
    $id = intval($id);
    if ($id <= 0) {
        return array('success' => false, 'msg' => '参数错误');
    }
    $id_escaped = $DB->escape($id);
    $zj = $DB->get_row("SELECT * FROM `zj` WHERE `id`='{$id_escaped}'");
    if (!$zj) {
        return array('success' => false, 'msg' => '记录不存在');
    }
    $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$zj['btid']}'");
    if ($bt) {
        $bt_api = new bt_api();
        $protocol = $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];

        $primary_domain = 'a116.vip';
        $full_domain = $zj['user'] . '.' . $primary_domain;

        $result = $bt_api->delsite($zj['webid'], $full_domain);

        if ($result && isset($result['status']) && $result['status'] === true) {
            $id_escaped = $DB->escape($id);
        $DB->query("DELETE FROM `zj` WHERE `id`='{$id_escaped}'");
            logjl(is_admin_login(), '删除主机', '删除主机: ' . $zj['user'] . ', webid: ' . $zj['webid'] . ', domain: ' . $full_domain, true);
            return array('success' => true, 'msg' => '删除成功');
        }

        $error_msg = isset($result['msg']) ? $result['msg'] : '未知错误';
        
        // 如果宝塔返回网站不存在，视为删除成功
        $not_exists_keywords = array('不存在', 'not exist', '找不到', '没有找到', '已被删除');
        $is_not_exists = false;
        foreach ($not_exists_keywords as $keyword) {
            if (stripos($error_msg, $keyword) !== false) {
                $is_not_exists = true;
                break;
            }
        }
        
        if ($is_not_exists) {
            // 网站已在宝塔删除，直接删除本地记录
            $id_escaped = $DB->escape($id);
        $DB->query("DELETE FROM `zj` WHERE `id`='{$id_escaped}'");
            logjl(is_admin_login(), '删除主机', '删除主机(宝塔已删): ' . $zj['user'] . ', webid: ' . $zj['webid'] . ', domain: ' . $full_domain, true);
            return array('success' => true, 'msg' => '删除成功');
        }
        
        return array('success' => false, 'msg' => '删除失败: ' . $error_msg);
    }

    $id_escaped = $DB->escape($id);
        $DB->query("DELETE FROM `zj` WHERE `id`='{$id_escaped}'");
    return array('success' => true, 'msg' => '删除成功（本地记录）');
}

switch ($egn) {
    case 'login':
        if (isset($_GET['logout']) || isset($_POST['logout'])) {
            logjl(is_admin_login(), '后台登出', '退出登录', true);
            setcookie("admin_token", "", time() - 604800);
            unset($_SESSION['admin_user']);
            unset($_SESSION['admin_login_time']);
            // 清除邮箱验证状态
            unset($_SESSION['admin_email_verified']);
            unset($_SESSION['admin_verify_code']);
            unset($_SESSION['admin_verify_time']);
            session_destroy();
            header('Location: /admin/login.php');
            exit;
        }
        
        if (isset($_POST['user']) && isset($_POST['pass'])) {
            $user = daddslashes($_POST['user']);
            $pass = daddslashes($_POST['pass']);
            $code = daddslashes($_POST['code']);
            
            if ($conf['yzm'] == 'true' && $code != $_SESSION['authcode']) {
                unset($_SESSION['authcode']);
                exit(json_encode(array('code' => '验证码错误')));
            } elseif ($user == $conf['user'] && md5($pass) == $conf['pwd']) {
                unset($_SESSION['authcode']);
                // 清除之前的邮箱验证状态，确保每次登录都需要重新验证
                unset($_SESSION['admin_email_verified']);
                unset($_SESSION['admin_verify_code']);
                unset($_SESSION['admin_verify_time']);
                global $password_hash;
                $session = md5($user . $conf['pwd'] . $password_hash);
                $token = authcode("{$user}\t{$session}", 'ENCODE', SYS_KEY);
                setcookie("admin_token", $token, time() + 604800);
                $_SESSION['admin_user'] = $user;
                logjl($user, '后台登录', '登录成功', true);
                exit(json_encode(array('code' => '登陆成功')));
            } else {
                unset($_SESSION['authcode']);
                logjl($user, '后台登录', '登录失败:用户名或密码错误', true);
                exit(json_encode(array('code' => '用户名或密码错误')));
            }
        }
        break;
        
    case 'setwz':
        $gg = daddslashes($_POST['gg']);
        $qqh = daddslashes($_POST['qqh']);
        $yzm = isset($_POST['yzm']) ? 'true' : 'false';
        $zjyxbd = isset($_POST['zjyxbd']) ? 'true' : 'false';
        
        $gg_escaped = $DB->escape($gg);
        $qqh_escaped = $DB->escape($qqh);
        $yzm_escaped = $DB->escape($yzm);
        $zjyxbd_escaped = $DB->escape($zjyxbd);
        $DB->query("UPDATE `config` SET `gg`='{$gg_escaped}',`qqh`='{$qqh_escaped}',`yzm`='{$yzm_escaped}',`zjyxbd`='{$zjyxbd_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '网站设置', '修改网站设置', true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'setapi':
        $api = daddslashes($_POST['api']);
        $apiqk = isset($_POST['apiqk']) ? 'true' : 'false';
        $hxu = daddslashes($_POST['hxu']);
        $hxi = daddslashes($_POST['hxi']);
        $hxo = daddslashes($_POST['hxo']);
        
        $api_escaped = $DB->escape($api);
        $apiqk_escaped = $DB->escape($apiqk);
        $hxu_escaped = $DB->escape($hxu);
        $hxi_escaped = $DB->escape($hxi);
        $hxo_escaped = $DB->escape($hxo);
        $DB->query("UPDATE `config` SET `api`='{$api_escaped}',`apiqk`='{$apiqk_escaped}',`hxu`='{$hxu_escaped}',`hxi`='{$hxi_escaped}',`hxo`='{$hxo_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), 'API设置', '修改API设置', true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'setkzmb':
        $name = daddslashes($_POST['name']);
        $hxw = daddslashes($_POST['hxw']);
        $hxp = daddslashes($_POST['hxp']);
        $yzme = isset($_POST['yzme']) ? 'true' : 'false';
        $kzmbqk = isset($_POST['kzmbqk']) ? 'true' : 'false';
        $login_email_verify = isset($_POST['login_email_verify']) ? 'true' : 'false';
        
        if (isset($_FILES['logo']) && $_FILES['logo']['error'] == 0) {
            $ext = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION);
            $filename = 'logo_' . time() . '.' . $ext;
            
            // 确保目录存在且可写
            $upload_dir = '../imsetes';
            if (!@is_dir($upload_dir)) {
                @mkdir($upload_dir, 0755, true);
            }
            
            if (!@is_writable($upload_dir)) {
                // 如果不可写，尝试使用系统临时目录
                $upload_dir = sys_get_temp_dir();
                $filename = 'bt_logo_' . $filename;
            }
            
            $target_file = rtrim($upload_dir, '/') . '/' . $filename;
            if (@move_uploaded_file($_FILES['logo']['tmp_name'], $target_file)) {
                $filename_escaped = $DB->escape($filename);
                $DB->query("UPDATE `config` SET `auther`='{$filename_escaped}' WHERE `id`=1");
            }
        }
        
        $name_escaped = $DB->escape($name);
        $hxw_escaped = $DB->escape($hxw);
        $hxp_escaped = $DB->escape($hxp);
        $yzme_escaped = $DB->escape($yzme);
        $kzmbqk_escaped = $DB->escape($kzmbqk);
        $login_email_verify_escaped = $DB->escape($login_email_verify);
        $DB->query("UPDATE `config` SET `name`='{$name_escaped}',`hxw`='{$hxw_escaped}',`hxp`='{$hxp_escaped}',`yzme`='{$yzme_escaped}',`kzmbqk`='{$kzmbqk_escaped}',`login_email_verify`='{$login_email_verify_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '控制面板设置', '修改控制面板设置', true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'settheme':
        $theme = daddslashes($_POST['theme']);
        
        $template_path = ROOT . 'templates/' . $theme . '/config.json';
        if (!file_exists($template_path)) {
            exit(json_encode(array('code' => '模板不存在')));
        }
        
        $theme_escaped = $DB->escape($theme);
        $DB->query("UPDATE `config` SET `theme`='{$theme_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '主题模板', '切换模板为: ' . $theme, true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'setzf':
        $hxe = daddslashes($_POST['hxe']);
        $hxr = daddslashes($_POST['hxr']);
        $hxt = daddslashes($_POST['hxt']);
        $pay_alipay = isset($_POST['pay_alipay']) ? 'true' : 'false';
        $pay_wechat = isset($_POST['pay_wechat']) ? 'true' : 'false';

        $hxe_escaped = $DB->escape($hxe);
        $hxr_escaped = $DB->escape($hxr);
        $hxt_escaped = $DB->escape($hxt);
        $pay_alipay_escaped = $DB->escape($pay_alipay);
        $pay_wechat_escaped = $DB->escape($pay_wechat);
        $DB->query("UPDATE `config` SET `hxe`='{$hxe_escaped}',`hxr`='{$hxr_escaped}',`hxt`='{$hxt_escaped}',`pay_alipay`='{$pay_alipay_escaped}',`pay_wechat`='{$pay_wechat_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '支付设置', '修改支付设置', true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'setadmin_dir':
        $admin_dir = daddslashes($_POST['admin_dir']);
        
        // 验证目录名称
        if(empty($admin_dir)) {
            exit(json_encode(array('code' => 400, 'message' => '目录名称不能为空')));
        }
        
        if(!preg_match('/^[a-zA-Z0-9_-]+$/', $admin_dir)) {
            exit(json_encode(array('code' => 400, 'message' => '目录名称只能包含字母、数字、下划线和横线')));
        }
        
        // 检查是否是系统保留目录
        $reserved_dirs = array('user', 'static', 'MPHX', 'install', 'api', 'vendor');
        if(in_array($admin_dir, $reserved_dirs)) {
            exit(json_encode(array('code' => 400, 'message' => '该目录名称已被系统保留，请选择其他名称')));
        }
        
        $old_dir = isset($conf['admin_dir']) ? $conf['admin_dir'] : 'admin';
        
        // 如果目录名称没有变化
        if($admin_dir == $old_dir) {
            exit(json_encode(array('code' => 200, 'message' => '目录名称未变化')));
        }
        
        // 检查新目录是否已存在
        if(file_exists(ROOT . $admin_dir) && is_dir(ROOT . $admin_dir)) {
            exit(json_encode(array('code' => 400, 'message' => '该目录已存在，请选择其他名称')));
        }
        
        // 检查原目录是否存在
        if(!file_exists(ROOT . $old_dir) || !is_dir(ROOT . $old_dir)) {
            exit(json_encode(array('code' => 400, 'message' => '原后台目录不存在')));
        }
        
        // 重命名目录
        if(!rename(ROOT . $old_dir, ROOT . $admin_dir)) {
            exit(json_encode(array('code' => 500, 'message' => '目录重命名失败，请检查文件权限')));
        }
        
        // 更新数据库配置
        $admin_dir_escaped = $DB->escape($admin_dir);
        $DB->query("UPDATE `config` SET `admin_dir`='{$admin_dir_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '后台目录设置', '修改后台目录从 ' . $old_dir . ' 到 ' . $admin_dir, true);
        
        exit(json_encode(array('code' => 200, 'message' => '修改成功，请使用新地址登录')));
        break;
        
    case 'gl':
        $olduser = daddslashes($_POST['olduser']);
        $oldpass = daddslashes($_POST['oldpass']);
        $newuser = daddslashes($_POST['newuser']);
        $newpass = daddslashes($_POST['newpass']);
        
        if ($olduser != $conf['user'] || md5($oldpass) != $conf['pwd']) {
            exit(json_encode(array('code' => '原用户名或密码错误')));
        }
        
        $newuser_escaped = $DB->escape($newuser);
        $DB->query("UPDATE `config` SET `user`='{$newuser_escaped}',`pwd`='" . md5($newpass) . "' WHERE `id`=1");
        logjl(is_admin_login(), '管理设置', '修改管理员账号密码', true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'setadmin_email_verify':
        $admin_email = daddslashes($_POST['admin_email']);
        $admin_email_verify = daddslashes($_POST['admin_email_verify']);
        
        // 验证邮箱格式
        if(!empty($admin_email) && !filter_var($admin_email, FILTER_VALIDATE_EMAIL)) {
            exit(json_encode(array('code' => '邮箱格式不正确')));
        }
        
        // 如果开启验证，必须填写邮箱
        if($admin_email_verify == 'true' && empty($admin_email)) {
            exit(json_encode(array('code' => '开启邮箱验证前请先填写管理员邮箱')));
        }
        
        // 检查字段是否存在，不存在则添加
        $columns = $DB->query("DESCRIBE `config`");
        $has_admin_email = false;
        $has_admin_email_verify = false;
        while ($col = $DB->fetch($columns)) {
            if ($col['Field'] == 'admin_email') {
                $has_admin_email = true;
            }
            if ($col['Field'] == 'admin_email_verify') {
                $has_admin_email_verify = true;
            }
        }
        if (!$has_admin_email) {
            $DB->query("ALTER TABLE `config` ADD COLUMN `admin_email` varchar(255) DEFAULT NULL");
        }
        if (!$has_admin_email_verify) {
            $DB->query("ALTER TABLE `config` ADD COLUMN `admin_email_verify` varchar(10) DEFAULT 'false'");
        }
        
        $admin_email_escaped = $DB->escape($admin_email);
        $admin_email_verify_escaped = $DB->escape($admin_email_verify);
        $DB->query("UPDATE `config` SET `admin_email`='{$admin_email_escaped}',`admin_email_verify`='{$admin_email_verify_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '邮箱验证设置', '修改后台邮箱验证设置: ' . ($admin_email_verify == 'true' ? '开启' : '关闭'), true);
        exit(json_encode(array('code' => '修改成功')));
        break;
        
    case 'verify_admin_email':
        $admin_email = daddslashes($_POST['admin_email']);
        
        // 验证邮箱格式
        if(empty($admin_email) || !filter_var($admin_email, FILTER_VALIDATE_EMAIL)) {
            exit(json_encode(array('code' => 'error', 'message' => '邮箱格式不正确')));
        }
        
        // 检查邮箱配置是否完整
        if(empty($conf['mailhost']) || empty($conf['mailuser']) || empty($conf['mailpassword']) || empty($conf['mailport'])) {
            exit(json_encode(array('code' => 'error', 'message' => '请先配置SMTP邮箱信息（系统配置 -> 邮箱设置）')));
        }
        
        // 发送测试邮件
        $subject = '邮箱验证测试 - ' . $conf['name'];
        $content = "<h3>邮箱验证测试</h3>
        <p>这是一封测试邮件，用于验证您的管理员邮箱配置是否正确。</p>
        <p>如果您收到此邮件，说明邮箱配置正确，可以开启后台访问邮箱验证功能。</p>
        <p>发送时间：" . date('Y-m-d H:i:s') . "</p>";
        
        $result = sendEmail($admin_email, $subject, $content);
        
        if ($result === true) {
            exit(json_encode(array('code' => 'success', 'message' => '验证邮件已发送，请查收并确认邮箱地址正确')));
        } else {
            $error_msg = is_array($result) && isset($result['error']) ? $result['error'] : '邮件发送失败';
            exit(json_encode(array('code' => 'error', 'message' => '邮件发送失败：' . $error_msg)));
        }
        break;
        
    case 'addbt':
        $btmc = daddslashes($_POST['btmc']);
        $ip = daddslashes($_POST['ip']);
        $dk = daddslashes($_POST['dk']);
        $key = daddslashes($_POST['key']);
        $ftp = daddslashes($_POST['ftp']);
        $ymsm = daddslashes($_POST['ymsm']);
        $bzbh = daddslashes($_POST['bzbh']);
        $czzt = daddslashes($_POST['czzt']);
        $aqfw = isset($_POST['aqfw']) ? 'true' : 'false';
        $jkkg = isset($_POST['jkkg']) ? 'true' : 'false';
        
        // 检查btmc字段是否存在，不存在则添加
        $columns = $DB->query("DESCRIBE `bt`");
        $has_btmc = false;
        while ($col = $DB->fetch($columns)) {
            if ($col['Field'] == 'btmc') {
                $has_btmc = true;
                break;
            }
        }
        if (!$has_btmc) {
            $DB->query("ALTER TABLE `bt` ADD COLUMN `btmc` varchar(255) DEFAULT '' AFTER `id`");
        }
        
        // 生成对接密钥
        $qmk = md5(time() . rand(1000, 9999));
        $ktmy = md5($key . $qmk);
        
        $btmc_escaped = $DB->escape($btmc);
        $ip_escaped = $DB->escape($ip);
        $dk_escaped = $DB->escape($dk);
        $key_escaped = $DB->escape($key);
        $ftp_escaped = $DB->escape($ftp);
        $ymsm_escaped = $DB->escape($ymsm);
        $bzbh_escaped = $DB->escape($bzbh);
        $czzt_escaped = $DB->escape($czzt);
        $aqfw_escaped = $DB->escape($aqfw);
        $jkkg_escaped = $DB->escape($jkkg);
        $ktmy_escaped = $DB->escape($ktmy);
        $qmk_escaped = $DB->escape($qmk);
        $DB->query("INSERT INTO `bt` (`btmc`,`ip`,`dk`,`key`,`ftp`,`ymsm`,`bzbh`,`czzt`,`aqfw`,`jkkg`,`ktmy`,`qmk`) VALUES ('{$btmc_escaped}','{$ip_escaped}','{$dk_escaped}','{$key_escaped}','{$ftp_escaped}','{$ymsm_escaped}','{$bzbh_escaped}','{$czzt_escaped}','{$aqfw_escaped}','{$jkkg_escaped}','{$ktmy_escaped}','{$qmk_escaped}')");
        logjl(is_admin_login(), '添加宝塔', '添加宝塔服务器: ' . $btmc . ' (' . $ip . ')', true);
        exit(json_encode(array('code' => '添加成功')));
        break;
        
    case 'check_conn':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 'error', 'msg' => '请先登录')));
        }
        
        $ip = daddslashes($_POST['ip']);
        $port = daddslashes($_POST['port']);
        $key = daddslashes($_POST['key']);
        $aqfw = isset($_POST['aqfw']) ? daddslashes($_POST['aqfw']) : 'false';
        
        if (empty($ip) || empty($port) || empty($key)) {
            exit(json_encode(array('code' => 'error', 'msg' => '参数错误')));
        }
        
        try {
            // 根据aqfw参数决定使用的协议
            $protocol = $aqfw == 'true' ? 'https' : 'http';
            $url = $protocol . '://' . $ip . ':' . $port . '/system?action=GetSystemTotal';
            $now_time = time();
            $data = array(
                'request_token' => md5($now_time . '' . md5($key)),
                'request_time' => $now_time
            );
            
            // 使用curl请求
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
            if ($protocol == 'https') {
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            }
            curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 增加超时时间到10秒
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 增加连接超时时间到5秒
            $result = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            curl_close($ch);
            
            // 检查结果
            if ($http_code == 200 && !$error && !empty($result)) {
                // 连接成功
                exit(json_encode(array('code' => 'success', 'msg' => '连通')));
            } else {
                // 连接失败
                exit(json_encode(array('code' => 'error', 'msg' => '连接失败: ' . $error)));
            }
        } catch (Exception $e) {
            // 捕获异常
            exit(json_encode(array('code' => 'error', 'msg' => '连接异常: ' . $e->getMessage())));
        }
        break;
        
    case 'edit_bt':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        $id = intval($_POST['id']);
        $btmc = daddslashes($_POST['btmc']);
        $ip = daddslashes($_POST['ip']);
        $port = daddslashes($_POST['port']);
        $key = daddslashes($_POST['key']);
        $ftp = daddslashes($_POST['ftp']);
        $bzbh = daddslashes($_POST['bzbh']);
        $status = daddslashes($_POST['status']);
        $os = daddslashes($_POST['os']);
        $aqfw = isset($_POST['aqfw']) ? daddslashes($_POST['aqfw']) : 'false';
        
        if (empty($id) || empty($btmc) || empty($ip) || empty($port) || empty($key) || empty($bzbh) || empty($os)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        
        $id_escaped = $DB->escape($id);
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$id_escaped}'");
        if (!$bt) {
            exit(json_encode(array('code' => '宝塔服务器不存在')));
        }
        
        // 如果密钥改变了，重新生成调用密钥
        if ($bt['key'] != $key) {
            $qmk = md5(time() . rand(1000, 9999));
            $ktmy = md5($key . $qmk);
            $btmc_escaped = $DB->escape($btmc);
        $ip_escaped = $DB->escape($ip);
        $port_escaped = $DB->escape($port);
        $key_escaped = $DB->escape($key);
        $ftp_escaped = $DB->escape($ftp);
        $bzbh_escaped = $DB->escape($bzbh);
        $status_escaped = $DB->escape($status);
        $os_escaped = $DB->escape($os);
        $aqfw_escaped = $DB->escape($aqfw);
        $ktmy_escaped = $DB->escape($ktmy);
        $qmk_escaped = $DB->escape($qmk);
        $id_escaped = $DB->escape($id);
        $DB->query("UPDATE `bt` SET `btmc`='{$btmc_escaped}', `ip`='{$ip_escaped}', `dk`='{$port_escaped}', `key`='{$key_escaped}', `ftp`='{$ftp_escaped}', `bzbh`='{$bzbh_escaped}', `jkkg`='{$status_escaped}', `czzt`='{$os_escaped}', `aqfw`='{$aqfw_escaped}', `ktmy`='{$ktmy_escaped}', `qmk`='{$qmk_escaped}' WHERE `id`='{$id_escaped}'");
        } else {
            $btmc_escaped = $DB->escape($btmc);
            $ip_escaped = $DB->escape($ip);
            $port_escaped = $DB->escape($port);
            $key_escaped = $DB->escape($key);
            $ftp_escaped = $DB->escape($ftp);
            $bzbh_escaped = $DB->escape($bzbh);
            $status_escaped = $DB->escape($status);
            $os_escaped = $DB->escape($os);
            $aqfw_escaped = $DB->escape($aqfw);
            $id_escaped = $DB->escape($id);
            $DB->query("UPDATE `bt` SET `btmc`='{$btmc_escaped}', `ip`='{$ip_escaped}', `dk`='{$port_escaped}', `key`='{$key_escaped}', `ftp`='{$ftp_escaped}', `bzbh`='{$bzbh_escaped}', `jkkg`='{$status_escaped}', `czzt`='{$os_escaped}', `aqfw`='{$aqfw_escaped}' WHERE `id`='{$id_escaped}'");
        }
        logjl(is_admin_login(), '编辑宝塔', '编辑宝塔服务器: ' . $btmc . ' (' . $ip . ')', true);
        exit(json_encode(array('code' => '编辑成功')));
        break;
        
    case 'btsc':
        $id = intval($_POST['id']);
        $id_escaped = $DB->escape($id);
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$id_escaped}'");
        if ($bt) {
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `zj` WHERE `btid`='{$id_escaped}'");
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `bt` WHERE `id`='{$id_escaped}'");
            logjl(is_admin_login(), '删除宝塔', '删除宝塔服务器: ' . $bt['ip'], true);
            exit(json_encode(array('code' => '删除成功')));
        }
        exit(json_encode(array('code' => '删除失败')));
        break;
        
    case 'addzj':
        $btid = intval($_POST['btid']);
        $cplx = daddslashes($_POST['cplx']);
        $user = daddslashes($_POST['user']);
        $pass = daddslashes($_POST['pass']);
        
        // 网页空间和数据库空间直接以MB存储
        $wypj = floatval($_POST['wypj']);
        $sypj = floatval($_POST['sypj']);
        
        // 流量以GB存储
        $llxz = floatval($_POST['llxz']);
        $llxz_unit = $_POST['llxz_unit'] ?? 'GB';
        if ($llxz_unit === 'MB') {
            $llxz = $llxz / 1024;
        }
        
        $dqsj = daddslashes($_POST['dqsj']);
        $yms = intval($_POST['yms']);
        
        // 验证参数
        if (empty($btid) || empty($user) || empty($pass)) {
            exit(json_encode(array('code' => '参数错误: 宝塔ID、用户名和密码不能为空')));
        }
        
        $btid_escaped = $DB->escape($btid);
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$btid_escaped}'");
        if (!$bt) {
            exit(json_encode(array('code' => '宝塔服务器不存在')));
        }
        
        try {
            $bt_api = new bt_api();
            // 使用数据库中存储的实际IP地址连接宝塔API
            $protocol = $bt['aqfw'] == 'true' ? 'https' : 'http';
            $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
            $bt_api->BT_KEY = $bt['key'];
            
            // 测试连接
            $test_result = $bt_api->GetPanelStatus();
            if (!$test_result || (isset($test_result['status']) && $test_result['status'] === false)) {
                $error_msg = isset($test_result['msg']) ? $test_result['msg'] : '连接失败';
                exit(json_encode(array('code' => '连接宝塔服务器失败: ' . $error_msg)));
            }
        } catch (Exception $e) {
            exit(json_encode(array('code' => '宝塔服务器连接异常: ' . $e->getMessage())));
        }
        
        // 检查配置路径
        if (empty($conf['hxi']) || empty($conf['hxo'])) {
            exit(json_encode(array('code' => '系统配置错误: 网站根目录路径未设置')));
        }
        
        $path = $bt['czzt'] == 'Linux' ? $conf['hxi'] . '/' . $user : $conf['hxo'] . '/' . $user;
        // 生成二级域名用于开通
        $primary_domain = 'a116.vip'; // 默认一级域名
        $subdomain = $user . '.' . $primary_domain;
        
        // 检查并创建网站根目录
        $parent_dir = dirname($path);
        $check_dir = $bt_api->GetHostDirectory($parent_dir);
        if (!$check_dir || !isset($check_dir['DIR'])) {
            $bt_api->CreateDirectory($parent_dir);
        }
        
        // 使用正确的PHP版本格式
        // 根据宝塔API的要求，PHP版本应该使用纯数字格式如"74"
        $php_version = '74'; // 使用PHP 7.4
        
        try {
            $result = $bt_api->webkt($user, $pass, $subdomain, 'PHP', 'true', 'true', $php_version, $path);
        } catch (Exception $e) {
            exit(json_encode(array('code' => '宝塔API调用异常: ' . $e->getMessage())));
        }
        
        // 检查响应是否有效
        if (!$result) {
            exit(json_encode(array('code' => '宝塔API无响应，请检查宝塔服务器状态')));
        }
        
        if (isset($result['siteStatus']) && $result['siteStatus'] === true) {
            $webid = $result['siteId'];
            $ftpuser = isset($result['ftpUser']) ? $result['ftpUser'] : $user;
            $ftppass = isset($result['ftpPass']) ? $result['ftpPass'] : $pass;
            $sqluser = isset($result['databaseUser']) ? $result['databaseUser'] : $user;
            $sqlpass = isset($result['databasePass']) ? $result['databasePass'] : $pass;
            $sqldb = isset($result['databaseName']) ? $result['databaseName'] : $user;
            
            // 宝塔API添加网站成功
            
            // 从宝塔获取FTP地址
            $ftp_address = $bt['ftp'] ? $bt['ftp'] : '';
            
            $user_escaped = $DB->escape($user);
            $pass_escaped = $DB->escape($pass);
            $btid_escaped = $DB->escape($btid);
            $webid_escaped = $DB->escape($webid);
            $cplx_escaped = $DB->escape($cplx);
            $wypj_escaped = $DB->escape($wypj);
            $sypj_escaped = $DB->escape($sypj);
            $llxz_escaped = $DB->escape($llxz);
            $dqsj_escaped = $DB->escape($dqsj);
            $yms_escaped = $DB->escape($yms);
            $ftpuser_escaped = $DB->escape($ftpuser);
            $ftppass_escaped = $DB->escape($ftppass);
            $sqluser_escaped = $DB->escape($sqluser);
            $sqlpass_escaped = $DB->escape($sqlpass);
            $sqldb_escaped = $DB->escape($sqldb);
            $ftp_address_escaped = $DB->escape($ftp_address);
            $DB->query("INSERT INTO `zj` (`user`,`pass`,`btid`,`webid`,`cplx`,`wypj`,`sypj`,`llxz`,`dqsj`,`yms`,`ftpuser`,`ftppass`,`sqluser`,`sqlpass`,`sqldb`,`email`,`zt`,`ftp`) VALUES ('{$user_escaped}','{$pass_escaped}','{$btid_escaped}','{$webid_escaped}','{$cplx_escaped}','{$wypj_escaped}','{$sypj_escaped}','{$llxz_escaped}','{$dqsj_escaped}','{$yms_escaped}','{$ftpuser_escaped}','{$ftppass_escaped}','{$sqluser_escaped}','{$sqlpass_escaped}','{$sqldb_escaped}','','正常','{$ftp_address_escaped}')");
            logjl(is_admin_login(), '添加主机', '添加主机: ' . $user, true);
            exit(json_encode(array('code' => '添加成功')));
        }
        
        // 处理失败情况
        $error_msg = '添加失败';
        if (isset($result['msg'])) {
            $error_msg = $result['msg'];
        } elseif (isset($result['error'])) {
            $error_msg = $result['error'];
        } elseif (isset($result['siteStatus']) && $result['siteStatus'] === false) {
            $error_msg = '网站创建失败';
        } elseif (isset($result['ftpStatus']) && $result['ftpStatus'] === false) {
            $error_msg = 'FTP创建失败';
        } elseif (isset($result['databaseStatus']) && $result['databaseStatus'] === false) {
            $error_msg = '数据库创建失败';
        }
        // 使用json_encode确保JSON格式正确
        exit(json_encode(array('code' => '添加失败: ' . $error_msg)));
        break;
        
    case 'zjsc':
        $id = intval($_POST['id']);
        $result = admin_delete_zj_record($DB, $id);
        if ($result['success']) {
            exit(json_encode(array('code' => $result['msg'])));
        }
        exit(json_encode(array('code' => $result['msg'])));
        break;
        
    case 'edit_zj':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        $id = intval($_POST['id']);
        $user = daddslashes($_POST['user']);
        $pass = daddslashes($_POST['pass']);
        $cplx = daddslashes($_POST['cplx']);
        $wypj = intval($_POST['wypj']);
        $sypj = intval($_POST['sypj']);
        $llxz = intval($_POST['llxz']);
        $dqsj = daddslashes($_POST['dqsj']);
        $yms = intval($_POST['yms']);
        $btid = intval($_POST['btid']);
        
        if (empty($id) || empty($user) || empty($pass) || empty($btid)) {
            exit(json_encode(array('code' => '参数错误: ID、用户名、密码和宝塔ID不能为空')));
        }
        
        $id_escaped = $DB->escape($id);
    $zj = $DB->get_row("SELECT * FROM `zj` WHERE `id`='{$id_escaped}'");
        if (!$zj) {
            exit(json_encode(array('code' => '主机不存在')));
        }
        
        $btid_escaped = $DB->escape($btid);
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$btid_escaped}'");
        if (!$bt) {
            exit(json_encode(array('code' => '宝塔服务器不存在')));
        }
        
        // 更新主机信息
        $user_escaped = $DB->escape($user);
        $pass_escaped = $DB->escape($pass);
        $btid_escaped = $DB->escape($btid);
        $cplx_escaped = $DB->escape($cplx);
        $wypj_escaped = $DB->escape($wypj);
        $sypj_escaped = $DB->escape($sypj);
        $llxz_escaped = $DB->escape($llxz);
        $dqsj_escaped = $DB->escape($dqsj);
        $yms_escaped = $DB->escape($yms);
        $id_escaped = $DB->escape($id);
        $DB->query("UPDATE `zj` SET `user`='{$user_escaped}', `pass`='{$pass_escaped}', `btid`='{$btid_escaped}', `cplx`='{$cplx_escaped}', `wypj`='{$wypj_escaped}', `sypj`='{$sypj_escaped}', `llxz`='{$llxz_escaped}', `dqsj`='{$dqsj_escaped}', `yms`='{$yms_escaped}' WHERE `id`='{$id_escaped}'");
        logjl(is_admin_login(), '编辑主机', '编辑主机: ' . $user, true);
        exit(json_encode(array('code' => '编辑成功')));
        break;
        
    case 'addym':
        $ym = daddslashes($_POST['ym']);
        $jg = daddslashes($_POST['jg']);
        $js = daddslashes($_POST['js']);
        $btid = intval($_POST['btid']);
        
        $ym_escaped = $DB->escape($ym);
        $jg_escaped = $DB->escape($jg);
        $js_escaped = $DB->escape($js);
        $btid_escaped = $DB->escape($btid);
        $DB->query("INSERT INTO `ym` (`ym`,`jg`,`js`,`btid`) VALUES ('{$ym_escaped}','{$jg_escaped}','{$js_escaped}','{$btid_escaped}')");
        logjl(is_admin_login(), '添加域名', '添加域名: ' . $ym, true);
        exit(json_encode(array('code' => '添加成功')));
        break;
        
    case 'ymsc':
        $id = intval($_POST['id']);
        $id_escaped = $DB->escape($id);
        $ym = $DB->get_row("SELECT * FROM `ym` WHERE `id`='{$id_escaped}'");
        if ($ym) {
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `ym` WHERE `id`='{$id_escaped}'");
            logjl(is_admin_login(), '删除域名', '删除域名: ' . $ym['ym'], true);
            exit(json_encode(array('code' => '删除成功')));
        }
        exit(json_encode(array('code' => '删除失败')));
        break;
        
    case 'setmail':
        $mailhost = $DB->escape($_POST['mailhost']);
        $mailuser = $DB->escape($_POST['mailuser']);
        $mailpassword = isset($_POST['mailpassword']) ? trim($_POST['mailpassword']) : '';
        $mailport = $DB->escape($_POST['mailport']);
        
        // 如果密码为空，保持原密码不变
        if (empty($mailpassword)) {
            $mailhost_escaped = $DB->escape($mailhost);
            $mailuser_escaped = $DB->escape($mailuser);
            $mailport_escaped = $DB->escape($mailport);
            $DB->query("UPDATE `config` SET `mailhost`='{$mailhost_escaped}',`mailuser`='{$mailuser_escaped}',`mailport`='{$mailport_escaped}' WHERE `id`=1");
        } else {
            $mailpassword = $DB->escape($mailpassword);
            $mailhost_escaped = $DB->escape($mailhost);
            $mailuser_escaped = $DB->escape($mailuser);
            $mailpassword_escaped = $DB->escape($mailpassword);
            $mailport_escaped = $DB->escape($mailport);
            $DB->query("UPDATE `config` SET `mailhost`='{$mailhost_escaped}',`mailuser`='{$mailuser_escaped}',`mailpassword`='{$mailpassword_escaped}',`mailport`='{$mailport_escaped}' WHERE `id`=1");
        }
        logjl(is_admin_login(), '邮箱设置', '修改邮箱设置', true);
        exit('{"code":"修改成功"}');
        break;
        
    case 'sendtestmail':
        $to = daddslashes($_POST['to']);
        $subject = daddslashes($_POST['subject']);
        $message = daddslashes($_POST['message']);
        
        $result = sendEmail($to, $subject, $message);
        if ($result === true) {
            logjl(is_admin_login(), '发送测试邮件', '发送到: ' . $to, true);
            exit('{"code":"邮件发送成功"}');
        } else {
            $error_msg = isset($result['error']) ? $result['error'] : '邮件发送失败，请检查邮箱配置';
            exit('{"code":"' . $error_msg . '"}');
        }
        break;
        
    case 'send_admin_verify_code':
        // 检查是否开启了邮箱验证
        if (!isset($conf['admin_email_verify']) || $conf['admin_email_verify'] !== 'true') {
            exit(json_encode(array('code' => 'error', 'message' => '邮箱验证未开启')));
        }
        
        // 检查是否设置了管理员邮箱
        if (empty($conf['admin_email'])) {
            exit(json_encode(array('code' => 'error', 'message' => '管理员邮箱未设置')));
        }
        
        // 生成6位验证码
        $code = rand(100000, 999999);
        
        // 存储验证码到session
        $_SESSION['admin_verify_code'] = $code;
        $_SESSION['admin_verify_time'] = time();
        
        // 发送邮件
        $subject = '后台登录验证 - ' . $conf['name'];
        $content = "<h3>后台登录安全验证</h3>
        <p>您的验证码是：<strong style='font-size:24px;color:#188038;'>{$code}</strong></p>
        <p>验证码有效期为10分钟，请勿泄露给他人。</p>
        <p>如非本人操作，请立即修改管理员密码。</p>";
        
        $result = sendEmail($conf['admin_email'], $subject, $content);
        
        if ($result === true) {
            exit(json_encode(array('code' => 'success', 'message' => '验证码已发送')));
        } else {
            $error_msg = is_array($result) && isset($result['error']) ? $result['error'] : '邮件发送失败';
            exit(json_encode(array('code' => 'error', 'message' => $error_msg)));
        }
        break;
        
    case 'verify_admin_code':
        $code = isset($_POST['code']) ? trim($_POST['code']) : '';
        
        if (empty($code)) {
            exit(json_encode(array('code' => 'error', 'message' => '请输入验证码')));
        }
        
        // 检查验证码是否存在
        if (!isset($_SESSION['admin_verify_code']) || !isset($_SESSION['admin_verify_time'])) {
            exit(json_encode(array('code' => 'error', 'message' => '验证码已过期，请重新获取')));
        }
        
        // 检查验证码是否过期（10分钟）
        if (time() - $_SESSION['admin_verify_time'] > 600) {
            unset($_SESSION['admin_verify_code']);
            unset($_SESSION['admin_verify_time']);
            exit(json_encode(array('code' => 'error', 'message' => '验证码已过期，请重新获取')));
        }
        
        // 验证验证码
        if ($_SESSION['admin_verify_code'] != $code) {
            exit(json_encode(array('code' => 'error', 'message' => '验证码错误')));
        }
        
        // 验证成功，标记已验证
        $_SESSION['admin_email_verified'] = true;
        
        // 清除验证码
        unset($_SESSION['admin_verify_code']);
        unset($_SESSION['admin_verify_time']);
        
        logjl('admin', '邮箱验证', '后台邮箱验证成功', true);
        exit(json_encode(array('code' => 'success', 'message' => '验证成功')));
        break;
        
    case 'testmailconfig':
        $mailhost = isset($_POST['mailhost']) ? trim($_POST['mailhost']) : '';
        $mailuser = isset($_POST['mailuser']) ? trim($_POST['mailuser']) : '';
        $mailpassword_input = isset($_POST['mailpassword']) ? trim($_POST['mailpassword']) : '';
        $mailport = isset($_POST['mailport']) ? trim($_POST['mailport']) : '';
        $test_email = isset($_POST['test_email']) ? trim($_POST['test_email']) : '';
        
        // 如果表单中的密码为空，使用数据库中的密码
        if (empty($mailpassword_input)) {
            $mailpassword = $conf['mailpassword'];
        } else {
            $mailpassword = $mailpassword_input;
        }
        
        // 检查必填项
        if (empty($mailhost) || empty($mailuser) || empty($mailpassword) || empty($mailport)) {
            exit('{"code":"请填写完整的邮箱配置信息"}');
        }
        
        // 创建自定义配置用于测试
        $test_config = array(
            'mailhost' => $mailhost,
            'mailuser' => $mailuser,
            'mailpassword' => $mailpassword,
            'mailport' => $mailport,
            'name' => $conf['name']
        );
        
        $subject = '邮箱配置测试 - ' . $conf['name'];
        $message = '<h3>邮箱配置测试</h3>';
        $message .= '<p>这是一封测试邮件，用于验证您的邮箱配置是否正确。</p>';
        $message .= '<p><strong>配置信息：</strong></p>';
        $message .= '<ul>';
        $message .= '<li>邮箱服务器：' . htmlspecialchars($mailhost) . '</li>';
        $message .= '<li>邮箱账号：' . htmlspecialchars($mailuser) . '</li>';
        $message .= '<li>邮箱端口：' . htmlspecialchars($mailport) . '</li>';
        $message .= '</ul>';
        $message .= '<p>如果您收到此邮件，说明您的邮箱配置正确！</p>';
        $message .= '<p style="color: #888; font-size: 12px;">发送时间：' . date('Y-m-d H:i:s') . '</p>';
        
        $result = sendEmail($test_email, $subject, $message, $test_config);
        if ($result === true) {
            logjl(is_admin_login(), '邮箱配置测试', '测试邮件发送到: ' . $test_email, true);
            exit('{"code":"测试邮件发送成功，请检查收件箱"}');
        } else {
            $error_msg = isset($result['error']) ? $result['error'] : '测试邮件发送失败，请检查邮箱配置是否正确';
            exit('{"code":"' . $error_msg . '"}');
        }
        break;
        
    case 'setjk':
        $ymjkkg = isset($_POST['ymjkkg']) ? 'true' : 'false';
        $wjjkkg = isset($_POST['wjjkkg']) ? 'true' : 'false';
        $mtyxfskg = isset($_POST['mtyxfskg']) ? 'true' : 'false';
        $ymjktsyz = daddslashes($_POST['ymjktsyz']);
        $wjjktsyz = daddslashes($_POST['wjjktsyz']);
        
        $ymjkkg_escaped = $DB->escape($ymjkkg);
        $wjjkkg_escaped = $DB->escape($wjjkkg);
        $mtyxfskg_escaped = $DB->escape($mtyxfskg);
        $ymjktsyz_escaped = $DB->escape($ymjktsyz);
        $wjjktsyz_escaped = $DB->escape($wjjktsyz);
        $DB->query("UPDATE `config` SET `ymjkkg`='{$ymjkkg_escaped}',`wjjkkg`='{$wjjkkg_escaped}',`mtyxfskg`='{$mtyxfskg_escaped}',`ymjktsyz`='{$ymjktsyz_escaped}',`wjjktsyz`='{$wjjktsyz_escaped}' WHERE `id`=1");
        logjl(is_admin_login(), '监控设置', '修改监控设置', true);
        exit('{"code":"修改成功"}');
        break;
        
    case 'save_server_parse_domain':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        $parse_domains = isset($_POST['parse_domain']) ? $_POST['parse_domain'] : array();
        $success_count = 0;
        
        foreach ($parse_domains as $bt_id => $domain) {
            $bt_id = intval($bt_id);
            $domain = daddslashes(trim($domain));
            
            // 验证域名格式
            if (!empty($domain) && !preg_match('/^[a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)+$/', $domain)) {
                continue;
            }
            
            // 检查是否已存在记录
            $bt_id_escaped = intval($bt_id);
            $exists = $DB->get_row("SELECT id FROM `server_parse_domain` WHERE `bt_id`={$bt_id_escaped}");
            if ($exists) {
                if (empty($domain)) {
                    // 如果域名为空，删除记录
                    $bt_id_escaped = intval($bt_id);
                    $DB->query("DELETE FROM `server_parse_domain` WHERE `bt_id`={$bt_id_escaped}");
                } else {
                    // 更新记录
                    $domain_escaped = $DB->escape($domain);
                    $bt_id_escaped = intval($bt_id);
                    $DB->query("UPDATE `server_parse_domain` SET `parse_domain`='{$domain_escaped}' WHERE `bt_id`={$bt_id_escaped}");
                }
            } else if (!empty($domain)) {
                // 插入新记录
                $bt_id_escaped = intval($bt_id);
                $domain_escaped = $DB->escape($domain);
                $DB->query("INSERT INTO `server_parse_domain` (`bt_id`, `parse_domain`) VALUES ({$bt_id_escaped}, '{$domain_escaped}')");
            }
            $success_count++;
        }
        
        logjl(is_admin_login(), '解析域名设置', '修改服务器解析域名设置', true);
        exit(json_encode(array('code' => '保存成功')));
        break;
        
    case 'checkupdate':
        // 检查登录状态
        $admin_user = is_admin_login();
        if (!$admin_user) {
            exit(json_encode(array('code' => 401, 'message' => '请先登录')));
        }
        
        require_once __DIR__ . '/../MPHX/AuthManager.php';
        logjl($admin_user, '检查更新', '检查系统更新', true);
        
        try {
            $authManager = new AuthManager($DB);
            
            // 获取token
            $token_result = $authManager->getToken();
            
            if ($token_result['code'] != 200) {
                exit(json_encode(array(
                    'code' => 500,
                    'message' => '授权验证失败: ' . ($token_result['message'] ?? '未知错误')
                )));
            }
            
            $token = $token_result['data']['token'];
            
            // 发送心跳获取版本信息
            $heartbeat = $authManager->heartbeat($token);
            
            if ($heartbeat['code'] != 200) {
                exit(json_encode(array(
                    'code' => 500,
                    'message' => '获取版本信息失败: ' . ($heartbeat['message'] ?? '未知错误')
                )));
            }
            
            // 获取版本信息（直接定义，避免加载 update.php 输出 HTML）
            $current_version = '1.1.2'; // 当前版本号（去掉 v 前缀）
            $remote_version = '';
            $has_update = false;
            $update_info = array();
            
            if (isset($heartbeat['data']['cloud']['latest_version']['version'])) {
                $latest_version = $heartbeat['data']['cloud']['latest_version'];
                $remote_version = $latest_version['version'];
                $has_update = version_compare($remote_version, $current_version, '>');
                
                $update_info = array(
                    'version' => $remote_version,
                    'size' => $latest_version['file_size'] ? formatBytes($latest_version['file_size']) : '未知',
                    'changelog' => $latest_version['changelog'] ?? '暂无更新日志',
                    'download_url' => $latest_version['download_url'] ?? ''
                );
            }
            
            exit(json_encode(array(
                'code' => 200,
                'has_update' => $has_update,
                'current_version' => 'v' . $current_version,
                'remote_version' => $remote_version ? 'v' . $remote_version : '',
                'update_size' => $update_info['size'] ?? '未知',
                'update_time' => date('Y-m-d'),
                'update_log' => $update_info['changelog'] ?? '暂无更新日志',
                'download_url' => $update_info['download_url'] ?? '',
                'message' => $has_update ? '发现新版本' : '当前已是最新版本'
            )));
            
        } catch (Exception $e) {
            exit(json_encode(array(
                'code' => 500,
                'message' => '检查更新失败: ' . $e->getMessage(),
                'error_file' => $e->getFile(),
                'error_line' => $e->getLine(),
                'error_trace' => $e->getTraceAsString()
            )));
        }
        break;

    case 'startupdate':
        $download_url = isset($_POST['download_url']) ? $_POST['download_url'] : '';
        $is_repair = isset($_POST['repair']) && $_POST['repair'] == 1;

        // 调试日志已禁用
        /*
        */
        
        if(empty($download_url)) {
            exit(json_encode(array('code' => 400, 'message' => '下载地址不能为空')));
        }
        
        logjl(is_admin_login(), $is_repair ? '系统修复' : '系统更新', '开始' . ($is_repair ? '系统修复' : '系统更新'), true);
        
        try {
            // 获取当前后台目录
            $admin_dir = isset($conf['admin_dir']) ? $conf['admin_dir'] : 'admin';

            
            // 创建临时目录
            $temp_dir = ROOT . 'temp_update/';
            if(!is_dir($temp_dir)) {
                mkdir($temp_dir, 0755, true);
            }
            
            // 下载更新包
            $update_zip = $temp_dir . 'update.zip';
            $ch = curl_init($download_url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  // 跟随重定向
            curl_setopt($ch, CURLOPT_MAXREDIRS, 5);          // 最多 5 次重定向
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 300);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
            $zip_content = curl_exec($ch);
            $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
            $total_size = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
            $curl_error = curl_error($ch);
            curl_close($ch);
            
            if($curl_error) {
                exit(json_encode(array('code' => 500, 'message' => 'CURL 错误：' . $curl_error)));
            }
            
            if($http_code != 200) {
                exit(json_encode(array('code' => 500, 'message' => '下载更新包失败 (HTTP: ' . $http_code . ', Content-Type: ' . $content_type . ')')));
            }
            
            if(empty($zip_content)) {
                exit(json_encode(array('code' => 500, 'message' => '下载的更新包文件异常，大小：0 字节 (URL: ' . $download_url . ')')));
            }
            
            // 检查 Content-Type 是否为 ZIP
            if(strpos($content_type, 'zip') === false && strpos($content_type, 'octet-stream') === false) {
                exit(json_encode(array('code' => 500, 'message' => '下载的文件类型不正确 (Content-Type: ' . $content_type . '). 可能下载了 HTML 页面而不是 ZIP 文件')));
            }
            
            file_put_contents($update_zip, $zip_content);
            
            // 验证下载的文件大小
            $downloaded_size = filesize($update_zip);
            if($downloaded_size < 1024) { // 小于 1KB 认为异常
                @unlink($update_zip);
                exit(json_encode(array('code' => 500, 'message' => '下载的更新包文件异常，大小：' . $downloaded_size . ' 字节')));
            }
            
            // 解压更新包
            $zip = new ZipArchive();
            $zip_result = $zip->open($update_zip);
            if($zip_result !== true) {
                $error_msg = '无法打开更新包 (错误码：' . $zip_result . ')';
                // ZipArchive 错误码常量
                $zip_errors = [
                    ZipArchive::ER_NOENT => ' - 文件不存在',
                    ZipArchive::ER_NOZIP => ' - 不是有效的 ZIP 文件',
                    19 => ' - ZIP 格式错误', // ZipArchive::ER_FORMAT (19) - PHP 7.4 之前不存在此常量
                    ZipArchive::ER_MEMORY => ' - 内存不足',
                    ZipArchive::ER_INCONS => ' - ZIP 归档不一致',
                    ZipArchive::ER_NOENT => ' - 文件不存在'
                ];
                if(isset($zip_errors[$zip_result])) {
                    $error_msg .= $zip_errors[$zip_result];
                }
                @unlink($update_zip);
                exit(json_encode(array('code' => 500, 'message' => $error_msg)));
            }
            
            $extract_dir = $temp_dir . 'extract/';
            if(!is_dir($extract_dir)) {
                mkdir($extract_dir, 0755, true);
            }
            
            $zip->extractTo($extract_dir);
            $zip->close();
            
            // 查找解压后的目录（通常是项目名称）
            $extracted_dirs = glob($extract_dir . '*', GLOB_ONLYDIR);
            if(empty($extracted_dirs)) {
                exit(json_encode(array('code' => 500, 'message' => '更新包结构不正确')));
            }
            
            $source_dir = $extracted_dirs[0] . '/';
            
            // 复制文件到目标位置，同时处理 admin 目录（只替换文件，不删除原有文件）
            $copy_log_file = $log_file; // 将日志文件路径传递给闭包
            $copy_update_files = function($source, $dest, $admin_dir) use (&$copy_update_files, $copy_log_file) {
                if(is_dir($source)) {
                    if(!is_dir($dest)) {
                        mkdir($dest, 0755, true);
                    }
                    
                    $files = scandir($source);
                    foreach($files as $file) {
                        if($file == '.' || $file == '..') continue;
                        
                        $src_file = $source . $file;
                        
                        // 如果是 admin 目录，复制到当前配置的后台目录
                        if($file == 'admin' && is_dir($src_file)) {
                            $dest_file = $dest . $admin_dir . '/';
                        } else {
                            $dest_file = $dest . $file;
                        }
                        
                        if(is_dir($src_file)) {
                            $copy_update_files($src_file . '/', $dest_file . '/', $admin_dir);
                        } else {
                            // 只复制文件，保留原有文件
                            if(copy($src_file, $dest_file)) {
                                // 复制成功
                            } else {
                                // 复制失败
                            }
                        }
                    }
                }
            };
            
            $copy_update_files($source_dir, ROOT, $admin_dir);
            
            // 执行数据库更新
            $sql_file = $source_dir . 'update.sql';
            if(file_exists($sql_file)) {
                $sql_content = file_get_contents($sql_file);
                
                // 处理SQL文件，支持多条语句
                $sql_content = str_replace("\r\n", "\n", $sql_content);
                $sql_content = str_replace("\r", "\n", $sql_content);
                
                // 分割SQL语句
                $sql_statements = explode(";\n", $sql_content);
                $sql_errors = array();
                
                foreach($sql_statements as $sql) {
                    $sql = trim($sql);
                    if(empty($sql) || substr($sql, 0, 2) == '--') continue;
                    
                    if(!$DB->query($sql)) {
                        $sql_errors[] = 'SQL错误: ' . substr($sql, 0, 100) . '...';
                    }
                }
                
                if(!empty($sql_errors)) {
                    logjl(is_admin_login(), '系统更新-数据库', '部分SQL执行失败: ' . implode('; ', $sql_errors), false);
                } else {
                    logjl(is_admin_login(), '系统更新-数据库', '数据库更新成功', true);
                }
            }
            
            // 清理临时文件（只删除文件，保留目录结构）
            function clean_temp_files($dir) {
                if(is_dir($dir)) {
                    $files = scandir($dir);
                    foreach($files as $file) {
                        if($file == '.' || $file == '..') continue;
                        $path = $dir . '/' . $file;
                        if(is_dir($path)) {
                            clean_temp_files($path);
                            // 尝试删除空目录
                            @rmdir($path);
                        } else {
                            unlink($path);
                        }
                    }
                }
            }
            
            clean_temp_files($temp_dir);
            
            logjl(is_admin_login(), $is_repair ? '系统修复' : '系统更新', $is_repair ? '系统修复完成' : '系统更新完成', true);
            exit(json_encode(array('code' => 200, 'message' => $is_repair ? '修复成功' : '更新成功')));
            
        } catch(Exception $e) {
            exit(json_encode(array('code' => 500, 'message' => ($is_repair ? '修复' : '更新') . '失败: ' . $e->getMessage())));
        }
        break;
        
    case 'bssc':
        $id = intval($_POST['id']);
        $id_escaped = $DB->escape($id);
        $bs = $DB->get_row("SELECT * FROM `bs` WHERE `id`='{$id_escaped}'");
        if ($bs) {
            // 删除数据库记录
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `bs` WHERE `id`='{$id_escaped}'");
            
            // 删除程序源码文件
            if (!empty($bs['wj'])) {
                $wj_path = $bs['wj'];
                // 如果wj包含programs/前缀，去掉前缀获取实际文件名
                if (strpos($wj_path, 'programs/') === 0) {
                    $wj_filename = substr($wj_path, 9);
                } else {
                    $wj_filename = $wj_path;
                }
                $file_path = '../uploads/programs/' . $wj_filename;
                if (file_exists($file_path)) {
                    unlink($file_path);
                }
            }
            
            // 删除封面图片 (tb字段 - 旧版)
            if (!empty($bs['tb'])) {
                $tb_path = '../uploads/' . $bs['tb'];
                if (file_exists($tb_path)) {
                    unlink($tb_path);
                }
            }
            
            // 删除封面图片 (cover字段 - 新版)
            if (!empty($bs['cover'])) {
                $cover_path = '../uploads/' . $bs['cover'];
                if (file_exists($cover_path)) {
                    unlink($cover_path);
                }
            }
            
            // 删除详情图片
            if (!empty($bs['images'])) {
                $images = json_decode($bs['images'], true);
                if (is_array($images)) {
                    foreach ($images as $img) {
                        $img_path = '../uploads/' . $img;
                        if (file_exists($img_path)) {
                            unlink($img_path);
                        }
                    }
                }
            }
            
            logjl(is_admin_login(), '删除程序', '删除程序: ' . $bs['name'], true);
            exit('{"code":"删除成功"}');
        }
        exit('{"code":"删除失败"}');
        break;
        
    case 'addcx':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        try {
            $name = daddslashes($_POST['name']);
            $jg = daddslashes($_POST['jg']);
            $js = daddslashes($_POST['js']);
            $type = daddslashes($_POST['type']);
            $version = daddslashes($_POST['version']);
            $webkj = intval($_POST['webkj'] ?? 0);
            $sqlkj = intval($_POST['sqlkj'] ?? 0);
            $php_version = daddslashes($_POST['php_version'] ?? '');
            $php_ext = daddslashes($_POST['php_ext'] ?? '');
            $alerts = daddslashes($_POST['alerts'] ?? '');
            $status = isset($_POST['status']) ? 1 : 0;
            
            
            // 处理表单字段配置 - 支持数组格式 form_fields[0][name]
            $form_fields = array();
            if (isset($_POST['form_fields']) && is_array($_POST['form_fields'])) {
                foreach ($_POST['form_fields'] as $field) {
                    if (!empty($field['name'])) {
                        $form_fields[] = array(
                            'name' => $field['name'],
                            'type' => $field['type'] ?? 'text',
                            'label' => $field['label'] ?? $field['name'],
                            'placeholder' => $field['placeholder'] ?? '',
                            'default' => $field['default'] ?? '',
                            'required' => isset($field['required']) ? 1 : 0,
                            'options' => $field['options'] ?? ''
                        );
                    }
                }
            }
            $form_fields_json = json_encode($form_fields, JSON_UNESCAPED_UNICODE);
            
            // 处理安装操作配置 - 支持数组格式 install_ops[0][type]
            $install_ops = array();
            if (isset($_POST['install_ops']) && is_array($_POST['install_ops'])) {
                foreach ($_POST['install_ops'] as $op) {
                    if (!empty($op['type'])) {
                        $install_ops[] = $op;
                    }
                }
            }
            $install_ops_json = json_encode($install_ops, JSON_UNESCAPED_UNICODE);

            // 处理封面图片
            $cover_filename = '';
            if (isset($_FILES['cover']) && $_FILES['cover']['error'] == 0) {
                $cover_ext = strtolower(pathinfo($_FILES['cover']['name'], PATHINFO_EXTENSION));
                $allowed_cover = array('png', 'jpg', 'jpeg', 'gif');
                if (!in_array($cover_ext, $allowed_cover)) {
                    exit('{"code":"封面格式不支持"}');
                }
                $cover_filename = 'program_cover_' . time() . '.' . $cover_ext;
                $upload_dir = '../uploads';
                if (!@is_dir($upload_dir)) {
                    @mkdir($upload_dir, 0755, true);
                }
                if (!@is_writable($upload_dir)) {
                    $upload_dir = sys_get_temp_dir();
                    $cover_filename = 'bt_upload_' . $cover_filename;
                }
                $target_file = rtrim($upload_dir, '/') . '/' . $cover_filename;
                if (!@move_uploaded_file($_FILES['cover']['tmp_name'], $target_file)) {
                    exit('{"code":"封面保存失败"}');
                }
            }

            // 处理程序源码文件
            $source_file = '';
            if (isset($_FILES['source_file']) && $_FILES['source_file']['error'] == 0) {
                $ext = strtolower(pathinfo($_FILES['source_file']['name'], PATHINFO_EXTENSION));
                $allowed_ext = array('zip', 'tar', 'gz');
                if (!in_array($ext, $allowed_ext)) {
                    exit('{"code":"源码文件格式不支持，仅支持 .zip, .tar, .tar.gz"}');
                }
                $source_filename = 'program_source_' . time() . '.' . $ext;
                $upload_dir = '../uploads/programs';
                if (!@is_dir($upload_dir)) {
                    @mkdir($upload_dir, 0755, true);
                }
                $target_file = rtrim($upload_dir, '/') . '/' . $source_filename;
                if (!@move_uploaded_file($_FILES['source_file']['tmp_name'], $target_file)) {
                    exit('{"code":"源码文件保存失败"}');
                }
                $source_file = $source_filename;
            }

            $bs_columns = admin_get_table_columns($DB, 'bs');
            
            $data = array(
                'name' => $name,
                'jg' => $jg,
                'js' => $js,
                'type' => $type,
                'version' => $version,
                'webkj' => $webkj,
                'sqlkj' => $sqlkj,
                'php_version' => $php_version,
                'php_ext' => $php_ext,
                'alerts' => $alerts,
                'status' => $status,
                'form_fields' => $form_fields_json,
                'install_ops' => $install_ops_json
            );
            if (!empty($cover_filename)) {
                if (in_array('tb', $bs_columns)) {
                    $data['tb'] = $cover_filename;
                } elseif (in_array('cover', $bs_columns)) {
                    $data['cover'] = $cover_filename;
                }
            }
            if (!empty($source_file)) {
                // 使用 wj 字段存储源码文件（数据库表中没有 source_file 字段）
                if (in_array('wj', $bs_columns)) {
                    $data['wj'] = $source_file;
                }
            }
            
            $sql = admin_build_insert_sql('bs', $data, $bs_columns);
            
            if (empty($sql)) {
                exit('{"code":"表结构不匹配"}');
            }
            
            $result = $DB->query($sql);
            if (!$result) {
                $db_error = $DB->error();
                exit('{"code":"数据库错误: ' . $db_error . '"}');
            }
            
            logjl(is_admin_login(), '添加程序', '添加程序: ' . $name, true);
            exit('{"code":"添加成功"}');
        } catch (Exception $e) {
            exit('{"code":"服务器错误: ' . $e->getMessage() . '"}');
        }
        break;

    case 'edit_cx':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        $id = intval($_POST['id'] ?? 0);
        if ($id <= 0) {
            exit('{"code":"参数错误：缺少程序ID"}');
        }
        
        $name = daddslashes($_POST['name']);
        $jg = daddslashes($_POST['jg']);
        $js = daddslashes($_POST['js']);
        $type = daddslashes($_POST['type']);
        $version = daddslashes($_POST['version']);
        $webkj = intval($_POST['webkj'] ?? 0);
        $sqlkj = intval($_POST['sqlkj'] ?? 0);
        $php_version = daddslashes($_POST['php_version'] ?? '');
        $php_ext = daddslashes($_POST['php_ext'] ?? '');
        $alerts = daddslashes($_POST['alerts'] ?? '');
        $status = isset($_POST['status']) ? 1 : 0;
        
        // 检查程序是否存在
        $id_escaped = $DB->escape($id);
        $program = $DB->get_row("SELECT * FROM `bs` WHERE `id`='{$id_escaped}'");
        if (!$program) {
            exit('{"code":"程序不存在"}');
        }
        
        // 处理表单字段配置 - 支持数组格式 form_fields[0][name]
        $form_fields = array();
        if (isset($_POST['form_fields']) && is_array($_POST['form_fields'])) {
            foreach ($_POST['form_fields'] as $field) {
                if (!empty($field['name'])) {
                    $form_fields[] = array(
                        'name' => $field['name'],
                        'type' => $field['type'] ?? 'text',
                        'label' => $field['label'] ?? $field['name'],
                        'placeholder' => $field['placeholder'] ?? '',
                        'default' => $field['default'] ?? '',
                        'required' => isset($field['required']) ? 1 : 0,
                        'options' => $field['options'] ?? ''
                    );
                }
            }
        }
        $form_fields_json = json_encode($form_fields, JSON_UNESCAPED_UNICODE);
        
        // 处理安装操作配置 - 支持数组格式 install_ops[0][type]
        $install_ops = array();
        if (isset($_POST['install_ops']) && is_array($_POST['install_ops'])) {
            foreach ($_POST['install_ops'] as $op) {
                if (!empty($op['type'])) {
                    $install_ops[] = $op;
                }
            }
        }
        $install_ops_json = json_encode($install_ops, JSON_UNESCAPED_UNICODE);

        // 处理封面图片
        $cover_filename = '';
        if (isset($_FILES['cover']) && $_FILES['cover']['error'] == 0) {
            $cover_ext = strtolower(pathinfo($_FILES['cover']['name'], PATHINFO_EXTENSION));
            $allowed_cover = array('png', 'jpg', 'jpeg', 'gif');
            if (!in_array($cover_ext, $allowed_cover)) {
                exit('{"code":"封面格式不支持"}');
            }
            $cover_filename = 'program_cover_' . time() . '.' . $cover_ext;
            $upload_dir = '../uploads';
            if (!@is_dir($upload_dir)) {
                @mkdir($upload_dir, 0755, true);
            }
            if (!@is_writable($upload_dir)) {
                $upload_dir = sys_get_temp_dir();
                $cover_filename = 'bt_upload_' . $cover_filename;
            }
            $target_file = rtrim($upload_dir, '/') . '/' . $cover_filename;
            if (!@move_uploaded_file($_FILES['cover']['tmp_name'], $target_file)) {
                exit('{"code":"封面保存失败"}');
            }
        }

        // 处理程序源码文件
        $source_file = '';
        if (isset($_FILES['source_file']) && $_FILES['source_file']['error'] == 0) {
            $ext = strtolower(pathinfo($_FILES['source_file']['name'], PATHINFO_EXTENSION));
            $allowed_ext = array('zip', 'tar', 'gz');
            if (!in_array($ext, $allowed_ext)) {
                exit('{"code":"源码文件格式不支持，仅支持 .zip, .tar, .tar.gz"}');
            }
            $source_filename = 'program_source_' . time() . '.' . $ext;
            $upload_dir = '../uploads/programs';
            if (!@is_dir($upload_dir)) {
                @mkdir($upload_dir, 0755, true);
            }
            $target_file = rtrim($upload_dir, '/') . '/' . $source_filename;
            if (!@move_uploaded_file($_FILES['source_file']['tmp_name'], $target_file)) {
                exit('{"code":"源码文件保存失败"}');
            }
            // 保存时添加programs/前缀
            $source_file = 'programs/' . $source_filename;
        }

        // 检查是否删除源码文件
        $existing_source = isset($_POST['existing_source_file']) ? $_POST['existing_source_file'] : '';
        if (empty($existing_source) && !empty($program['wj'])) {
            // 标记删除源码文件
            $delete_source = true;
            // 删除物理文件
            $old_wj = $program['wj'];
            if (strpos($old_wj, 'programs/') === 0) {
                $old_file_path = '../uploads/' . $old_wj;
            } else {
                $old_file_path = '../uploads/programs/' . $old_wj;
            }
            if (file_exists($old_file_path)) {
                @unlink($old_file_path);
            }
        }
        
        // 构建更新数据
        $data = array(
            'name' => $name,
            'jg' => $jg,
            'js' => $js,
            'type' => $type,
            'version' => $version,
            'webkj' => $webkj,
            'sqlkj' => $sqlkj,
            'php_version' => $php_version,
            'php_ext' => $php_ext,
            'alerts' => $alerts,
            'status' => $status,
            'form_fields' => $form_fields_json,
            'install_ops' => $install_ops_json
        );
        
        if (!empty($cover_filename)) {
            $data['tb'] = $cover_filename;
        }
        if (!empty($source_file)) {
            $data['wj'] = $source_file;
        } elseif (isset($delete_source) && $delete_source) {
            $data['wj'] = '';
        }
        
        // 处理展示图片
        $existing_images = isset($_POST['existing_images']) ? json_decode($_POST['existing_images'], true) : array();
        if (!is_array($existing_images)) $existing_images = array();
        
        // 处理新上传的图片
        $new_images = $existing_images;
        if (isset($_FILES['new_images']) && is_array($_FILES['new_images']['name'])) {
            $upload_dir = '../uploads';
            if (!@is_dir($upload_dir)) {
                @mkdir($upload_dir, 0755, true);
            }
            
            $file_count = count($_FILES['new_images']['name']);
            for ($i = 0; $i < $file_count; $i++) {
                if ($_FILES['new_images']['error'][$i] == 0) {
                    $img_ext = strtolower(pathinfo($_FILES['new_images']['name'][$i], PATHINFO_EXTENSION));
                    $allowed_img = array('png', 'jpg', 'jpeg', 'gif');
                    if (in_array($img_ext, $allowed_img)) {
                        $img_filename = 'program_img_' . time() . '_' . $i . '.' . $img_ext;
                        $target_file = rtrim($upload_dir, '/') . '/' . $img_filename;
                        if (@move_uploaded_file($_FILES['new_images']['tmp_name'][$i], $target_file)) {
                            $new_images[] = $img_filename;
                        }
                    }
                }
            }
        }
        
        // 限制最多9张图片
        if (count($new_images) > 9) {
            $new_images = array_slice($new_images, 0, 9);
        }
        $data['images'] = json_encode($new_images, JSON_UNESCAPED_UNICODE);
        
        // 构建UPDATE SQL
        $sets = array();
        foreach ($data as $key => $value) {
            $sets[] = "`{$key}`='" . daddslashes($value) . "'";
        }
        $sql = "UPDATE `bs` SET " . implode(',', $sets) . " WHERE `id`='{$id}'";
        
        $result = $DB->query($sql);
        if ($result) {
            logjl(is_admin_login(), '编辑程序', '编辑程序: ' . $name . ' (ID:' . $id . ')', true);
            exit('{"code":"更新成功"}');
        } else {
            exit('{"code":"更新失败: ' . $DB->error() . '"}');
        }
        break;

    case 'adddr':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $name = daddslashes($_POST['name']);
        $jg = daddslashes($_POST['jg']);
        $js = daddslashes($_POST['js']);
        $type = daddslashes($_POST['type']);
        $version = daddslashes($_POST['version']);

        if (!isset($_FILES['file']) || $_FILES['file']['error'] != 0) {
            exit('{"code":"文件上传失败"}');
        }

        $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
        $allowed_ext = array('zip', 'rar', 'tar', 'gz');
        if (!in_array($ext, $allowed_ext)) {
            exit('{"code":"程序包格式不支持"}');
        }
        if (!empty($_FILES['file']['size']) && $_FILES['file']['size'] > 200 * 1024 * 1024) {
            exit('{"code":"程序包过大"}');
        }

        $filename = 'program_' . time() . '.' . $ext;
        $upload_dir = '../uploads/programs';
        if (!@is_dir($upload_dir)) {
            @mkdir($upload_dir, 0755, true);
        }
        if (!@is_writable($upload_dir)) {
            $upload_dir = sys_get_temp_dir();
            $filename = 'bt_upload_' . $filename;
        }
        $target_file = rtrim($upload_dir, '/') . '/' . $filename;
        if (!@move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) {
            exit('{"code":"文件保存失败"}');
        }

        $cover_filename = '';
        if (isset($_FILES['cover']) && $_FILES['cover']['error'] == 0) {
            $cover_ext = strtolower(pathinfo($_FILES['cover']['name'], PATHINFO_EXTENSION));
            $allowed_cover = array('png', 'jpg', 'jpeg', 'gif');
            if (!in_array($cover_ext, $allowed_cover)) {
                exit('{"code":"封面格式不支持"}');
            }
            $cover_filename = 'program_cover_' . time() . '.' . $cover_ext;
            $upload_dir_cover = '../uploads';
            if (!@is_dir($upload_dir_cover)) {
                @mkdir($upload_dir_cover, 0755, true);
            }
            if (!@is_writable($upload_dir_cover)) {
                $upload_dir_cover = sys_get_temp_dir();
                $cover_filename = 'bt_upload_' . $cover_filename;
            }
            $target_cover = rtrim($upload_dir_cover, '/') . '/' . $cover_filename;
            if (!@move_uploaded_file($_FILES['cover']['tmp_name'], $target_cover)) {
                exit('{"code":"封面保存失败"}');
            }
        }

        $bs_columns = admin_get_table_columns($DB, 'bs');
        $data = array(
            'name' => $name,
            'jg' => $jg,
            'js' => $js,
            'type' => $type,
            'version' => $version
        );
        // 数据库中保存相对路径 programs/xxx.zip
        $wj_path = 'programs/' . $filename;
        if (in_array('file', $bs_columns)) {
            $data['file'] = $wj_path;
        } elseif (in_array('wj', $bs_columns)) {
            $data['wj'] = $wj_path;
        }
        if (!empty($cover_filename)) {
            if (in_array('tb', $bs_columns)) {
                $data['tb'] = $cover_filename;
            } elseif (in_array('cover', $bs_columns)) {
                $data['cover'] = $cover_filename;
            }
        }
        $sql = admin_build_insert_sql('bs', $data, $bs_columns);
        if (empty($sql)) {
            exit('{"code":"表结构不匹配"}');
        }
        $DB->query($sql);
        logjl(is_admin_login(), '导入程序', '导入程序: ' . $name, true);
        exit('{"code":"导入成功"}');
        break;
        
    case 'parse_import_zip':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        if (!isset($_FILES['file']) || $_FILES['file']['error'] != 0) {
            exit(json_encode(array('code' => '文件上传失败')));
        }
        
        $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
        if ($ext != 'zip') {
            exit(json_encode(array('code' => '请上传ZIP格式的文件')));
        }
        
        $upload_dir = '../uploads/temp';
        if (!is_dir($upload_dir)) {
            mkdir($upload_dir, 0755, true);
        }
        
        $temp_file = $upload_dir . '/import_' . time() . '_' . uniqid() . '.zip';
        if (!move_uploaded_file($_FILES['file']['tmp_name'], $temp_file)) {
            exit(json_encode(array('code' => '文件保存失败')));
        }
        
        $zip = new ZipArchive();
        if ($zip->open($temp_file) !== true) {
            unlink($temp_file);
            exit(json_encode(array('code' => '无法打开ZIP文件')));
        }
        
        // 读取programs.json
        $programs_json = $zip->getFromName('programs.json');
        if ($programs_json === false) {
            $zip->close();
            unlink($temp_file);
            exit(json_encode(array('code' => 'ZIP文件中未找到 programs.json')));
        }
        
        $export_data = json_decode($programs_json, true);
        if (!$export_data || !isset($export_data['programs'])) {
            $zip->close();
            unlink($temp_file);
            exit(json_encode(array('code' => 'programs.json 格式错误')));
        }
        
        // 统计图片数量
        $image_count = 0;
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $file_name = $zip->getNameIndex($i);
            if (strpos($file_name, 'images/') === 0 && preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $file_name)) {
                $image_count++;
            }
        }
        
        $zip->close();
        
        // 保存临时文件路径到session
        if (!isset($_SESSION)) session_start();
        $_SESSION['import_temp_file'] = $temp_file;
        
        exit(json_encode(array(
            'code' => '解析成功',
            'programs' => $export_data['programs'],
            'export_time' => $export_data['export_time'] ?? '未知',
            'export_version' => $export_data['export_version'] ?? '未知',
            'program_count' => count($export_data['programs']),
            'image_count' => $image_count
        )));
        break;
        
    case 'import_programs_zip':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        
        $programs_json = isset($_POST['programs']) ? $_POST['programs'] : '';
        $programs = json_decode($programs_json, true);
        
        if (!$programs || !is_array($programs)) {
            exit(json_encode(array('code' => '程序数据格式错误')));
        }
        
        // 获取临时ZIP文件
        if (!isset($_SESSION)) session_start();
        $temp_file = isset($_SESSION['import_temp_file']) ? $_SESSION['import_temp_file'] : '';
        
        if (empty($temp_file) || !file_exists($temp_file)) {
            exit(json_encode(array('code' => '临时文件已过期，请重新上传')));
        }
        
        $zip = new ZipArchive();
        if ($zip->open($temp_file) !== true) {
            exit(json_encode(array('code' => '无法打开ZIP文件')));
        }
        
        $bs_columns = admin_get_table_columns($DB, 'bs');
        $imported = 0;
        $skipped = 0;
        
        foreach ($programs as $program) {
            $name = daddslashes($program['name'] ?? '');
            if (empty($name)) continue;
            
            // 检查是否已存在
            $name_escaped = $DB->escape($name);
            $exists = $DB->get_row("SELECT id FROM `bs` WHERE `name`='{$name_escaped}'");
            if ($exists) {
                $skipped++;
                continue;
            }
            
            // 准备数据
            $data = array(
                'name' => $name,
                'js' => daddslashes($program['js'] ?? ''),
                'tb' => daddslashes($program['tb'] ?? ''),
                'wj' => daddslashes($program['wj'] ?? ''),
                'pz' => daddslashes($program['pz'] ?? ''),
                'jg' => daddslashes($program['jg'] ?? ''),
                'ybd' => daddslashes($program['ybd'] ?? ''),
                'pzsj' => daddslashes($program['pzsj'] ?? ''),
                'wcts' => daddslashes($program['wcts'] ?? ''),
                'type' => daddslashes($program['type'] ?? 'other'),
                'version' => daddslashes($program['version'] ?? ''),
                'webkj' => intval($program['webkj'] ?? 0),
                'sqlkj' => intval($program['sqlkj'] ?? 0),
                'alerts' => daddslashes($program['alerts'] ?? ''),
                'status' => intval($program['status'] ?? 1),
                'form_fields' => daddslashes($program['form_fields'] ?? ''),
                'install_ops' => daddslashes($program['install_ops'] ?? ''),
                'cover' => daddslashes($program['cover'] ?? ''),
                'images' => daddslashes($program['images'] ?? ''),
                'php_version' => daddslashes($program['php_version'] ?? ''),
                'php_ext' => daddslashes($program['php_ext'] ?? ''),
                'category_id' => intval($program['category_id'] ?? 0)
            );
            
            // 处理封面图片
            if (!empty($program['cover']) && strpos($program['cover'], 'images/') === 0) {
                $cover_data = $zip->getFromName($program['cover']);
                if ($cover_data !== false) {
                    $cover_name = basename($program['cover']);
                    $cover_path = '../uploads/' . $cover_name;
                    file_put_contents($cover_path, $cover_data);
                    $data['cover'] = $cover_name;
                    $data['tb'] = $cover_name;
                }
            }
            
            // 处理其他图片
            if (!empty($program['images'])) {
                $images = json_decode($program['images'], true);
                if (is_array($images)) {
                    $new_images = array();
                    foreach ($images as $img) {
                        if (strpos($img, 'images/') === 0) {
                            $img_data = $zip->getFromName($img);
                            if ($img_data !== false) {
                                $img_name = basename($img);
                                $img_path = '../uploads/' . $img_name;
                                file_put_contents($img_path, $img_data);
                                $new_images[] = $img_name;
                            }
                        } else {
                            $new_images[] = $img;
                        }
                    }
                    $data['images'] = json_encode($new_images);
                }
            }
            
            // 处理程序包文件
            if (!empty($program['wj'])) {
                $wj_filename = $program['wj'];
                // 如果wj包含programs/前缀，去掉前缀获取实际文件名
                if (strpos($wj_filename, 'programs/') === 0) {
                    $wj_filename = substr($wj_filename, 9);
                }
                // 在ZIP中查找程序包文件
                $wj_in_zip = 'programs/' . $wj_filename;
                $wj_data = $zip->getFromName($wj_in_zip);
                if ($wj_data !== false) {
                    // 确保programs目录存在
                    $programs_dir = '../uploads/programs';
                    if (!is_dir($programs_dir)) {
                        mkdir($programs_dir, 0755, true);
                    }
                    $new_wj_name = 'program_source_' . time() . '_' . uniqid() . '.' . pathinfo($wj_filename, PATHINFO_EXTENSION);
                    $wj_path = $programs_dir . '/' . $new_wj_name;
                    file_put_contents($wj_path, $wj_data);
                    // 数据库中保存相对路径
                    $data['wj'] = 'programs/' . $new_wj_name;
                }
            }
            
            // 构建并执行SQL
            $sql = admin_build_insert_sql('bs', $data, $bs_columns);
            if (!empty($sql)) {
                $DB->query($sql);
                $imported++;
            }
        }
        
        $zip->close();
        unlink($temp_file);
        unset($_SESSION['import_temp_file']);
        
        logjl(is_admin_login(), '批量导入程序', "导入 {$imported} 个，跳过 {$skipped} 个", true);
        exit(json_encode(array(
            'code' => '导入完成',
            'imported' => $imported,
            'skipped' => $skipped
        )));
        break;
        
    case 'ddsc':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $id = intval($_POST['id']);
        if ($id <= 0) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $orders_table_exists = $DB->query("SHOW TABLES LIKE 'orders'");
        $has_orders_table = $orders_table_exists && $DB->num_rows($orders_table_exists) > 0;
        if ($has_orders_table) {
            $id_escaped = $DB->escape($id);
            $order = $DB->get_row("SELECT * FROM `orders` WHERE `id`='{$id_escaped}'");
            if ($order) {
                $id_escaped = $DB->escape($id);
                $DB->query("DELETE FROM `orders` WHERE `id`='{$id_escaped}'");
                logjl(is_admin_login(), '删除订单', '删除订单ID: ' . $id, true);
                exit(json_encode(array('code' => '删除成功')));
            }
        }
        $id_escaped = $DB->escape($id);
        $dd = $DB->get_row("SELECT * FROM `dd` WHERE `id`='{$id_escaped}'");
        if ($dd) {
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `dd` WHERE `id`='{$id_escaped}'");
            logjl(is_admin_login(), '删除订单', '删除订单ID: ' . $id, true);
            exit(json_encode(array('code' => '删除成功')));
        }
        exit(json_encode(array('code' => '删除失败')));
        break;

    case 'ddscxz':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : (isset($_POST['idsz']) ? $_POST['idsz'] : array());
        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        $ids = array_filter(array_map('intval', $ids));
        if (empty($ids)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $id_list = implode(',', $ids);
        $orders_table_exists = $DB->query("SHOW TABLES LIKE 'orders'");
        $has_orders_table = $orders_table_exists && $DB->num_rows($orders_table_exists) > 0;
        if ($has_orders_table) {
            $id_list_escaped = $DB->escape($id_list);
            $DB->query("DELETE FROM `orders` WHERE `id` IN ({$id_list_escaped})");
        } else {
            $id_list_escaped = $DB->escape($id_list);
            $DB->query("DELETE FROM `dd` WHERE `id` IN ({$id_list_escaped})");
        }
        logjl(is_admin_login(), '批量删除订单', '删除订单ID: ' . $id_list, true);
        exit(json_encode(array('code' => '删除成功', 'count' => count($ids))));
        break;

    case 'listdd':
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) {
            $limit = 10;
        }
        if ($limit > 100) {
            $limit = 100;
        }
        $offset = ($page - 1) * $limit;
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));
        $status = daddslashes(trim(isset($_POST['status']) ? $_POST['status'] : ''));
        $payment_method = daddslashes(trim(isset($_POST['payment_method']) ? $_POST['payment_method'] : ''));

        $orders_table_exists = $DB->query("SHOW TABLES LIKE 'orders'");
        $has_orders_table = $orders_table_exists && $DB->num_rows($orders_table_exists) > 0;
        $use_orders = false;
        if ($has_orders_table) {
            $orders_count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `orders`");
            $use_orders = $orders_count_row && intval($orders_count_row['cnt']) > 0;
        }

        $rows = array();
        $total = 0;
        if ($use_orders) {
            $columns = admin_get_table_columns($DB, 'orders');
            $conditions = array();
            if (!empty($keyword)) {
                $like_parts = array();
                if (in_array('order_no', $columns)) {
                    $like_parts[] = "`order_no` LIKE '%{$keyword}%'";
                }
                if (in_array('user', $columns)) {
                    $like_parts[] = "`user` LIKE '%{$keyword}%'";
                }
                if (in_array('product_name', $columns)) {
                    $like_parts[] = "`product_name` LIKE '%{$keyword}%'";
                }
                if (!empty($like_parts)) {
                    $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
                }
            }
            if (!empty($status) && in_array('status', $columns)) {
                $conditions[] = "`status`='{$status}'";
            }
            if (!empty($payment_method) && in_array('payment_method', $columns)) {
                $conditions[] = "`payment_method`='{$payment_method}'";
            }
            $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
            $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `orders` WHERE {$where}");
            $total = $count_row ? intval($count_row['cnt']) : 0;
            if ($total > 0) {
                $res = $DB->query("SELECT * FROM `orders` WHERE {$where} ORDER BY `create_time` DESC, `id` DESC LIMIT {$offset},{$limit}");
                while ($row = $DB->fetch($res)) {
                    $user_name = '-';
                    if (isset($row['user']) && $row['user'] !== '') {
                        $user_name = $row['user'];
                    } elseif (isset($row['user_id'])) {
                        $user_info = $DB->get_row("SELECT `user` FROM `zj` WHERE `id`='" . intval($row['user_id']) . "'");
                        $user_name = $user_info ? $user_info['user'] : '-';
                    }
                    $product_name = isset($row['product_name']) ? $row['product_name'] : '-';
                    $rows[] = array(
                        'id' => isset($row['id']) ? intval($row['id']) : 0,
                        'user' => $user_name,
                        'order_no' => isset($row['order_no']) ? $row['order_no'] : '-',
                        'product_name' => $product_name,
                        'amount' => isset($row['amount']) ? $row['amount'] : '0',
                        'payment_method' => isset($row['payment_method']) ? $row['payment_method'] : '-',
                        'status' => isset($row['status']) ? $row['status'] : '-',
                        'create_time' => isset($row['create_time']) ? $row['create_time'] : '-'
                    );
                }
            }
        } else {
            $dd_table_exists = $DB->query("SHOW TABLES LIKE 'dd'");
            $has_dd_table = $dd_table_exists && $DB->num_rows($dd_table_exists) > 0;
            if ($has_dd_table) {
                $columns = admin_get_table_columns($DB, 'dd');
                $conditions = array();
                if (!empty($keyword)) {
                    $like_parts = array();
                    if (in_array('ddh', $columns)) {
                        $like_parts[] = "`ddh` LIKE '%{$keyword}%'";
                    }
                    if (in_array('user', $columns)) {
                        $like_parts[] = "`user` LIKE '%{$keyword}%'";
                    }
                    if (in_array('spname', $columns)) {
                        $like_parts[] = "`spname` LIKE '%{$keyword}%'";
                    }
                    if (!empty($like_parts)) {
                        $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
                    }
                }
                $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
                $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `dd` WHERE {$where}");
                $total = $count_row ? intval($count_row['cnt']) : 0;
                if ($total > 0) {
                    $res = $DB->query("SELECT * FROM `dd` WHERE {$where} ORDER BY `id` DESC LIMIT {$offset},{$limit}");
                    while ($row = $DB->fetch($res)) {
                        $product_name = '-';
                        if (isset($row['spname']) && $row['spname'] !== '') {
                            $product_name = $row['spname'];
                        } elseif (isset($row['bsid'])) {
                            $bs_info = $DB->get_row("SELECT `name` FROM `bs` WHERE `id`='" . intval($row['bsid']) . "'");
                            if ($bs_info && !empty($bs_info['name'])) {
                                $product_name = $bs_info['name'];
                            }
                        }
                        $rows[] = array(
                            'id' => isset($row['id']) ? intval($row['id']) : 0,
                            'user' => isset($row['user']) ? $row['user'] : '-',
                            'order_no' => isset($row['ddh']) ? $row['ddh'] : '-',
                            'product_name' => $product_name,
                            'amount' => isset($row['jg']) ? $row['jg'] : '0',
                            'payment_method' => isset($row['zffs']) ? $row['zffs'] : '-',
                            'status' => isset($row['zt']) ? $row['zt'] : '-',
                            'create_time' => isset($row['date']) ? $row['date'] : '-'
                        );
                    }
                }
            }
        }
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;

    case 'listbs':
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) {
            $limit = 10;
        }
        if ($limit > 100) {
            $limit = 100;
        }
        $offset = ($page - 1) * $limit;
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        $columns = admin_get_table_columns($DB, 'bs');
        $conditions = array();
        if (!empty($keyword)) {
            $like_parts = array();
            if (in_array('name', $columns)) {
                $like_parts[] = "`name` LIKE '%{$keyword}%'";
            }
            if (in_array('type', $columns)) {
                $like_parts[] = "`type` LIKE '%{$keyword}%'";
            }
            if (in_array('version', $columns)) {
                $like_parts[] = "`version` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `bs` WHERE {$where}");
        $total = $count_row ? intval($count_row['cnt']) : 0;
        $rows = array();
        if ($total > 0) {
            $res = $DB->query("SELECT * FROM `bs` WHERE {$where} ORDER BY `id` DESC LIMIT {$offset},{$limit}");
            while ($row = $DB->fetch($res)) {
                $rows[] = array(
                    'id' => isset($row['id']) ? intval($row['id']) : 0,
                    'name' => isset($row['name']) ? $row['name'] : '-',
                    'type' => isset($row['type']) ? $row['type'] : '-',
                    'version' => isset($row['version']) ? $row['version'] : '-',
                    'price' => isset($row['jg']) ? $row['jg'] : '0',
                    'desc' => isset($row['js']) ? $row['js'] : '',
                    'tb' => isset($row['tb']) ? $row['tb'] : '',
                    'cover' => isset($row['cover']) ? $row['cover'] : '',
                    'images' => isset($row['images']) ? $row['images'] : '[]',
                    'webkj' => isset($row['webkj']) ? $row['webkj'] : 0,
                    'sqlkj' => isset($row['sqlkj']) ? $row['sqlkj'] : 0,
                    'status' => isset($row['status']) ? intval($row['status']) : 0
                );
            }
        }
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;

    case 'listbt':
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) {
            $limit = 10;
        }
        if ($limit > 100) {
            $limit = 100;
        }
        $offset = ($page - 1) * $limit;
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));
        $status = daddslashes(trim(isset($_POST['status']) ? $_POST['status'] : ''));
        $os = daddslashes(trim(isset($_POST['os']) ? $_POST['os'] : ''));

        $columns = admin_get_table_columns($DB, 'bt');
        $conditions = array();
        if (!empty($keyword)) {
            $like_parts = array();
            if (in_array('btmc', $columns)) {
                $like_parts[] = "`btmc` LIKE '%{$keyword}%'";
            }
            if (in_array('ip', $columns)) {
                $like_parts[] = "`ip` LIKE '%{$keyword}%'";
            }
            if (in_array('bzbh', $columns)) {
                $like_parts[] = "`bzbh` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        if ($status !== '' && in_array('jkkg', $columns)) {
            $conditions[] = "`jkkg`='{$status}'";
        }
        if ($os !== '' && in_array('czzt', $columns)) {
            $conditions[] = "`czzt`='{$os}'";
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `bt` WHERE {$where}");
        $total = $count_row ? intval($count_row['cnt']) : 0;
        $rows = array();
        if ($total > 0) {
            $res = $DB->query("SELECT * FROM `bt` WHERE {$where} ORDER BY `id` DESC LIMIT {$offset},{$limit}");
            while ($row = $DB->fetch($res)) {
                $rows[] = array(
                    'id' => isset($row['id']) ? intval($row['id']) : 0,
                    'btmc' => isset($row['btmc']) ? $row['btmc'] : '',
                    'ip' => isset($row['ip']) ? $row['ip'] : '',
                    'dk' => isset($row['dk']) ? $row['dk'] : '',
                    'bzbh' => isset($row['bzbh']) ? $row['bzbh'] : '',
                    'czzt' => isset($row['czzt']) ? $row['czzt'] : '',
                    'jkkg' => isset($row['jkkg']) ? $row['jkkg'] : 'false',
                    'aqfw' => isset($row['aqfw']) ? $row['aqfw'] : 'false',
                    'key' => isset($row['key']) ? $row['key'] : '',
                    'ftp' => isset($row['ftp']) ? $row['ftp'] : ''
                );
            }
        }
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;

    case 'listzj':
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) {
            $limit = 10;
        }
        if ($limit > 100) {
            $limit = 100;
        }
        $offset = ($page - 1) * $limit;
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        $columns = admin_get_table_columns($DB, 'zj');
        $conditions = array();
        if (!empty($keyword)) {
            $like_parts = array();
            if (in_array('user', $columns)) {
                $like_parts[] = "`user` LIKE '%{$keyword}%'";
            }
            if (in_array('cplx', $columns)) {
                $like_parts[] = "`cplx` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `zj` WHERE {$where}");
        $total = $count_row ? intval($count_row['cnt']) : 0;
        $rows = array();
        if ($total > 0) {
            $res = $DB->query("SELECT * FROM `zj` WHERE {$where} ORDER BY `id` DESC LIMIT {$offset},{$limit}");
            while ($row = $DB->fetch($res)) {
                $rows[] = array(
                    'id' => isset($row['id']) ? intval($row['id']) : 0,
                    'user' => isset($row['user']) ? $row['user'] : '',
                    'pass' => isset($row['pass']) ? $row['pass'] : '',
                    'cplx' => isset($row['cplx']) ? $row['cplx'] : '',
                    'wypj' => isset($row['wypj']) ? $row['wypj'] : 0,
                    'sypj' => isset($row['sypj']) ? $row['sypj'] : 0,
                    'llxz' => isset($row['llxz']) ? $row['llxz'] : 0,
                    'dqsj' => isset($row['dqsj']) ? $row['dqsj'] : '',
                    'yms' => isset($row['yms']) ? $row['yms'] : 0,
                    'btid' => isset($row['btid']) ? $row['btid'] : 0,
                    'zt' => isset($row['zt']) ? $row['zt'] : ''
                );
            }
        }
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;

    case 'toggle_site':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 0, 'msg' => '请先登录')));
        }
        $id = intval(isset($_POST['id']) ? $_POST['id'] : 0);
        $action = isset($_POST['action']) ? $_POST['action'] : '';
        
        if ($id <= 0 || !in_array($action, array('start', 'stop'))) {
            exit(json_encode(array('code' => 0, 'msg' => '参数错误')));
        }
        
        // 获取主机信息
        $zj = $DB->get_row("SELECT * FROM `zj` WHERE `id`='{$id}'");
        if (!$zj) {
            exit(json_encode(array('code' => 0, 'msg' => '主机不存在')));
        }
        
        // 获取宝塔服务器信息
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='" . intval($zj['btid']) . "'");
        if (!$bt) {
            exit(json_encode(array('code' => 0, 'msg' => '宝塔服务器信息不存在')));
        }
        
        // 初始化宝塔API
        $bt_api = new bt_api();
        $protocol = isset($bt['aqfw']) && $bt['aqfw'] == 'true' ? 'https' : 'http';
        $bt_api->BT_PANEL = $protocol . '://' . $bt['ip'] . ':' . $bt['dk'];
        $bt_api->BT_KEY = $bt['key'];
        
        // 执行暂停/启动操作
        $errors = array();
        
        // 构建完整域名（宝塔API需要完整域名来定位配置文件）
        $domain = $zj['user'] . '.a116.vip';
        
        if ($action === 'stop') {
            // 1. 暂停网站（SiteStop内部已包含serviceReload）
            $result = $bt_api->ztweb($zj['webid'], $domain);
            if (!$result || !isset($result['status']) || ($result['status'] !== true && $result['status'] !== 'true')) {
                $errors[] = '网站暂停失败: ' . (isset($result['msg']) ? $result['msg'] : '未知错误');
            }
            
            // 2. 暂停数据库（通过设置访问权限为本地）
            $db_result = $bt_api->mysqlqx($zj['user'], '127.0.0.1');
            if (!$db_result || !isset($db_result['status']) || ($db_result['status'] !== true && $db_result['status'] !== 'true')) {
                $errors[] = '数据库暂停失败: ' . (isset($db_result['msg']) ? $db_result['msg'] : '未知错误');
            }
            
            // 3. 暂停FTP
            $ftp_result = $bt_api->ftpxg($zj['webid'], $zj['user'], '0');
            if (!$ftp_result || !isset($ftp_result['status']) || ($ftp_result['status'] !== true && $ftp_result['status'] !== 'true')) {
                $errors[] = 'FTP暂停失败: ' . (isset($ftp_result['msg']) ? $ftp_result['msg'] : '未知错误');
            }
            
            $newStatus = '已暂停';
        } else {
            // 1. 启动网站（SiteStart内部已包含serviceReload）
            $result = $bt_api->qdweb($zj['webid'], $domain);
            if (!$result || !isset($result['status']) || ($result['status'] !== true && $result['status'] !== 'true')) {
                $errors[] = '网站启动失败: ' . (isset($result['msg']) ? $result['msg'] : '未知错误');
            }
            
            // 2. 启动数据库（恢复访问权限为%）
            $db_result = $bt_api->mysqlqx($zj['user'], '%');
            if (!$db_result || !isset($db_result['status']) || ($db_result['status'] !== true && $db_result['status'] !== 'true')) {
                $errors[] = '数据库启动失败: ' . (isset($db_result['msg']) ? $db_result['msg'] : '未知错误');
            }
            
            // 3. 启动FTP
            $ftp_result = $bt_api->ftpxg($zj['webid'], $zj['user'], '1');
            if (!$ftp_result || !isset($ftp_result['status']) || ($ftp_result['status'] !== true && $ftp_result['status'] !== 'true')) {
                $errors[] = 'FTP启动失败: ' . (isset($ftp_result['msg']) ? $result['msg'] : '未知错误');
            }
            
            $newStatus = '正常';
        }
        
        // 更新数据库状态（即使部分失败也更新状态）
        $DB->query("UPDATE `zj` SET `zt`='{$newStatus}' WHERE `id`='{$id}'");
        $actionText = $action === 'stop' ? '暂停' : '启动';
        logjl($zj['user'], '管理员' . $actionText, '管理员手动' . $actionText . '主机', true);
        
        if (empty($errors)) {
            exit(json_encode(array('code' => 1, 'msg' => $actionText . '成功', 'status' => true)));
        } else {
            exit(json_encode(array('code' => 1, 'msg' => $actionText . '完成，但有部分操作失败: ' . implode('; ', $errors), 'status' => true, 'warnings' => $errors)));
        }
        break;

    case 'clean_old_files':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 0, 'msg' => '请先登录')));
        }

        $rootPath = realpath(__DIR__ . '/..');
        if (!$rootPath) {
            exit(json_encode(array('code' => 0, 'msg' => '无法获取根目录路径')));
        }

        // 项目文件清单（写死在代码中）- 从zip文件提取的完整列表
        $projectFiles = array(
            // 根目录文件
            '.htaccess', '.user.ini', '404.html', 'app-download.php', 'bash.conf.php', 'class.php',
            'cf_up.php', 'favicon.ico', 'index.php', 'install.php', 'jk.php', 'opt.php',
            'robots.txt', 'sitemap.xml', 'version.php', '安装教程',
            // admin 目录
            'admin', 'admin/index.php', 'admin/sy.php', 'admin/category.php', 'admin/migrate_categories.php',
            'admin/db_table_check.php', 'admin/login.php', 'admin/monitor.php', 'admin/expire_manage.php',
            'admin/ajax.php', 'admin/add_dr_new.php', 'admin/wjxz.php', 'admin/feedback_history.php',
            'admin/upgrade_handler.php', 'admin/edit.php', 'admin/verify.php', 'admin/head.php',
            'admin/list.php', 'admin/submit_feedback.php', 'admin/add.php', 'admin/async_import.php',
            'admin/chat_manage.php', 'admin/author.php', 'admin/tutorial.php', 'admin/update.php',
            'admin/css', 'admin/css/login.css', 'admin/css/style.css', 'admin/announcement.php',
            'admin/heartbeat.php', 'admin/api_keys.php', 'admin/js', 'admin/js/login.js',
            'admin/mail.php', 'admin/expire_settings.php', 'admin/set_auth.php', 'admin/cleaner.php',
            'admin/bt_monitor.php', 'admin/set.php', 'admin/chat_proxy.php', 'admin/code.php',
            // api 目录
            'api', 'api/app_base_api.php', 'api/app_domain_api.php', 'api/download.php',
            'api/app_file_api.php', 'api/api.php', 'api/programs.php', 'api/app_api_new.php',
            'api/api_debug.log', 'api/app_api.php', 'api/app_api_proxy.php',
            // app 目录
            'app', 'app/app.apk',
            // cron 目录
            'cron', 'cron/check_ssl.php', 'cron/check_expire.php', 'cron/run_cron.php',
            'cron/auto_stop_expire.php', 'cron/auto_delete_expired.php', 'cron/collect_traffic.php',
            // fin 目录
            'fin', 'fin/mleoe_swapidc', 'fin/mleoe_swapidc/mleoe.zip',
            'fin/mleoe_mofang', 'fin/mleoe_mofang/mleoebt.zip',
            // install 目录
            'install', 'install/index.php', 'install/index.php.new.backup', 'install/sql',
            'install/sql/zj.sql', 'install/sql/expire_settings.sql', 'install/sql/bs_purchase.sql',
            'install/sql/program_categories.sql', 'install/sql/notification_settings.sql',
            'install/sql/import_tasks.sql', 'install/sql/bsjl.sql', 'install/sql/ssl_certificates.sql',
            'install/sql/app_access_tokens.sql', 'install/sql/dd.sql', 'install/sql/system_api_keys.sql',
            'install/sql/auth_token.sql', 'install/sql/log.sql', 'install/sql/qr_login.sql',
            'install/sql/cron_monitor_stats.sql', 'install/sql/host_log.sql', 'install/sql/user_certs.sql',
            'install/sql/notifications.sql', 'install/sql/traffic_stats.sql', 'install/sql/balance_logs.sql',
            'install/sql/cron_tasks.sql', 'install/sql/tables_order.txt', 'install/sql/backups.sql',
            'install/sql/orders.sql', 'install/sql/dre_admin.sql', 'install/sql/user_tokens.sql',
            'install/sql/config.sql', 'install/sql/cron_monitor_logs.sql', 'install/sql/program_id_mapping.sql',
            'install/sql/bs.sql', 'install/sql/balance_orders.sql', 'install/sql/server_parse_domain.sql',
            'install/sql/user_login_region.sql', 'install/sql/user_notification_settings.sql',
            // lang 目录
            'lang', 'lang/zh_CN.php', 'lang/en_US.php', 'lang/zh_CN_extensions.php', 'lang/en_US_extensions.php',
            // data 目录
            'data',
            // logs 目录
            'logs', 'logs/api_error.log',
            // mail 目录
            'mail', 'mail/PHPMailerAutoload.php',
            // MPHX 目录
            'MPHX', 'MPHX/security.php', 'MPHX/member.php', 'MPHX/json_helper.php',
            'MPHX/UpgradeManager.php', 'MPHX/lib', 'MPHX/lib/notify.class.php',
            'MPHX/lib/core.function.php', 'MPHX/lib/md5.function.php', 'MPHX/lib/submit.class.php',
            'MPHX/TemplateBase.php', 'MPHX/api', 'MPHX/api/UserApi.php', 'MPHX/AuthManager.php',
            'MPHX/BL.php', 'MPHX/db.class.php', 'MPHX/function.php', 'MPHX/common.php', 'MPHX/SQ.php',
            // plugin 目录
            'plugin', 'plugin/shop', 'plugin/shop/project_system',
            'plugin/shop/project_system/server.php', 'plugin/shop/project_system/action.php',
            'plugin/shop/project_system/view', 'plugin/shop/project_system/view/index.html',
            'plugin/shop/project_system/config_new.php', 'plugin/shop/project_system/modular',
            'plugin/shop/project_system/modular/index.php',
            'plugin/shop/project_system/admin', 'plugin/shop/project_system/modular_admin',
            // static 目录
            'static', 'static/css', 'static/css/all.min.css', 'static/css/bootstrap.min.css',
            'static/css/materialdesignicons.min.css', 'static/webfonts', 'static/webfonts/fa-solid-900.woff2',
            'static/webfonts/fa-solid-900.woff', 'static/webfonts/fa-brands-400.eot',
            'static/webfonts/fa-brands-400.woff2', 'static/webfonts/fa-regular-400.woff2',
            'static/webfonts/fa-regular-400.eot', 'static/webfonts/fa-solid-900.eot',
            'static/webfonts/fa-solid-900.ttf', 'static/js',
            'static/js/Chart.min.js', 'static/js/bootstrap.bundle.min.js', 'static/js/jquery.min.js',
            'static/js/china_map.json', 'static/js/echarts.min.js', 'static/js/bootstrap.min.js',
            'static/fonts', 'static/fonts/materialdesignicons-webfont.woff',
            'static/fonts/materialdesignicons-webfont.ttf', 'static/fonts/materialdesignicons-webfont.eot',
            'static/fonts/materialdesignicons-webfont.woff2',
            // templates 目录
            'templates', 'templates/default', 'templates/default/index.php', 'templates/default/config.json',
            'templates/default/assets', 'templates/default/assets/images', 'templates/default/assets/images/preview.jpg',
            'templates/default/assets/css', 'templates/default/assets/css/responsive.css',
            'templates/default/assets/css/login.css', 'templates/default/assets/css/style.css',
            'templates/default/assets/css/ui-ux-pro-max.css', 'templates/default/assets/js',
            'templates/default/assets/js/page-loader.js', 'templates/default/assets/js/login.js',
            'templates/default/assets/js/ui-ux-pro-max.js', 'templates/default/components',
            'templates/default/pages', 'templates/default/pages/index.php', 'templates/default/pages/app-download.php',
            'templates/modern', 'templates/modern/index.php', 'templates/modern/images', 'templates/modern/images/preview.jpg',
            'templates/modern/config.json', 'templates/modern/assets', 'templates/modern/assets/css',
            'templates/modern/assets/css/dashboard.css', 'templates/modern/assets/css/style.css',
            'templates/modern/components', 'templates/modern/pages', 'templates/modern/pages/dashboard.php',
            'templates/modern/pages/app-download.php',
            // user 目录
            'user', 'user/sso_login.php', 'user/index.php', 'user/sy.php', 'user/return_url.php',
            'user/sql.php', 'user/login.php', 'user/ajax.php', 'user/deploy_logs.php', 'user/sqlqx.php',
            'user/ftp_settings.php', 'user/sql_permission.php', 'user/theme_loader.php', 'user/profile.php',
            'user/TemplateManager.php', 'user/pay.php', 'user/balance_notify.php', 'user/theme.php',
            'user/balance_return.php', 'user/idcdl.php', 'user/optimize.php', 'user/deploy.php',
            'user/traffic.php', 'user/clear_cache.php', 'user/css', 'user/css/responsive.css',
            'user/css/login.css', 'user/css/style.css', 'user/css/ui-ux-pro-max.css', 'user/notifications.php',
            'user/api', 'user/api/php', 'user/api/php/php_api.php', 'user/api/domain', 'user/api/domain/domain_api.php',
            'user/api/file', 'user/api/file/file_api.php', 'user/api/base_api.php', 'user/api/api_router.php',
            'user/api/auth', 'user/api/auth/auth_api.php', 'user/api/auth/email_verify_api.php',
            'user/api/deploy', 'user/api/deploy/json_helper.php', 'user/api/deploy/deploy_api.php',
            'user/api/cron', 'user/api/cron/cron_api.php', 'user/api/balance_api.php',
            'user/api/backup', 'user/api/backup/backup_api.php', 'user/api/debug.log',
            'user/api/site', 'user/api/site/site_api.php', 'user/api/template', 'user/api/template/template_api.php',
            'user/api/traffic', 'user/api/traffic/traffic_api.php', 'user/api/error.log',
            'user/logs.php', 'user/backup.php', 'user/includes', 'user/includes/access.php',
            'user/includes/anti_hotlink.php', 'user/includes/default_doc.php', 'user/includes/rewrite.php',
            'user/includes/run_dir.php', 'user/includes/ssl.php', 'user/includes/subdirectory.php',
            'user/file.php', 'user/.htaccess', 'user/js', 'user/js/page-loader.js', 'user/js/ui-ux-pro-max.js',
            'user/js/login.js', 'user/notification-settings.php', 'user/cron.php', 'user/panel.php',
            'user/set.php', 'user/notify_url.php', 'user/orders.php', 'user/app_access.php',
            'user/certs', 'user/modules', 'user/modules/website', 'user/modules/file', 'user/modules/personal',
            'user/modules/backup', 'user/modules/security', 'user/modules/finance', 'user/modules/database',
            'user/modules/monitor', 'user/uploads', 'user/uploads/avatars',
            'user/uploads/avatars/avatar_11_1771494806.jpg', 'user/uploads/avatars/avatar_11_1771495084.png',
            'user/uploads/avatars/avatar_11_1771553536.png', 'user/uploads/avatars/avatar_8_1772591785.png',
            // uploads 目录
            'uploads', 'uploads/programs',
        );
        
        // 排除的路径（不检测）
        $excludedPaths = array('config.php', 'uploads', 'data');
        
        $foundItems = array();
        $projectFilesCount = 0;
        
        function scanDirectoryForClean($dir, $rootPath, $excludedPaths, $projectFiles, &$foundItems, &$projectFilesCount) {
            $items = scandir($dir);
            foreach ($items as $item) {
                if ($item === '.' || $item === '..') continue;
                
                $fullPath = $dir . DIRECTORY_SEPARATOR . $item;
                $realPath = realpath($fullPath);
                
                // 获取相对路径（统一使用/作为分隔符）
                $relativePath = str_replace($rootPath . DIRECTORY_SEPARATOR, '', $realPath);
                $relativePath = str_replace($rootPath, '', $relativePath);
                $relativePath = ltrim($relativePath, DIRECTORY_SEPARATOR);
                $relativePath = str_replace('\\', '/', $relativePath);
                
                // 检查是否在排除列表中
                $isExcluded = false;
                foreach ($excludedPaths as $excluded) {
                    if ($relativePath === $excluded || strpos($relativePath, $excluded . '/') === 0) {
                        $isExcluded = true;
                        break;
                    }
                }
                if ($isExcluded) continue;
                
                // 检查是否是项目文件（精确匹配或路径前缀匹配）
                $isProjectFile = false;
                if (in_array($relativePath, $projectFiles)) {
                    $isProjectFile = true;
                } else {
                    // 检查是否是某个项目目录的子文件/子目录
                    foreach ($projectFiles as $projectFile) {
                        // 如果项目文件是目录，检查当前路径是否在该目录下
                        if (strpos($relativePath, $projectFile . '/') === 0) {
                            $isProjectFile = true;
                            break;
                        }
                    }
                }
                
                if ($isProjectFile) {
                    $projectFilesCount++;
                    if (is_dir($realPath)) {
                        scanDirectoryForClean($realPath, $rootPath, $excludedPaths, $projectFiles, $foundItems, $projectFilesCount);
                    }
                } else {
                    $foundItems[] = $relativePath;
                }
            }
        }
        
        scanDirectoryForClean($rootPath, $rootPath, $excludedPaths, $projectFiles, $foundItems, $projectFilesCount);
        
        // 保存项目文件列表到session，供删除时使用
        $_SESSION['clean_project_files'] = $projectFiles;
        
        exit(json_encode(array(
            'code' => 1,
            'scanned_path' => $rootPath,
            'excluded_paths' => $excludedPaths,
            'project_files_count' => $projectFilesCount,
            'found_items' => $foundItems,
            'message' => '扫描完成，发现 ' . count($foundItems) . ' 个非项目文件/文件夹'
        )));
        break;

    case 'confirm_delete_files':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 0, 'msg' => '请先登录')));
        }
        
        $files = isset($_POST['files']) ? json_decode($_POST['files'], true) : array();
        if (empty($files) || !is_array($files)) {
            exit(json_encode(array('code' => 0, 'msg' => '没有要删除的文件')));
        }
        
        $rootPath = realpath(__DIR__ . '/..');
        $deleted = array();
        $failed = array();
        
        foreach ($files as $file) {
            // 安全检查：防止目录遍历
            $file = str_replace(array('..', '\\'), array('', '/'), $file);
            $fullPath = $rootPath . DIRECTORY_SEPARATOR . $file;
            $realPath = realpath($fullPath);
            
            // 确保路径在项目目录内
            if (!$realPath || strpos($realPath, $rootPath) !== 0) {
                $failed[] = array('path' => $file, 'error' => '路径不合法');
                continue;
            }
            
            // 排除保护文件
            if (basename($realPath) === 'config.php' || strpos($realPath, 'uploads') !== false) {
                $failed[] = array('path' => $file, 'error' => '受保护的文件');
                continue;
            }
            
            if (is_dir($realPath)) {
                // 递归删除目录
                $iterator = new RecursiveIteratorIterator(
                    new RecursiveDirectoryIterator($realPath, RecursiveDirectoryIterator::SKIP_DOTS),
                    RecursiveIteratorIterator::CHILD_FIRST
                );
                $dirDeleted = true;
                foreach ($iterator as $subItem) {
                    if ($subItem->isDir()) {
                        if (!rmdir($subItem->getRealPath())) {
                            $dirDeleted = false;
                        }
                    } else {
                        if (!unlink($subItem->getRealPath())) {
                            $dirDeleted = false;
                        }
                    }
                }
                if (rmdir($realPath) && $dirDeleted) {
                    $deleted[] = $file;
                } else {
                    $failed[] = array('path' => $file, 'error' => '删除目录失败');
                }
            } else {
                if (unlink($realPath)) {
                    $deleted[] = $file;
                } else {
                    $failed[] = array('path' => $file, 'error' => '删除文件失败');
                }
            }
        }
        
        exit(json_encode(array(
            'code' => 1,
            'message' => '删除完成：成功 ' . count($deleted) . ' 个，失败 ' . count($failed) . ' 个',
            'deleted' => $deleted,
            'failed' => $failed
        )));
        break;

    case 'listym':
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) {
            $limit = 10;
        }
        if ($limit > 100) {
            $limit = 100;
        }
        $offset = ($page - 1) * $limit;
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        $columns = admin_get_table_columns($DB, 'ym');
        $conditions = array();
        if (!empty($keyword)) {
            $like_parts = array();
            if (in_array('ym', $columns)) {
                $like_parts[] = "`ym` LIKE '%{$keyword}%'";
            }
            if (in_array('js', $columns)) {
                $like_parts[] = "`js` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `ym` WHERE {$where}");
        $total = $count_row ? intval($count_row['cnt']) : 0;
        $rows = array();
        if ($total > 0) {
            $res = $DB->query("SELECT * FROM `ym` WHERE {$where} ORDER BY `id` DESC LIMIT {$offset},{$limit}");
            while ($row = $DB->fetch($res)) {
                $bt_ip = '-';
                if (!empty($row['btid'])) {
                    $bt_info = $DB->get_row("SELECT `ip` FROM `bt` WHERE `id`='" . intval($row['btid']) . "'");
                    $bt_ip = $bt_info ? $bt_info['ip'] : '-';
                }
                $rows[] = array(
                    'id' => isset($row['id']) ? intval($row['id']) : 0,
                    'ym' => isset($row['ym']) ? $row['ym'] : '',
                    'jg' => isset($row['jg']) ? $row['jg'] : '',
                    'js' => isset($row['js']) ? $row['js'] : '',
                    'btid' => isset($row['btid']) ? $row['btid'] : 0,
                    'bt_ip' => $bt_ip
                );
            }
        }
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;

    case 'btscxz':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : (isset($_POST['idsz']) ? $_POST['idsz'] : array());
        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        $ids = array_filter(array_map('intval', $ids));
        if (empty($ids)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $success = 0;
        $failed = 0;
        foreach ($ids as $id) {
            $id_escaped = $DB->escape($id);
        $bt = $DB->get_row("SELECT * FROM `bt` WHERE `id`='{$id_escaped}'");
            if ($bt) {
                $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `zj` WHERE `btid`='{$id_escaped}'");
                $id_escaped2 = $DB->escape($id);
                if ($DB->query("DELETE FROM `bt` WHERE `id`='{$id_escaped2}'")) {
                    $success++;
                } else {
                    $failed++;
                }
            } else {
                $failed++;
            }
        }
        logjl(is_admin_login(), '批量删除宝塔', '删除宝塔ID: ' . implode(',', $ids), true);
        exit(json_encode(array('code' => '删除成功', 'success' => $success, 'failed' => $failed)));
        break;

    case 'zjscxz':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : (isset($_POST['idsz']) ? $_POST['idsz'] : array());
        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        $ids = array_filter(array_map('intval', $ids));
        if (empty($ids)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $success = 0;
        $failed = 0;
        foreach ($ids as $id) {
            $delete_result = admin_delete_zj_record($DB, $id);
            if ($delete_result['success']) {
                $success++;
            } else {
                $failed++;
            }
        }
        exit(json_encode(array('code' => '删除成功', 'success' => $success, 'failed' => $failed)));
        break;

    case 'ymscxz':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : (isset($_POST['idsz']) ? $_POST['idsz'] : array());
        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        $ids = array_filter(array_map('intval', $ids));
        if (empty($ids)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $id_list = implode(',', $ids);
        $id_list_escaped2 = $DB->escape($id_list);
        $DB->query("DELETE FROM `ym` WHERE `id` IN ({$id_list_escaped2})");
        logjl(is_admin_login(), '批量删除域名', '删除域名ID: ' . $id_list, true);
        exit(json_encode(array('code' => '删除成功', 'count' => count($ids))));
        break;

    case 'edit_ym':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $id = intval($_POST['id']);
        $ym = daddslashes($_POST['ym']);
        $jg = daddslashes($_POST['jg']);
        $js = daddslashes($_POST['js']);
        $btid = intval($_POST['btid']);

        if ($id <= 0 || empty($ym) || empty($jg)) {
            exit(json_encode(array('code' => '参数错误')));
        }

        $columns = admin_get_table_columns($DB, 'ym');
        $updates = array();
        if (in_array('ym', $columns)) {
            $updates[] = "`ym`='{$ym}'";
        }
        if (in_array('jg', $columns)) {
            $updates[] = "`jg`='{$jg}'";
        }
        if (in_array('js', $columns)) {
            $updates[] = "`js`='{$js}'";
        }
        if (in_array('btid', $columns)) {
            $updates[] = "`btid`='{$btid}'";
        }
        if (empty($updates)) {
            exit(json_encode(array('code' => '表结构不匹配')));
        }
        $id_escaped = $DB->escape($id);
        $DB->query("UPDATE `ym` SET " . implode(',', $updates) . " WHERE `id`='{$id_escaped}'");
        logjl(is_admin_login(), '编辑域名', '编辑域名ID: ' . $id, true);
        exit(json_encode(array('code' => '编辑成功')));
        break;

    case 'exportbt':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $ids = is_array($ids) ? $ids : explode(',', $ids);
        $ids = array_filter(array_map('intval', $ids));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));
        $status = daddslashes(trim(isset($_POST['status']) ? $_POST['status'] : ''));
        $os = daddslashes(trim(isset($_POST['os']) ? $_POST['os'] : ''));

        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="bt_servers_' . date('Ymd_His') . '.csv"');
        $output = fopen('php://output', 'w');
        fwrite($output, "\xEF\xBB\xBF");
        fputcsv($output, array('ID', '宝塔名字', 'IP', '端口', '编号', '操作系统', '状态'));

        $columns = admin_get_table_columns($DB, 'bt');
        $conditions = array();
        if (!empty($ids)) {
            $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
        } elseif (!empty($keyword)) {
            $like_parts = array();
            if (in_array('btmc', $columns)) {
                $like_parts[] = "`btmc` LIKE '%{$keyword}%'";
            }
            if (in_array('ip', $columns)) {
                $like_parts[] = "`ip` LIKE '%{$keyword}%'";
            }
            if (in_array('bzbh', $columns)) {
                $like_parts[] = "`bzbh` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        if ($status !== '' && in_array('jkkg', $columns)) {
            $conditions[] = "`jkkg`='{$status}'";
        }
        if ($os !== '' && in_array('czzt', $columns)) {
            $conditions[] = "`czzt`='{$os}'";
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $res = $DB->query("SELECT * FROM `bt` WHERE {$where} ORDER BY `id` DESC LIMIT 2000");
        while ($row = $DB->fetch($res)) {
            $statusText = isset($row['jkkg']) && $row['jkkg'] == 'true' ? '开启' : '关闭';
            fputcsv($output, array(
                isset($row['id']) ? $row['id'] : '',
                isset($row['btmc']) ? $row['btmc'] : '',
                isset($row['ip']) ? $row['ip'] : '',
                isset($row['dk']) ? $row['dk'] : '',
                isset($row['bzbh']) ? $row['bzbh'] : '',
                isset($row['czzt']) ? $row['czzt'] : '',
                $statusText
            ));
        }
        fclose($output);
        exit;
        break;

    case 'exportzj':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $ids = is_array($ids) ? $ids : explode(',', $ids);
        $ids = array_filter(array_map('intval', $ids));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="hosts_' . date('Ymd_His') . '.csv"');
        $output = fopen('php://output', 'w');
        fwrite($output, "\xEF\xBB\xBF");
        fputcsv($output, array('ID', '用户名', '类型', '网页空间(GB)', '数据库空间(GB)', '流量(GB)', '到期时间', '状态'));

        $columns = admin_get_table_columns($DB, 'zj');
        $conditions = array();
        if (!empty($ids)) {
            $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
        } elseif (!empty($keyword)) {
            $like_parts = array();
            if (in_array('user', $columns)) {
                $like_parts[] = "`user` LIKE '%{$keyword}%'";
            }
            if (in_array('cplx', $columns)) {
                $like_parts[] = "`cplx` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $res = $DB->query("SELECT * FROM `zj` WHERE {$where} ORDER BY `id` DESC LIMIT 2000");
        while ($row = $DB->fetch($res)) {
            fputcsv($output, array(
                isset($row['id']) ? $row['id'] : '',
                isset($row['user']) ? $row['user'] : '',
                isset($row['cplx']) ? $row['cplx'] : '',
                isset($row['wypj']) ? $row['wypj'] : '',
                isset($row['sypj']) ? $row['sypj'] : '',
                isset($row['llxz']) ? $row['llxz'] : '',
                isset($row['dqsj']) ? $row['dqsj'] : '',
                isset($row['zt']) ? $row['zt'] : ''
            ));
        }
        fclose($output);
        exit;
        break;

    case 'exportym':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $ids = is_array($ids) ? $ids : explode(',', $ids);
        $ids = array_filter(array_map('intval', $ids));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="domains_' . date('Ymd_His') . '.csv"');
        $output = fopen('php://output', 'w');
        fwrite($output, "\xEF\xBB\xBF");
        fputcsv($output, array('ID', '域名', '价格', '简介', '所属宝塔'));

        $columns = admin_get_table_columns($DB, 'ym');
        $conditions = array();
        if (!empty($ids)) {
            $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
        } elseif (!empty($keyword)) {
            $like_parts = array();
            if (in_array('ym', $columns)) {
                $like_parts[] = "`ym` LIKE '%{$keyword}%'";
            }
            if (in_array('js', $columns)) {
                $like_parts[] = "`js` LIKE '%{$keyword}%'";
            }
            if (!empty($like_parts)) {
                $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
            }
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $res = $DB->query("SELECT * FROM `ym` WHERE {$where} ORDER BY `id` DESC LIMIT 2000");
        while ($row = $DB->fetch($res)) {
            $bt_ip = '-';
            if (!empty($row['btid'])) {
                $bt_info = $DB->get_row("SELECT `ip` FROM `bt` WHERE `id`='" . intval($row['btid']) . "'");
                $bt_ip = $bt_info ? $bt_info['ip'] : '-';
            }
            fputcsv($output, array(
                isset($row['id']) ? $row['id'] : '',
                isset($row['ym']) ? $row['ym'] : '',
                isset($row['jg']) ? $row['jg'] : '',
                isset($row['js']) ? $row['js'] : '',
                $bt_ip
            ));
        }
        fclose($output);
        exit;
        break;

    case 'bsscxz':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : (isset($_POST['idsz']) ? $_POST['idsz'] : array());
        if (!is_array($ids)) {
            $ids = explode(',', $ids);
        }
        $ids = array_filter(array_map('intval', $ids));
        if (empty($ids)) {
            exit(json_encode(array('code' => '参数错误')));
        }
        $id_list = implode(',', $ids);
        
        // 先获取所有要删除的程序信息
        $id_list_escaped = $DB->escape($id_list);
        $programs = $DB->get_all("SELECT * FROM `bs` WHERE `id` IN ({$id_list_escaped})");
        
        // 删除数据库记录
        $id_list_escaped = $DB->escape($id_list);
        $DB->query("DELETE FROM `bs` WHERE `id` IN ({$id_list_escaped})");
        
        // 删除关联的文件
        if ($programs) {
            foreach ($programs as $bs) {
                // 删除程序源码文件
                if (!empty($bs['wj'])) {
                    $wj_path = $bs['wj'];
                    if (strpos($wj_path, 'programs/') === 0) {
                        $wj_filename = substr($wj_path, 9);
                    } else {
                        $wj_filename = $wj_path;
                    }
                    $file_path = '../uploads/programs/' . $wj_filename;
                    if (file_exists($file_path)) {
                        unlink($file_path);
                    }
                }
                
                // 删除封面图片 (tb字段 - 旧版)
                if (!empty($bs['tb'])) {
                    $tb_path = '../uploads/' . $bs['tb'];
                    if (file_exists($tb_path)) {
                        unlink($tb_path);
                    }
                }
                
                // 删除封面图片 (cover字段 - 新版)
                if (!empty($bs['cover'])) {
                    $cover_path = '../uploads/' . $bs['cover'];
                    if (file_exists($cover_path)) {
                        unlink($cover_path);
                    }
                }
                
                // 删除详情图片
                if (!empty($bs['images'])) {
                    $images = json_decode($bs['images'], true);
                    if (is_array($images)) {
                        foreach ($images as $img) {
                            $img_path = '../uploads/' . $img;
                            if (file_exists($img_path)) {
                                unlink($img_path);
                            }
                        }
                    }
                }
            }
        }
        
        logjl(is_admin_login(), '批量删除程序', '删除程序ID: ' . $id_list, true);
        exit(json_encode(array('code' => '删除成功', 'count' => count($ids))));
        break;

    case 'exportdd':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $ids = is_array($ids) ? $ids : explode(',', $ids);
        $ids = array_filter(array_map('intval', $ids));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));
        $status = daddslashes(trim(isset($_POST['status']) ? $_POST['status'] : ''));
        $payment_method = daddslashes(trim(isset($_POST['payment_method']) ? $_POST['payment_method'] : ''));

        $orders_table_exists = $DB->query("SHOW TABLES LIKE 'orders'");
        $has_orders_table = $orders_table_exists && $DB->num_rows($orders_table_exists) > 0;
        $use_orders = false;
        if ($has_orders_table) {
            if (!empty($ids)) {
                $id_list = implode(',', $ids);
                $id_list_escaped2 = $DB->escape($id_list);
                $count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `orders` WHERE `id` IN ({$id_list_escaped2})");
                $use_orders = $count_row && intval($count_row['cnt']) > 0;
            } else {
                $orders_count_row = $DB->get_row("SELECT COUNT(*) AS cnt FROM `orders`");
                $use_orders = $orders_count_row && intval($orders_count_row['cnt']) > 0;
            }
        }

        header('Content-Type: text/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="orders_' . date('Ymd_His') . '.csv"');
        $output = fopen('php://output', 'w');
        fwrite($output, "\xEF\xBB\xBF");
        fputcsv($output, array('ID', '用户', '订单号', '商品', '金额', '支付方式', '状态', '创建时间'));

        if ($use_orders) {
            $columns = admin_get_table_columns($DB, 'orders');
            $conditions = array();
            if (!empty($ids)) {
                $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
            } elseif (!empty($keyword)) {
                $like_parts = array();
                if (in_array('order_no', $columns)) {
                    $like_parts[] = "`order_no` LIKE '%{$keyword}%'";
                }
                if (in_array('user', $columns)) {
                    $like_parts[] = "`user` LIKE '%{$keyword}%'";
                }
                if (in_array('product_name', $columns)) {
                    $like_parts[] = "`product_name` LIKE '%{$keyword}%'";
                }
                if (!empty($like_parts)) {
                    $conditions[] = '(' . implode(' OR ', $like_parts) . ')';
                }
            }
            if (!empty($status) && in_array('status', $columns)) {
                $conditions[] = "`status`='{$status}'";
            }
            if (!empty($payment_method) && in_array('payment_method', $columns)) {
                $conditions[] = "`payment_method`='{$payment_method}'";
            }
            $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
            $res = $DB->query("SELECT * FROM `orders` WHERE {$where} ORDER BY `create_time` DESC, `id` DESC LIMIT 2000");
            while ($row = $DB->fetch($res)) {
                $user_name = '-';
                if (isset($row['user']) && $row['user'] !== '') {
                    $user_name = $row['user'];
                } elseif (isset($row['user_id'])) {
                    $user_info = $DB->get_row("SELECT `user` FROM `zj` WHERE `id`='" . intval($row['user_id']) . "'");
                    $user_name = $user_info ? $user_info['user'] : '-';
                }
                $product_name = isset($row['product_name']) ? $row['product_name'] : '-';
                fputcsv($output, array(
                    isset($row['id']) ? $row['id'] : '',
                    $user_name,
                    isset($row['order_no']) ? $row['order_no'] : '',
                    $product_name,
                    isset($row['amount']) ? $row['amount'] : '',
                    isset($row['payment_method']) ? $row['payment_method'] : '',
                    isset($row['status']) ? $row['status'] : '',
                    isset($row['create_time']) ? $row['create_time'] : ''
                ));
            }
        } else {
            $dd_table_exists = $DB->query("SHOW TABLES LIKE 'dd'");
            $has_dd_table = $dd_table_exists && $DB->num_rows($dd_table_exists) > 0;
            if ($has_dd_table) {
                $conditions = array();
                if (!empty($ids)) {
                    $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
                } elseif (!empty($keyword)) {
                    $conditions[] = "(`ddh` LIKE '%{$keyword}%' OR `user` LIKE '%{$keyword}%' OR `spname` LIKE '%{$keyword}%')";
                }
                $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
                $res = $DB->query("SELECT * FROM `dd` WHERE {$where} ORDER BY `id` DESC LIMIT 2000");
                while ($row = $DB->fetch($res)) {
                    $product_name = '-';
                    if (isset($row['spname']) && $row['spname'] !== '') {
                        $product_name = $row['spname'];
                    } elseif (isset($row['bsid'])) {
                        $bs_info = $DB->get_row("SELECT `name` FROM `bs` WHERE `id`='" . intval($row['bsid']) . "'");
                        if ($bs_info && !empty($bs_info['name'])) {
                            $product_name = $bs_info['name'];
                        }
                    }
                    fputcsv($output, array(
                        isset($row['id']) ? $row['id'] : '',
                        isset($row['user']) ? $row['user'] : '',
                        isset($row['ddh']) ? $row['ddh'] : '',
                        $product_name,
                        isset($row['jg']) ? $row['jg'] : '',
                        isset($row['zffs']) ? $row['zffs'] : '',
                        isset($row['zt']) ? $row['zt'] : '',
                        isset($row['date']) ? $row['date'] : ''
                    ));
                }
            }
        }
        fclose($output);
        exit;
        break;

    case 'exportbs':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => '请先登录')));
        }
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $ids = is_array($ids) ? $ids : explode(',', $ids);
        $ids = array_filter(array_map('intval', $ids));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));

        // 查询程序数据
        $conditions = array();
        if (!empty($ids)) {
            $conditions[] = "`id` IN (" . implode(',', $ids) . ")";
        } elseif (!empty($keyword)) {
            $conditions[] = "(`name` LIKE '%{$keyword}%' OR `type` LIKE '%{$keyword}%' OR `version` LIKE '%{$keyword}%')";
        }
        $where = empty($conditions) ? '1' : implode(' AND ', $conditions);
        $res = $DB->query("SELECT * FROM `bs` WHERE {$where} ORDER BY `id` DESC LIMIT 2000");
        
        $programs = array();
        while ($row = $DB->fetch($res)) {
            $programs[] = $row;
        }

        if (empty($programs)) {
            exit(json_encode(array('code' => '没有要导出的程序')));
        }

        // 创建临时ZIP文件
        $temp_dir = '../uploads/temp';
        if (!is_dir($temp_dir)) {
            mkdir($temp_dir, 0755, true);
        }
        $zip_file = $temp_dir . '/export_' . time() . '_' . uniqid() . '.zip';
        
        $zip = new ZipArchive();
        if ($zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            exit(json_encode(array('code' => '无法创建ZIP文件')));
        }

        // 准备导出数据
        $export_data = array(
            'export_time' => date('Y-m-d H:i:s'),
            'export_version' => '1.0',
            'program_count' => count($programs),
            'programs' => array()
        );

        foreach ($programs as $program) {
            $prog_data = array(
                'id' => isset($program['id']) ? $program['id'] : '',
                'name' => isset($program['name']) ? $program['name'] : '',
                'type' => isset($program['type']) ? $program['type'] : '',
                'version' => isset($program['version']) ? $program['version'] : '',
                'jg' => isset($program['jg']) ? $program['jg'] : '',
                'js' => isset($program['js']) ? $program['js'] : '',
                'webkj' => isset($program['webkj']) ? $program['webkj'] : '0',
                'sqlkj' => isset($program['sqlkj']) ? $program['sqlkj'] : '0',
                'php_version' => isset($program['php_version']) ? $program['php_version'] : '',
                'php_ext' => isset($program['php_ext']) ? $program['php_ext'] : '',
                'alerts' => isset($program['alerts']) ? $program['alerts'] : '',
                'status' => isset($program['status']) ? $program['status'] : 1,
                'form_fields' => isset($program['form_fields']) ? $program['form_fields'] : '',
                'install_ops' => isset($program['install_ops']) ? $program['install_ops'] : '',
                'pz' => isset($program['pz']) ? $program['pz'] : '',
                'ybd' => isset($program['ybd']) ? $program['ybd'] : '',
                'pzsj' => isset($program['pzsj']) ? $program['pzsj'] : '',
                'wcts' => isset($program['wcts']) ? $program['wcts'] : '',
                'tb' => '',
                'cover' => '',
                'wj' => '',
                'images' => '[]'
            );

            // 处理封面图片 (tb/cover)
            $cover_file = !empty($program['tb']) ? $program['tb'] : (!empty($program['cover']) ? $program['cover'] : '');
            if (!empty($cover_file)) {
                $cover_path = '../uploads/' . $cover_file;
                if (file_exists($cover_path)) {
                    $cover_ext = pathinfo($cover_file, PATHINFO_EXTENSION);
                    $new_cover_name = 'cover_' . $program['id'] . '_' . time() . '.' . $cover_ext;
                    $zip->addFile($cover_path, 'images/' . $new_cover_name);
                    $prog_data['tb'] = 'images/' . $new_cover_name;
                    $prog_data['cover'] = 'images/' . $new_cover_name;
                }
            }

            // 处理程序包文件 (wj)
            if (!empty($program['wj'])) {
                $wj_file = $program['wj'];
                // 处理路径前缀
                if (strpos($wj_file, 'programs/') === 0) {
                    $wj_path = '../uploads/' . $wj_file;
                    $wj_filename = substr($wj_file, 9);
                } else {
                    $wj_path = '../uploads/programs/' . $wj_file;
                    $wj_filename = $wj_file;
                }
                
                if (file_exists($wj_path)) {
                    $wj_ext = pathinfo($wj_filename, PATHINFO_EXTENSION);
                    $new_wj_name = 'program_' . $program['id'] . '_' . time() . '.' . $wj_ext;
                    $zip->addFile($wj_path, 'programs/' . $new_wj_name);
                    $prog_data['wj'] = 'programs/' . $new_wj_name;
                }
            }

            // 处理展示图片 (images)
            if (!empty($program['images'])) {
                $images = json_decode($program['images'], true);
                if (is_array($images)) {
                    $new_images = array();
                    foreach ($images as $index => $img) {
                        $img_path = '../uploads/' . $img;
                        if (file_exists($img_path)) {
                            $img_ext = pathinfo($img, PATHINFO_EXTENSION);
                            $new_img_name = 'image_' . $program['id'] . '_' . $index . '_' . time() . '.' . $img_ext;
                            $zip->addFile($img_path, 'images/' . $new_img_name);
                            $new_images[] = 'images/' . $new_img_name;
                        }
                    }
                    $prog_data['images'] = json_encode($new_images, JSON_UNESCAPED_UNICODE);
                }
            }

            $export_data['programs'][] = $prog_data;
        }

        // 添加programs.json到ZIP
        $zip->addFromString('programs.json', json_encode($export_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
        $zip->close();

        // 输出ZIP文件
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="programs_' . date('Ymd_His') . '.zip"');
        header('Content-Length: ' . filesize($zip_file));
        readfile($zip_file);
        
        // 删除临时文件
        @unlink($zip_file);
        
        logjl(is_admin_login(), '导出程序', "导出 " . count($programs) . " 个程序", true);
        exit;
        break;
        
    case 'publish_announcement':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => -1, 'msg' => '请先登录')));
        }
        
        // 验证CSRF Token
        $csrf_token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : '';
        if (!hash_equals($_SESSION['csrf_token'], $csrf_token)) {
            exit(json_encode(array('code' => -1, 'msg' => 'CSRF验证失败')));
        }
        
        $title = daddslashes($_POST['title']);
        $content = daddslashes($_POST['content']);
        $category = isset($_POST['category']) ? $_POST['category'] : 'general';
        $target_type = daddslashes($_POST['target_type']);
        $target_bt = isset($_POST['target_bt']) ? intval($_POST['target_bt']) : 0;
        $is_active = daddslashes($_POST['is_active']);
        
        // 验证分类参数
        $allowed_categories = array('general', 'maintenance', 'update', 'important', 'activity');
        if (!in_array($category, $allowed_categories)) {
            $category = 'general';
        }
        
        if (empty($title) || empty($content)) {
            exit(json_encode(array('code' => 0, 'msg' => '标题和内容不能为空')));
        }
        
        // 创建公告记录（作为模板）
        $category_escaped = $DB->escape($category);
        $target_type_escaped = $DB->escape($target_type);
        $target_bt_escaped = intval($target_bt);
        $title_escaped = $DB->escape($title);
        $content_escaped = $DB->escape($content);
        $DB->query("INSERT INTO `notifications` (`user_id`, `type`, `category`, `target_type`, `target_bt`, `title`, `content`, `is_read`, `create_time`) VALUES (0, 'announcement', '{$category_escaped}', '{$target_type_escaped}', {$target_bt_escaped}, '{$title_escaped}', '{$content_escaped}', 0, NOW())");
        $notification_id = $DB->insert_id();
        
        // 为所有用户创建通知记录
        if ($target_type == 'all') {
            $all_zj = $DB->query("SELECT id FROM `zj`");
            while ($zj = $DB->fetch($all_zj)) {
                $category_escaped = $DB->escape($category);
                $target_type_escaped = $DB->escape($target_type);
                $target_bt_escaped = intval($target_bt);
                $title_escaped = $DB->escape($title);
                $content_escaped = $DB->escape($content);
                $DB->query("INSERT INTO `notifications` (`user_id`, `type`, `category`, `target_type`, `target_bt`, `title`, `content`, `is_read`, `create_time`) VALUES ({$zj['id']}, 'announcement', '{$category_escaped}', '{$target_type_escaped}', {$target_bt_escaped}, '{$title_escaped}', '{$content_escaped}', 0, NOW())");
            }
        }
        // 为指定宝塔服务器下的所有用户创建通知记录
        elseif ($target_type == 'bt_server' && !empty($target_bt)) {
            $bt_zj = $DB->query("SELECT id FROM `zj` WHERE btid=" . intval($target_bt));
            while ($zj = $DB->fetch($bt_zj)) {
                $category_escaped = $DB->escape($category);
                $target_type_escaped = $DB->escape($target_type);
                $target_bt_escaped = intval($target_bt);
                $title_escaped = $DB->escape($title);
                $content_escaped = $DB->escape($content);
                $DB->query("INSERT INTO `notifications` (`user_id`, `type`, `category`, `target_type`, `target_bt`, `title`, `content`, `is_read`, `create_time`) VALUES ({$zj['id']}, 'announcement', '{$category_escaped}', '{$target_type_escaped}', {$target_bt_escaped}, '{$title_escaped}', '{$content_escaped}', 0, NOW())");
            }
        }
        
        logjl(is_admin_login(), '发布公告', '发布公告: ' . $title . ' (分类: ' . $category . ')', true);
        exit(json_encode(array('code' => 1, 'msg' => '公告发布成功')));
        break;
        
    case 'delete_announcement':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 0, 'msg' => '请先登录')));
        }
        
        // 验证CSRF Token
        $csrf_token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : '';
        if (!hash_equals($_SESSION['csrf_token'], $csrf_token)) {
            exit(json_encode(array('code' => -1, 'msg' => 'CSRF验证失败')));
        }
        
        $id = intval($_POST['id']);
        
        // 验证公告是否存在且是模板
        $id_escaped = intval($id);
        $notif = $DB->get_row("SELECT * FROM `notifications` WHERE id={$id_escaped} AND user_id=0");
        if (!$notif) {
            exit(json_encode(array('code' => 0, 'msg' => '公告不存在')));
        }
        
        // 删除公告模板及所有用户的通知记录
        $DB->query("DELETE FROM `notifications` WHERE title='" . $notif['title'] . "' AND content='" . $notif['content'] . "'");
        
        logjl(is_admin_login(), '删除公告', '删除公告ID: ' . $id, true);
        exit(json_encode(array('code' => 1, 'msg' => '公告删除成功')));
        break;
        
    case 'edit_announcement':
        if (!is_admin_login()) {
            exit(json_encode(array('code' => 0, 'msg' => '请先登录')));
        }
        
        // 验证CSRF Token
        $csrf_token = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : '';
        if (!hash_equals($_SESSION['csrf_token'], $csrf_token)) {
            exit(json_encode(array('code' => -1, 'msg' => 'CSRF验证失败')));
        }
        
        $id = intval($_POST['id']);
        $title = daddslashes($_POST['title']);
        $category = isset($_POST['category']) ? $_POST['category'] : 'general';
        $content = daddslashes($_POST['content']);
        
        // 验证分类参数
        $allowed_categories = array('general', 'maintenance', 'update', 'important', 'activity');
        if (!in_array($category, $allowed_categories)) {
            $category = 'general';
        }
        
        if (empty($title) || empty($content)) {
            exit(json_encode(array('code' => 0, 'msg' => '标题和内容不能为空')));
        }
        
        // 先获取原公告信息
        $id_escaped = intval($id);
        $notif = $DB->get_row("SELECT * FROM `notifications` WHERE id={$id_escaped} AND user_id=0");
        if (!$notif) {
            exit(json_encode(array('code' => 0, 'msg' => '公告不存在或不是模板')));
        }
        
        // 更新公告模板（user_id=0）
        $title_escaped = $DB->escape($title);
        $category_escaped = $DB->escape($category);
        $content_escaped = $DB->escape($content);
        $id_escaped = intval($id);
        $DB->query("UPDATE `notifications` SET title='{$title_escaped}', category='{$category_escaped}', content='{$content_escaped}' WHERE id={$id_escaped} AND user_id=0");
        
        // 同步更新所有用户收到的相同公告
        $title_escaped = $DB->escape($title);
        $category_escaped = $DB->escape($category);
        $content_escaped = $DB->escape($content);
        $DB->query("UPDATE `notifications` SET title='{$title_escaped}', category='{$category_escaped}', content='{$content_escaped}' WHERE title='" . $notif['title'] . "' AND content='" . $notif['content'] . "'");
        
        logjl(is_admin_login(), '编辑公告', '编辑公告ID: ' . $id . ' (分类: ' . $category . ')', true);
        exit(json_encode(array('code' => 1, 'msg' => '公告修改成功')));
        break;
        
    case 'activate_auth':
        // 激活授权
        require_once __DIR__ . '/../MPHX/AuthManager.php';
        $auth_code = daddslashes($_POST['auth_code'] ?? '');
        
        if (empty($auth_code)) {
            exit(json_encode(array('code' => 400, 'message' => '请输入授权码')));
        }
        
        try {
            $authManager = new AuthManager($DB);
            $result = $authManager->activate($auth_code);
            
            if ($result['code'] == 200) {
                logjl(is_admin_login(), '激活授权', '使用授权码激活成功: ' . $auth_code, true);
                exit(json_encode(array('code' => 200, 'message' => '授权激活成功')));
            } else {
                exit(json_encode(array('code' => $result['code'], 'message' => $result['message'] ?? '激活失败')));
            }
        } catch (Exception $e) {
            exit(json_encode(array('code' => 500, 'message' => '激活失败: ' . $e->getMessage())));
        }
        break;
        
    case 'refresh_auth':
        // 刷新授权 - 只验证现有token，不重新申请
        require_once __DIR__ . '/../MPHX/AuthManager.php';
        
        try {
            $authManager = new AuthManager($DB);
            // 使用refreshAuth方法，会验证现有token或刷新，不会重新申请试用
            $result = $authManager->refreshAuth();
            
            if ($result['code'] == 200) {
                logjl(is_admin_login(), '刷新授权', '授权状态刷新成功', true);
                exit(json_encode(array('code' => 200, 'message' => '授权刷新成功')));
            } else {
                exit(json_encode(array('code' => $result['code'], 'message' => $result['message'] ?? '刷新失败')));
            }
        } catch (Exception $e) {
            exit(json_encode(array('code' => 500, 'message' => '刷新失败: ' . $e->getMessage())));
        }
        break;
        
    case 'reapply_auth':
        // 重新申请授权 - 清除本地记录并重新申请试用
        require_once __DIR__ . '/../MPHX/AuthManager.php';
        
        try {
            $authManager = new AuthManager($DB);
            // 先清除本地授权记录
            $authManager->clearAuth();
            // 然后重新申请试用
            $result = $authManager->applyTrial();
            
            if ($result['code'] == 200) {
                logjl(is_admin_login(), '重新申请授权', '试用授权申请成功', true);
                exit(json_encode(array('code' => 200, 'message' => '试用授权申请成功')));
            } else {
                exit(json_encode(array('code' => $result['code'], 'message' => $result['message'] ?? '申请失败')));
            }
        } catch (Exception $e) {
            exit(json_encode(array('code' => 500, 'message' => '申请失败: ' . $e->getMessage())));
        }
        break;
        
    case 'query_domain_auth':
        // 查询当前域名的授权状态
        require_once __DIR__ . '/../MPHX/AuthManager.php';
        
        try {
            $authManager = new AuthManager($DB);
            $domain = $authManager->getDomain();
            
            // 从授权站查询该域名的授权信息
            $result = $authManager->queryDomainAuth($domain);
            
            if ($result['code'] == 200 && !empty($result['data'])) {
                exit(json_encode(array(
                    'code' => 200,
                    'domain' => $result['data']['domain'] ?? $domain,
                    'is_trial' => $result['data']['is_trial'] ?? true,
                    'expire_time' => $result['data']['expire_time'] ?? '',
                    'remain_seconds' => $result['data']['remain_seconds'] ?? 0,
                    'message' => '查询成功'
                )));
            } else {
                exit(json_encode(array(
                    'code' => 404,
                    'message' => '未找到该域名的授权记录'
                )));
            }
        } catch (Exception $e) {
            exit(json_encode(array('code' => 500, 'message' => '查询失败: ' . $e->getMessage())));
        }
        break;
        
    case 'listlog':
        // 获取日志列表
        if (!is_admin_login()) {
            exit(json_encode(array('total' => 0, 'rows' => array(), 'code' => '请先登录')));
        }
        
        $page = max(1, intval(isset($_POST['page']) ? $_POST['page'] : 1));
        $limit = intval(isset($_POST['limit']) ? $_POST['limit'] : 10);
        if ($limit <= 0) $limit = 10;
        if ($limit > 100) $limit = 100;
        $offset = ($page - 1) * $limit;
        
        $type = daddslashes(trim(isset($_POST['type']) ? $_POST['type'] : ''));
        $keyword = daddslashes(trim(isset($_POST['keyword']) ? $_POST['keyword'] : ''));
        
        $rows = array();
        $total = 0;
        
        if ($type === 'host') {
            // 开通日志 - 使用 host_log 表
            $where = "WHERE 1=1";
            if (!empty($keyword)) {
                $where .= " AND (user LIKE '%{$keyword}%' OR hostname LIKE '%{$keyword}%' OR package LIKE '%{$keyword}%')";
            }
            
            $count_res = $DB->query("SELECT COUNT(*) as total FROM `host_log` {$where}");
            if ($count_res) {
                $total = intval($DB->fetch($count_res)['total']);
            }
            
            $res = $DB->query("SELECT * FROM `host_log` {$where} ORDER BY date DESC LIMIT {$offset}, {$limit}");
            if ($res) {
                while ($row = $DB->fetch($res)) {
                    $rows[] = array(
                        'id' => $row['id'],
                        'user' => $row['user'],
                        'lx' => $row['action'],
                        'hostname' => $row['hostname'],
                        'package' => $row['package'],
                        'price' => $row['price'],
                        'duration' => $row['duration'],
                        'ip' => $row['ip'],
                        'date' => $row['date']
                    );
                }
            }
        } else {
            // 其他日志 - 使用 log 表，根据类型筛选
            $where = "WHERE 1=1";
            
            // 根据类型筛选（如果指定了类型且不是空值）
            if ($type === 'admin') {
                // 管理员日志 - 显示所有记录（管理员操作的所有日志）
                // 不再限制特定关键字，显示所有日志
            } elseif ($type === 'user') {
                // 用户日志 - 显示非admin用户的操作
                $where .= " AND user != 'admin'";
            } elseif ($type === 'api') {
                // API调用日志 - 只显示API连接、开通、删除、暂停虚拟空间的相关信息
                $where .= " AND (lr LIKE '%连接成功%' OR lr LIKE '%API添加主机%' OR lr LIKE '%API删除主机%' OR lr LIKE '%API暂停主机%' OR lr LIKE '%API解封主机%')";
            }
            
            if (!empty($keyword)) {
                $where .= " AND (user LIKE '%{$keyword}%' OR lx LIKE '%{$keyword}%' OR lr LIKE '%{$keyword}%')";
            }
            
            $count_res = $DB->query("SELECT COUNT(*) as total FROM `log` {$where}");
            if ($count_res) {
                $total = intval($DB->fetch($count_res)['total']);
            }
            
            $res = $DB->query("SELECT * FROM `log` {$where} ORDER BY date DESC LIMIT {$offset}, {$limit}");
            if ($res) {
                while ($row = $DB->fetch($res)) {
                    $rows[] = array(
                        'id' => $row['id'],
                        'user' => $row['user'],
                        'lx' => $row['lx'],
                        'lr' => $row['lr'],
                        'ip' => $row['ip'],
                        'date' => $row['date']
                    );
                }
            }
        }
        
        exit(json_encode(array('total' => $total, 'rows' => $rows)));
        break;
        
    case 'deletelog':
        // 删除单条日志
        if (!is_admin_login()) {
            exit(json_encode(array('code' => -1, 'message' => '请先登录')));
        }
        
        $id = intval(isset($_POST['id']) ? $_POST['id'] : 0);
        $type = daddslashes(trim(isset($_POST['type']) ? $_POST['type'] : ''));
        
        if ($id <= 0) {
            exit(json_encode(array('code' => -1, 'message' => '参数错误')));
        }
        
        if ($type === 'host') {
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `host_log` WHERE id='{$id_escaped}'");
        } else {
            $id_escaped = $DB->escape($id);
            $DB->query("DELETE FROM `log` WHERE id='{$id_escaped}'");
        }
        
        $affected = $DB->affected();
        if ($affected > 0) {
            logjl(is_admin_login(), '删除日志', '删除日志ID: ' . $id . ' (类型: ' . $type . ')', true);
            exit(json_encode(array('code' => 0, 'message' => '删除成功')));
        } else {
            exit(json_encode(array('code' => -1, 'message' => '删除失败：记录不存在或已被删除')));
        }
        break;
        
    case 'batch_deletelog':
        // 批量删除日志
        if (!is_admin_login()) {
            exit(json_encode(array('code' => -1, 'message' => '请先登录')));
        }
        
        $ids = isset($_POST['ids']) ? $_POST['ids'] : '';
        $type = daddslashes(trim(isset($_POST['type']) ? $_POST['type'] : ''));
        
        if (empty($ids)) {
            exit(json_encode(array('code' => -1, 'message' => '请选择要删除的日志')));
        }
        
        $id_array = explode(',', $ids);
        $id_array = array_filter(array_map('intval', $id_array));
        
        if (empty($id_array)) {
            exit(json_encode(array('code' => -1, 'message' => '参数错误')));
        }
        
        $id_list = implode(',', $id_array);
        
        if ($type === 'host') {
            $id_list_escaped = $DB->escape($id_list);
            $DB->query("DELETE FROM `host_log` WHERE id IN ({$id_list_escaped})");
        } else {
            $id_list_escaped = $DB->escape($id_list);
            $DB->query("DELETE FROM `log` WHERE id IN ({$id_list_escaped})");
        }
        
        $affected = $DB->affected();
        if ($affected > 0) {
            logjl(is_admin_login(), '批量删除日志', '删除日志ID: ' . $id_list . ' (类型: ' . $type . ')', true);
            exit(json_encode(array('code' => 0, 'message' => '删除成功', 'count' => $affected)));
        } else {
            exit(json_encode(array('code' => -1, 'message' => '删除失败：记录不存在或已被删除')));
        }
        break;
        
    case 'clearlog':
        // 清空全部日志
        if (!is_admin_login()) {
            exit(json_encode(array('code' => -1, 'message' => '请先登录')));
        }
        
        $type = daddslashes(trim(isset($_POST['type']) ? $_POST['type'] : ''));
        
        if ($type === 'host') {
            // 清空开通日志
            $DB->query("TRUNCATE TABLE `host_log`");
            logjl(is_admin_login(), '清空日志', '清空所有开通日志', true);
        } else {
            // 根据类型清空对应日志（与listlog查询逻辑保持一致）
            $where = "WHERE 1=1";
            if ($type === 'admin') {
                // 管理员日志 - 清空所有记录
                // 不再限制特定关键字，清空所有日志
            } elseif ($type === 'user') {
                // 用户日志 - 清空非admin用户的操作
                $where .= " AND user != 'admin'";
            } elseif ($type === 'api') {
                // API调用日志
                $where .= " AND (lr LIKE '%连接成功%' OR lr LIKE '%API添加主机%' OR lr LIKE '%API删除主机%' OR lr LIKE '%API暂停主机%' OR lr LIKE '%API解封主机%')";
            } else {
                // 清空全部普通日志
                $where = "";
            }
            
            if (empty($where)) {
                $DB->query("TRUNCATE TABLE `log`");
            } else {
                $DB->query("DELETE FROM `log` {$where}");
            }
            logjl(is_admin_login(), '清空日志', '清空日志 (类型: ' . $type . ')', true);
        }
        
        $affected = $DB->affected();
        exit(json_encode(array('code' => 0, 'message' => '清空成功', 'count' => $affected)));
        break;
        
    default:
        exit('{"code":"功能代码错误"}');
}
?>
