<?php
@header('Content-Type: application/json; charset=UTF-8');
include(dirname(__DIR__) . '/includes/common.php');
if (is_file(dirname(__DIR__) . '/includes/node_link_helper.php')) {
	include_once dirname(__DIR__) . '/includes/node_link_helper.php';
}
if($islogin2!=1)exit('{"code":-1,"msg":"未登录，鉴权失败"}');
$act=isset($_GET['act'])?daddslashes($_GET['act']):null;

/** 按相对 ROOT 的文件路径，递归创建所在目录并检查可写 */
function ensure_user_upload_dir($relativePath) {
	$dir = dirname(ROOT . $relativePath);
	if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
		return false;
	}
	return is_dir($dir) && is_writable($dir);
}

/**
 * 业务通知（充值余额/消费余额/在线购买）
 * 配置来源：admin/mail.php
 */
function send_user_business_notice($scene, $vars = []){
	global $conf, $userrow, $date;
	$scenes = [
		'recharge' => ['switch' => 'notice_recharge', 'tpl' => 'notice_recharge_tpl', 'title' => '充值余额提示'],
		'consume' => ['switch' => 'notice_consume', 'tpl' => 'notice_consume_tpl', 'title' => '消费余额提示'],
		'online_buy' => ['switch' => 'notice_online_buy', 'tpl' => 'notice_online_buy_tpl', 'title' => '在线购买提示'],
	];
	if(!isset($scenes[$scene])) return ['code' => 0, 'msg' => 'scene invalid'];
	$cfg = $scenes[$scene];
	$notice_type = intval($conf[$cfg['switch']] ?? 0);
	if($notice_type <= 0) return ['code' => 0, 'msg' => 'notice off'];

	$default_tpl = [
		'recharge' => '<h2 style="font-weight:bold;margin-bottom:5px;font-size:14px;">尊贵的用户，您好！</h2><p style="padding-left:2em;margin:0">【[站点名称]】充值余额提醒<br>用户：[用户账号](ID:[用户ID])<br>产品版本：[产品版本]<br>金额：[金额]元<br>变动后余额：[余额]元<br>说明：[说明]</p>',
		'consume' => '<h2 style="font-weight:bold;margin-bottom:5px;font-size:14px;">尊贵的用户，您好！</h2><p style="padding-left:2em;margin:0">【[站点名称]】消费余额提醒<br>用户：[用户账号](ID:[用户ID])<br>产品版本：[产品版本]<br>购买商品：[商品]<br>购买QQ：[QQ]<br>金额：[金额]元<br>变动后余额：[余额]元<br>说明：[说明]</p>',
		'online_buy' => '<h2 style="font-weight:bold;margin-bottom:5px;font-size:14px;">尊贵的用户，您好！</h2><p style="padding-left:2em;margin:0">【[站点名称]】在线购买提醒<br>用户：[用户账号](ID:[用户ID])<br>产品版本：[产品版本]<br>购买商品：[商品]<br>购买QQ：[QQ]<br>金额：[金额]元<br>支付方式：[支付方式]</p>'
	];
	$template = trim((string)($conf[$cfg['tpl']] ?? ''));
	if($template === '') $template = $default_tpl[$scene];
	// 防串模版：如果配置内容明显属于其它场景，则自动回退对应默认模板
	if($scene === 'recharge' && strpos($template, '[订单号]') !== false){
		$template = $default_tpl['recharge'];
	}elseif($scene === 'online_buy' && strpos($template, '[说明]') !== false && strpos($template, '[订单号]') === false){
		$template = $default_tpl['online_buy'];
	}

	$version_map = [
		'cloud' => (string)($conf['version_name_cloud'] ?? '云端版'),
		'qzone' => (string)($conf['version_name_qzone'] ?? '秒赞版'),
		'all' => (string)($conf['version_name_all'] ?? '通用版'),
	];
	$raw_version = strtolower(trim((string)($vars['version'] ?? '')));
	if(isset($version_map[$raw_version])){
		$version_text = $version_map[$raw_version];
	}else{
		$version_text = trim((string)($vars['version'] ?? ''));
		if($version_text === '') $version_text = '-';
	}
	$replace = [
		'[站点名称]' => (string)($conf['sitename'] ?? ''),
		'[用户ID]' => (string)($userrow['zid'] ?? ''),
		'[用户账号]' => (string)($userrow['user'] ?? ''),
		'[产品版本]' => $version_text,
		'[金额]' => (string)($vars['amount'] ?? ''),
		'[余额]' => (string)($vars['balance'] ?? ''),
		'[订单号]' => (string)($vars['trade_no'] ?? ''),
		'[商品]' => (string)($vars['goods'] ?? ''),
		'[QQ]' => (string)($vars['qq'] ?? ''),
		'[支付方式]' => (string)($vars['pay_type'] ?? ''),
		'[说明]' => (string)($vars['remark'] ?? ''),
		'[时间]' => (string)$date,
	];
	$content = strtr($template, $replace);
	$title = $cfg['title'];

	if($notice_type == 1){
		// 发给“当前用户”邮箱：优先用户绑定邮箱，其次QQ邮箱
		$user_mail = trim((string)($userrow['email'] ?? ''));
		if($user_mail === '' && !empty($userrow['qq'])){
			$user_mail = trim((string)$userrow['qq']).'@qq.com';
		}
		if($user_mail === '') return ['code' => -1, 'msg' => 'user email empty'];
		return \lib\MessageSend::send($user_mail, $title, $title, $content, $conf['sitename'] ?? '系统通知');
	}elseif($notice_type == 2){
		// 发给“当前用户”手机号
		if(empty($userrow['phone'])) return ['code' => -1, 'msg' => 'user phone empty'];
		$sms_content = str_replace(['<br />', '<br/>', '<br>'], "\n", $content);
		$sms_content = preg_replace('/\s+/', ' ', trim(strip_tags($sms_content)));
		return send_sms($userrow['phone'], $sms_content);
	}elseif($notice_type == 3){
		// 发给“当前用户”微信UID
		if(empty($userrow['wechat_appuid'])) return ['code' => -1, 'msg' => 'user wechat_appuid empty'];
		return send_wx($content, $title, 1, [], [$userrow['wechat_appuid']]);
	}
	return ['code' => 0, 'msg' => 'unsupported channel'];
}

switch($act){
case 'recharge_km':
	$km = daddslashes($_POST['km']);
	$kmrow = $DB->getRow("SELECT * FROM `pre_km` WHERE km='{$km}' LIMIT 1");
	if(!$kmrow)exit('{"code":-1,"msg":"卡密不存在"}');
	if($kmrow['isuse'] == '1')exit('{"code":-1,"msg":"该卡密已经被使用"}');
	if($kmrow['zid'] == 1 && $kmrow['shopid'] == '0'){
		$sql = "UPDATE `pre_user` SET `rmb`=`rmb`+'{$kmrow['rmb']}' WHERE zid='{$userrow['zid']}'";
		if($DB->exec($sql)){
			$DB->exec("UPDATE `pre_km` SET `isuse`='1',`qq`='用户账号：{$userrow['user']}',`usetime`=now() WHERE id='{$kmrow['id']}'");
			add_money_log($userrow['zid'],'卡密','卡密余额',$kmrow['rmb'],$userrow['rmb'],($userrow['rmb']+$kmrow['rmb']),'卡密方式充值'.$kmrow['rmb'].'元余额');
			send_user_business_notice('recharge', [
				'amount' => $kmrow['rmb'],
				'balance' => $userrow['rmb'] + $kmrow['rmb'],
				'remark' => '卡密方式充值'
			]);
			exit('{"code":1,"msg":"加款成功"}');
		}
	}
	exit('{"code":-1,"msg":"卡密类型不正确"}');
break;
case 'tc_to_rmb':
	if($conf['tc_to_rmb'] != 1)exit('{"code":-1,"msg":"未开启 佣金转余额"}');
	$tc = floatval($_POST['tc']);
	if(!is_numeric($tc) || !preg_match('/^[0-9.]+$/', $tc))exit('{"code":-1,"msg":"金额输入不规范"}');
	if(strripos($tc,'.')){
		$arr = explode('.',$tc);
		if(count($arr)>1 && mb_strlen($arr[1])>2){
			exit('{"code":-1,"msg":"金额小数点只能输入两位如：0.00"}');
		}
	}
	if($tc > $userrow['rmb_tc'])exit('{"code":-1,"msg":"佣金不足！"}');
	$_tc = floatval($userrow['rmb_tc']) - $tc;
	$rmb = floatval($userrow['rmb']) + $tc;
	$sql = "UPDATE `pre_user` SET `rmb_tc`='{$_tc}',`rmb`='{$rmb}' WHERE zid='{$userrow['zid']}'";
	if($DB->exec($sql)){
		add_money_log($userrow['zid'],'佣金','佣金转余额',$tc,$userrow['rmb_tc'],($userrow['rmb_tc']-$tc),'佣金转到余额 '.$tc.'元');
		add_money_log($userrow['zid'],'余额','收到余额',$tc,$userrow['rmb'],($userrow['rmb']+$tc),'收到余额 '.$tc.'元');
		send_user_business_notice('recharge', [
			'amount' => $tc,
			'balance' => $rmb,
			'remark' => '佣金转余额'
		]);

		exit('{"code":1,"msg":"转移成功","tc":"'.$_tc.'","rmb":"'.$rmb.'"}');
	}else{
		exit('{"code":-1,"msg":"转移失败'.$DB->error().'"}');
	}
break;
case 'kami_qk':
	$type = intval($_POST['kami_qk_type']);
	if($type == 1){
		$DB->exec("DELETE FROM `pre_km` WHERE isuse='1' AND zid='{$userrow['zid']}'");
	}else{//清空-并退回余额
		$q_rmb = $userrow['rmb'];
		$rs=$DB->query("SELECT * FROM pre_km WHERE zid='{$userrow['zid']}'");
		while($res = $rs->fetch()){
			if($DB->exec("DELETE FROM `pre_km` WHERE zid='{$userrow['zid']}' AND id='{$res['id']}'") && $res['isuse'] == '0'){
				$DB->exec("UPDATE `pre_user` SET `rmb`=`rmb`+'{$res['rmb']}' WHERE zid='{$userrow['zid']}'");
				add_money_log($userrow['zid'],'余额','退款',$res['rmb'],$q_rmb,($q_rmb+$res['rmb']),'管理员删除卡密:'.$res['km'].'退回'.$res['rmb'].'元');
				$q_rmb = $q_rmb+$res['rmb'];
			}
		}
	}
	exit('{"code":1,"msg":"操作成功"}');
break;
case 'get_WxPusher_qr':
	$wechat_apptoken = $conf['wechat_apptoken'];
	if($wechat_apptoken == '')exit('{"code":-1,"msg":"主站未配置好微信通知token"}');
	$post = '{"appToken":"'.$wechat_apptoken.'","extra":"'.time().'","validTime":600}';
	$ret = get_curl2('https://wxpusher.zjiecode.com/api/fun/create/qrcode',$post,0,['Content-Type: application/json']);
	exit($ret);
break;
case 'del_time'://删除QQ代挂时长
	$id = intval($_POST['id']);
	$cids = intval($_POST['cids']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
    $row = $DB->getRow("SELECT * FROM `{$qq_table}` WHERE id='{$id}' AND zid='{$userrow['zid']}' LIMIT 1");
    if(!$row)exit('{"code":-1,"msg":"数据不存在"}');
	$arr = json_decode($row['endtime_arr'],true);
	if(!is_array($arr)) $arr = [];

	if($cids >= 1000 && isset($arr[$cids]) && $arr[$cids] > $date){
		exit('{"code":-1,"msg":"该分类商品还没有过期，不能删除"}');
	}

	$sim = $arr;
	unset($sim[$cids]);
	if($cids < 1000 && !isset($sim['1000'])){
		$sim['1000'] = $date;
	}
	if(count($sim) < 1){
		exit('{"code":-1,"msg":"最少保留一个分类"}');
	}

	unset($arr[$cids]);
	if($cids < 1000 && !isset($arr['1000'])){
		$arr['1000'] = $date;
	}
	$t = json_encode($arr);
	$DB->exec("UPDATE {$qq_table} SET endtime_arr='".$t."' WHERE id='{$id}'");
	exit('{"code":1,"msg":"操作成功"}');
break;
case 'set_qq_config':
	$id=intval($_POST['id']);
	$type=daddslashes($_POST['type']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$sql = "";
	if($type == 'dropline'){
		$zt=intval($_POST['zt'])==1?0:1;
		$sql = "UPDATE {$qq_table} SET dropline='{$zt}' WHERE id='{$id}'";
	}elseif($type == 'online'){
		$zt=intval($_POST['zt'])==0?1:0;
		$sql = "UPDATE {$qq_table} SET online='{$zt}' WHERE id='{$id}'";
	}
	$DB->exec($sql);
	exit('{"code":1,"msg":"操作成功"}');
	if($sql = "")exit('{"code":-1,"msg":"error"}');
break;
case 'edit_phone':
    $phone=daddslashes($_POST['phone']);
    $code=daddslashes($_POST['code']);
    $tmptime = date('Y-m-d H:i:s',strtotime('-5minute'));
    $is = $DB->getRow("SELECT * FROM `pre_logs` WHERE type='短信' AND result2='{$phone}' AND addtime>'".$tmptime."' ORDER BY addtime DESC LIMIT 1");
    if(!$is)exit('{"code":-1,"msg":"短信验证码过期"}');
    if($is['result'] != $code){
        exit('{"code":-1,"msg":"手机短信验证码错误"}');
    }
	$DB->exec("UPDATE pre_user SET phone='{$phone}' WHERE zid='{$userrow['zid']}'");
	exit('{"code":1,"msg":"绑定成功"}');
break;
case 'edit_phone_check':
    $phone=daddslashes($_POST['phone']);
    $key=daddslashes($_POST['key']);
    if(strlen($phone)!=11)exit('{"code":-1,"msg":"请填写正确的手机号码！"}');
    if($key=='')exit('{"code":-1,"msg":"秘钥不能为空"}');
    if(strlen($key)!=32)exit('{"code":-1,"msg":"秘钥不正确"}');
    if($_SESSION["check_key"] != $key)exit('{"code":-1,"msg":"验证失败，请刷新网页"}');
    $is = $DB->getRow("SELECT * FROM `pre_logs` WHERE type='短信' AND result2='{$phone}' ORDER BY addtime DESC LIMIT 1");
    if($is && $is['result3'] > time()-60){
        exit('{"code":-1,"msg":"1分钟内不可以重复发送短信。"}');
    }
    $row = $DB->getRow("SELECT * FROM `pre_user` WHERE phone='{$phone}' LIMIT 1");
    if($row)exit('{"code":-1,"msg":"该手机号码已经被绑定了"}');
    $code = random(6,1);
    $ret = send_sms($phone, '您的验证码为：'.$code.'，有效期5分钟。');
    if($ret['code'] == 1){
        unset($_SESSION['check_key']);
        $DB->exec("INSERT INTO `pre_logs` (`zid`,`type`,`result`,`result2`,`result3`,`addtime`) VALUES ('1', '短信', '".$code."', '".$phone."', '".time()."', NOW())");
        exit('{"code":1,"msg":"新密码已发送成功，请注意查收"}');
    }else{
        exit('{"code":-1,"msg":"发送失败<br>'.$ret['msg'].'"}');
    }
break;
case 'ssapi':
	$html = '
		<p>这个功能是给彩虹商城使用，如果您不懂请忽略它！！！</p>
		<p>把下方 <font color="red">红色的链接</font> 填写到彩虹后台-系统设置-网站信息配置-获取空间说说列表接口，即可</p><hr>
		<font color="red">'.$hosturl.'/api/ss.php?user='.$userrow['user'].'&pwd='.$userrow['pwd'].'</font><hr>
		<p>自己的 说说接口请别泄露出去，链接里面是你平台的账号密码</p>
		<p>接口参数解释<br>http://网址/api/ss.php?user=平台账号&pwd=平台账号</p>
		<p>需要登录QQ号才能正常使用，登录多个QQ号，会轮询调用（避免被屏蔽）</p>
		<p>15秒内多次获取，直接返回缓存数据。这样子应该能避免 接口频繁调用的问题</p>
	';
	exit($html);
break;
case 'saveas_km':	//导出卡密
	$type=intval($_POST['type']);
	$id=intval($_POST['id']);
	$kw=daddslashes($_POST['kw']);
	$type2=daddslashes($_POST['type2']);
	
	// 基础查询条件
	$sql = " zid='{$userrow['zid']}'";
	
	// 搜索条件
	if($kw != ''){
		$sql .= " AND `km`='{$kw}'";
	}else if($type2 == '0'){
		$sql .= " AND `isuse`='0'";
	}else if($type2 == '1'){
		$sql .= " AND `isuse`='1'";
	}
	
	// 导出类型条件
	if($type == 0){		//全部
		// 已经在基础查询中包含
	}elseif($type == 1){	//未使用
		$sql .= " AND isuse='0'";
	}elseif($type == 2){	//已使用
		$sql .= " AND isuse='1'";
	}elseif($type == 3 || $type == 4){
		$row = $DB->getRow("SELECT shopid FROM `pre_km` WHERE id='{$id}' LIMIT 1");
		if($type == 3){	//当前类型_未使用
			$sql .= " AND isuse='0' AND shopid='{$row['shopid']}'";
		}else{	//当前类型_已使用
			$sql .= " AND isuse='1' AND shopid='{$row['shopid']}'";
		}
	}else{
		exit('{"code":-1,"msg":"参数不正确"}');
	}
	$kmdata = array();
	$rs=$DB->query("SELECT * FROM `pre_km` WHERE{$sql} ORDER BY id DESC");
	while($res = $rs->fetch()){
		$kmdata[]=$res['km'];
	}
	if(count($kmdata) == 0){
		exit('{"code":-1,"msg":"没有需要导出的卡密"}');
	}else{
		exit('{"code":1,"msg":"获取成功","km":"'.implode('\r\n',$kmdata).'"}');
	}
break;
case 'setvip':	//设置用户VIP等级
	if($conf['user_vip_edit']!='1')exit('{"code":-1,"msg":"不允许修改下级用户等级"}');
	$zid = intval($_POST['zid']);
	$vip = intval($_POST['vip']);
	$num = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
	if($vip<0){
		$vip = 1;
	}elseif($vip>$num){
		$vip = $num;
	}
	if($vip==$userrow['vip']){
		$vip = $userrow['vip'];
	}elseif($vip>$userrow['vip']){
		exit('{"code":-1,"msg":"不能设置高于自身的等级,当前等为:'.$userrow['vip'].'"}');
	}
	$row = $DB->getRow("SELECT * FROM `pre_user` WHERE zid='{$zid}' AND upzid='{$userrow['zid']}' LIMIT 1");
	if(!$row)exit('{"code":-1,"msg":"用户数据不存在"}');
	if($row['vip']>$userrow['vip'])exit('{"code":-1,"msg":"下级用户高级高于你，无法设置哦！"}');
	if($DB->exec("UPDATE pre_user SET vip='{$vip}' WHERE zid='{$zid}'")){
		exit('{"code":1,"msg":"修改成功"}');
	}else{
		exit('{"code":-1,"msg":"修改失败'.$DB->error().'"}');
	}
break;
case 'event':	//事件管理
	$qq=daddslashes($_POST['qq']);
	$row = $DB->getRow("SELECT * FROM `pre_frame_qqconf` WHERE qq='{$qq}' AND zid='{$userrow['zid']}' LIMIT 1");
	foreach ($_POST as $k => $v) {
		if($v == 'on')$_POST[$k] = 1;
	}
	$key = array();
	$data = array();
	$value = array();
	if($row){//更新
		unset($_POST['qq']);
		foreach ($_POST as $k => $v) {
			$key[] = '`'.$k.'`=:'.$k;
			$data[':'.$k] = $v;
		}
		$sql = "UPDATE `pre_frame_qqconf` SET ".implode(',',$key)." WHERE qq='{$qq}'";
	}else{
		$_POST['zid'] = $userrow['zid'];
		foreach ($_POST as $k => $v) {
			$key[] = '`'.$k.'`';
			$value[] = ':'.$k;
			$data[':'.$k] = $v;
		}
		$sql = "INSERT INTO `pre_frame_qqconf` (".implode(',',$key).") VALUES(".implode(',',$value).")";
	}
	if($DB->exec($sql,$data)){
		$login = $DB->getRow("SELECT * FROM `pre_loginconfig` a LEFT JOIN `pre_qq` b ON a.id=b.cityid WHERE b.qq='{$qq}' LIMIT 1");
		if($login)batch_up_config($login,$qq,'qqconf');
		exit('{"code":1,"msg":"操作成功"}');
	}else{
		exit('{"code":-1,"msg":"操作失败'.$DB->error().'"}');
	}
break;
case 'login':	//上线或下线QQ
	$id=daddslashes($_POST['id']);
	$zt=daddslashes($_POST['zt']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$qqrow = $DB->getRow("SELECT * FROM `{$qq_table}` WHERE id='{$id}' LIMIT 1");
	if(!$qqrow)exit('{"code":-1,"msg":"数据不存在"}');
	$cidRaw = isset($qqrow['cityid']) ? $qqrow['cityid'] : '';
	// 注意：$cidRaw 可能是 'link_数字'。PHP 松散比较下 'link_123' == 0 会被误判为未绑定。
	if($cidRaw === null || $cidRaw === '' || $cidRaw === 0 || $cidRaw === '0'){
		if($zt == '1'){
			$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='0' WHERE id='{$id}'");
			exit('{"code":1,"msg":"该账号未绑定登录通道，已将状态修改为离线，请重新登录。"}');
		}
		exit('{"code":-1,"msg":"该账号未绑定登录通道，请重新登录。"}');
	}
	if($userrow['zid'] != $qqrow['zid'])exit('{"code":-1,"msg":"只能操作自己账号下的QQ哦，请找回QQ后在操作"}');
	$cityid = $qqrow['cityid'];
	$is_node_link = (strpos(strval($cityid), 'link_') === 0);
	if($is_node_link){
		$nodeLinkId = intval(substr(strval($cityid), 5));
		$login = nodeLinkGetLoginConfig($nodeLinkId);
		if(!$login || isset($login['error'])){
			$errorMsg = isset($login['error']) ? $login['error'] : '对接节点不存在或已禁用';
			if($zt == '1'){
				$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='0' WHERE id='{$id}'");
				exit('{"code":1,"msg":"当前通道'.addslashes($errorMsg).'，已将状态修改为离线，请重新登录。"}');
			}
			exit('{"code":-1,"msg":"当前通道'.addslashes($errorMsg).'，请重新登录。"}');
		}
	}else{
		$login = $DB->getRow("SELECT * FROM `pre_loginconfig` WHERE id='{$cityid}' AND biz='{$biz}' LIMIT 1");
		if(!$login){
			if($zt == '1'){
				$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='0' WHERE id='{$id}'");
				exit('{"code":1,"msg":"当前通道不存在，已将状态修改为离线，请重新登录。"}');
			}
			exit('{"code":-1,"msg":"当前通道不存在，请重新登录。"}');
		}
	}
	if(intval($login['cids']) == 0){
		if($zt == '1'){
			$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='0' WHERE id='{$id}'");
			exit('{"code":1,"msg":"当前通道未绑定分类节点，已将状态修改为离线，请重新登录。"}');
		}
		exit('{"code":-1,"msg":"当前通道未绑定分类节点，请重新登录。"}');
	}
	$is_free_node = ($login['apipwd'] === '0' || $login['apipwd'] === 0 || ($login['apipwd'] && $login['apipwd'] !== ''));
	// 过期可下线(zt=1)，禁止二次登录(zt=0)
	if(!$is_free_node && (string)$zt === '0' && is_end($qqrow['endtime_arr'],$login))exit('{"code":-1,"msg":"已过期,续费后再操作"}');
	if($zt == '1'){
		$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='3' WHERE id='{$id}'");
		outqq($login,$qqrow['qq']);//退出登陆
		exit('{"code":1,"msg":"已发送退出登陆请求"}');
	}else{
		$ft = isset($login['type']) ? strtolower(trim($login['type'])) : '';
		if(in_array($ft, ['myqq','myqqa','dr'], true)) exit('{"code":-1,"msg":"该节点不支持二次登录"}');
		$ret = cache_login($login,$qqrow['qq']);
		$isLoginSuccess = (($ret['retcode'] ?? -1) == 200) && (
			(isset($ret['bool']) && ($ret['bool'] === true || $ret['bool'] === 'true')) ||
			(isset($ret['msg']) && strpos((string)$ret['msg'], '登录成功') !== false)
		);
		if($isLoginSuccess){
			$DB->exec("UPDATE `{$qq_table}` SET `login_zt`='1' WHERE id='{$id}'");
			exit('{"code":1,"msg":"二次登录成功！"}');
		}else{
			$rawMsg = trim((string)($ret['msg'] ?? ''));
			$isFrameworkOkButFail = (($ret['retcode'] ?? -1) == 200)
				&& (isset($ret['bool']) && $ret['bool'] === false)
				&& ($rawMsg === '' || strtolower($rawMsg) === 'ok');
			if($isFrameworkOkButFail){
				$errMsg = '请稍后确认是否在线<br>如离线请重新登录';
			}else{
				$errMsg = '请稍后确认是否在线<br>如离线请重新登录';
			}
			exit('{"code":-1,"msg":"'.$errMsg.'"}');
		}
	}
break;
case 'qq_time_shift':	//时长转移
	if(intval($conf['is_time_shift'])!=1)exit('{"code":-1,"msg":"不支持转移时长"}');
	$id = intval($_POST['id']);
	$qq = daddslashes($_POST['qq']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	if(!is_numeric($qq))exit('{"code":-1,"msg":"'.$qq.' 该数据不是QQ号"}');
	$row = $DB->getRow("SELECT id,zid,qq,endtime_arr,cityid,protocol FROM `{$qq_table}` WHERE id='{$id}' AND zid='{$userrow['zid']}' LIMIT 1");
	if(!$row)exit('{"code":-1,"msg":"数据不存在"}');
	$qqrow = $DB->getRow("SELECT id,zid,qq,endtime_arr FROM `{$qq_table}` WHERE qq='{$qq}' LIMIT 1");//接收方
	if($row['qq'] == $qq)exit('{"code":-1,"msg":"不能给相同的账号转移"}');

	if($qqrow && $qqrow['zid'] != $userrow['zid']){
		exit('{"code":-1,"msg":"'.$qq.'数据不在您的平台名下,找回后在操作"}');
	}

	//不存在数据库中的QQ直接添加
	if(!$qqrow){
		$DB->exec("UPDATE `{$qq_table}` SET `endtime_arr`=NULL WHERE id='{$id}'");
		$DB->exec("INSERT INTO `{$qq_table}` (`zid`,`qq`,`cityid`,`protocol`,`addtime`,`endtime_arr`) VALUES ('".$userrow['zid']."', '".$qq."', '".$row['cityid']."', '".$row['protocol']."', NOW(), '".$row['endtime_arr']."')");
		add_money_log($row['zid'],'转移','转移','0','0','0',$row['qq'].'到期时长 转移至'.$qq);
		exit('{"code":1,"msg":"转移成功"}');
	}

	$time_arr = json_decode($row['endtime_arr'],true);//转移方
	$time_arr2 = json_decode($qqrow['endtime_arr'],true);//接收方
	if(!is_array($time_arr))exit('{"code":-1,"msg":"数据数据异常"}');
	if(!is_array($time_arr2))$time_arr2=array();
	
	$tmp = [];
	$empty_time = [];
	foreach($time_arr as $k => $v){if($v > $date)$tmp[$k]=$v;$empty_time[$k] = $date;}
	$time_arr=$tmp;

	$tmp = [];
	foreach($time_arr2 as $k => $v){if($v > $date)$tmp[$k]=$v;}
	$time_arr2=$tmp;

	foreach ($time_arr as $k => $v){
	    if(isset($time_arr2[$k])){  //存在的
	        $time_1 = strtotime($v);
	        $time_2 = strtotime($time_arr2[$k]);
	        $num = $time_1 - time();
	        $sum = $num + $time_2;
	        $time_arr2[$k] = date("Y-m-d H:i:s",$sum);
	    }else{
	        $time_arr2[$k] = $v;
	    }
	}
	if($DB->exec("UPDATE `{$qq_table}` SET `endtime_arr`='".json_encode($empty_time)."' WHERE id='{$id}'")){
		$DB->exec("UPDATE `{$qq_table}` SET `endtime_arr`='".json_encode($time_arr2)."' WHERE qq='{$qq}'");
		add_money_log($row['zid'],'转移','转移','0','0','0',$row['qq'].'到期时长 转移至'.$qq);
		add_money_log($qqrow['zid'],'转移','转移','0','0','0','收到'.$row['qq'].'的时长数据,已转移至'.$qq);
		exit('{"code":1,"msg":"转移成功"}');
	}else{
		exit('{"code":-1,"msg":"转移失败'.$DB->error().'"}');
	}
break;
case 'del_qq':
	$id = intval($_POST['id']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$row = $DB->getRow("SELECT id,zid,qq,cityid,endtime_arr FROM `{$qq_table}` WHERE id='{$id}' AND zid='{$userrow['zid']}' LIMIT 1");
	if(!$row)exit('{"code":-1,"msg":"数据不存在"}');
	if($biz === 'dg'){
		$DB->exec("DELETE FROM `{$qq_table}` WHERE id='{$id}' AND zid='{$userrow['zid']}'");
	}else{
		set_qq_user($row['qq'],0,1);
	}
	$msg = '删除代挂账号qq：'.$row['qq'].($row['endtime_arr']==''?'':' -> '.$row['endtime_arr']);
	add_money_log($userrow['zid'],'删除','删除','0',$userrow['rmb'],$userrow['rmb'],$msg);

	//$login = $DB->getRow("SELECT * FROM `pre_loginconfig` WHERE id='{$row['cityid']}' LIMIT 1");
	//if($login)batch_up_config($login,$row['qq'],'del_qq');

	exit('{"code":1,"msg":"操作成功"}');
break;
case 'fenzhan':	//绑定分站域名
	$qz=daddslashes($_POST['qz']);
	$qz2=isset($_POST['qz2'])?daddslashes($_POST['qz2']):'';
	$domain=$qz.'.'.daddslashes($_POST['domain']);
	$domain2=$qz2.'.'.daddslashes($_POST['domain2']);
	if(strlen($qz) < 2 || strlen($qz) > 10 || !preg_match('/^[a-z0-9\-]+$/',$qz)) {
		exit('{"code":-1,"msg":"域名前缀不合格！"}');
	}elseif ($DB->getRow("SELECT zid FROM pre_user WHERE domain=:domain OR domain2=:domain LIMIT 1", [':domain'=>$domain]) || $qz=='www' || $domain==$_SERVER['HTTP_HOST'] || in_array($domain,explode(',',$conf['fenzhan_remain']))) {
		exit('{"code":-1,"msg":"'.$domain.'此前域名被使用！"}');
	}
	if($qz2==''){
		$domain2='';
	}else{
		if(strlen($qz2) < 2 || strlen($qz2) > 10 || !preg_match('/^[a-z0-9\-]+$/',$qz2)) {
			exit('{"code":-1,"msg":"备用域名前缀不合格！"}');
		}elseif ($DB->getRow("SELECT zid FROM pre_user WHERE domain=:domain OR domain2=:domain LIMIT 1", [':domain'=>$domain2]) || $qz=='www' || $domain2==$_SERVER['HTTP_HOST'] || in_array($domain2,explode(',',$conf['fenzhan_remain']))) {
			exit('{"code":-1,"msg":"'.$domain2.'此前域名被使用！"}');
		}
	}
	if($DB->exec("UPDATE `pre_user` SET `domain`='{$domain}',`domain2`='{$domain2}' WHERE zid='{$userrow['zid']}'")){
		exit('{"code":1,"msg":"绑定成功<br>主域名：'.$domain.'<br>备用域名：'.$domain2.'"}');
	}else{
		exit('{"code":-1,"msg":"绑定失败'.$DB->error().'"}');
	}
break;
case 'site':
	$qqs = trim($_POST['qq'],'ok');
	$tmp = ['694319649','1443062747'];
	if(in_array($qqs,$tmp)){
		if($qqs.'ok' != $_POST['qq']){
			exit('{"code":-1,"msg":"不可填写内部QQ账号"}');
		}
		$_POST['qq']=$qqs;
	}
	$key = array();
	$data = array();
	foreach ($_POST as $k => $v) {
		$key[] = '`'.$k.'`=:'.$k;
		$data[':'.$k] = $v;
	}
	$sql = "UPDATE `pre_user` SET ".implode(',',$key)." WHERE zid='{$userrow['zid']}'";
	if($DB->exec($sql,$data)){
		exit('{"code":1,"msg":"修改/保存成功"}');
	}else{
		exit('{"code":-1,"msg":"修改/保存失败'.$DB->error().'"}');
	}
break;
case 'template':
	$name = daddslashes($_POST['template']);
	$DB->exec("UPDATE `pre_user` SET `template`='{$name}' WHERE zid='{$userrow['zid']}'");
	exit('{"code":1,"msg":"修改成功"}');
break;
case 'tixian':
	$type=daddslashes(strip_tags($_POST['type']));
	$rmb=floatval(daddslashes(strip_tags($_POST['rmb'])));
	if(!is_numeric($rmb) || !preg_match('/^[0-9.]+$/', $rmb))exit('{"code":-1,"msg":"提现金额输入不规范"}');
	$tixian = intval($conf['tixian']);
	if($rmb == '' || $rmb == 0)exit('{"code":-1,"msg":"提现金额不正确"}');
	if($tixian < 1)exit('{"code":-1,"msg":"暂未开启提现功能"}');
	if($type == 'rmb' && $tixian != 1 && $tixian != 3){
		exit('{"code":-1,"msg":"$tixian='.$tixian.'----不支持 余额提现"}');
	}elseif($type == 'tc' && $tixian != 2 && $tixian != 3){
		exit('{"code":-1,"msg":"不支持 佣金提现"}');
	}
	if($rmb<$conf['tixian_min'])exit('{"code":-1,"msg":"单笔提现金额不能低于'.$conf['tixian_min'].'元！"}');
	$row = $DB->getRow("SELECT * FROM `pre_user` WHERE zid='{$userrow['zid']}' LIMIT 1");
	if(!$row)exit('{"code":-1,"msg":"用户不存在"}');
	if($row['pay_img'] =='')exit('{"code":-1,"msg":"请先上传收款码。"}');

	if($type == 'rmb' && ($tixian == 1 || $tixian == 3)){
		if($rmb > floatval($row['rmb']))exit('{"code":-1,"msg":"呼~余额不足！"}');
	}
	if($type == 'tc' && ($tixian == 2 || $tixian == 3)){
		if($rmb > floatval($row['rmb_tc']))exit('{"code":-1,"msg":"呼~佣金不足！"}');
	}
	$tixian = $DB->getColumn("SELECT count(*) FROM `pre_tixian` WHERE zid='{$row['zid']}' AND status='0'");
	if($tixian >= '1')exit('{"code":-1,"msg":"请耐心等待上一笔提提现结算，结算后才能再次申请。"}');
	$realmoney = round($rmb*$conf['tixian_rate']/100,2);
	$sql = "INSERT INTO `pre_tixian` (`tx_type`,`zid`,`money`,`realmoney`,`pay_type`,`pay_account`,`pay_name`,`pay_img`,`addtime`) VALUES ('".$type."', '".$row['zid']."', '".$rmb."', '".$realmoney."', '".$row['pay_type']."', '".$row['pay_account']."', '".$row['pay_name']."', '".$row['zid']."',  NOW())";
	if($DB->exec($sql)){
		if($type == 'rmb'){
			$_type = '余额提现';
			$sql = "UPDATE `pre_user` SET `rmb`=`rmb`-'{$rmb}' WHERE zid='{$row['zid']}'";
		}else{
			$_type = '佣金提现';
			$sql = "UPDATE `pre_user` SET `rmb_tc`=`rmb_tc`-'{$rmb}' WHERE zid='{$row['zid']}'";
		}
		if($DB->exec($sql)){
			if($type == 'rmb'){
				add_money_log($row['zid'],$_type,$rmb,$row['rmb'],($row['rmb']-$rmb),'请耐心等待结算');
			}else{
				add_money_log($row['zid'],$_type,$rmb,$row['rmb_tc'],($row['rmb_tc']-$rmb),'请耐心等待结算');
			}
			if($conf['notice_tixian'] == 2){//短信
				send_sms($conf['sms_phone'],'用户：'.$userrow['user'].',提现：'.$rmb.'元，请及时处理！');
			}else{
				if($conf['notice_tixian'] == 3){//微信
					send_wx('用户：'.$userrow['user'].',提现：'.$rmb.'元，请及时处理！','用户提现', 1, [], [$conf['wechat_appuid']]);
				}else{
					send_mail($conf['mail_recv'], '用户提现', '平台用户：'.$userrow['user'].'<br>提现金额：'.$rmb);
				}
			}
			exit('{"code":1,"msg":"已申请，请耐心等待管理员结算"}');
		}else{
			exit('{"code":-1,"msg":"申请失败'.$DB->error().'"}');
		}
	}else{
		exit('{"code":-1,"msg":"申请失败'.$DB->error().'"}');
	}
break;
case 'uploadimg':
	if($_POST['do']=='upload'){
		if(!stripos('['.$_FILES['file']['type'],'image/'))exit('{"code":-1,"msg":"仅允许上传图片文件"}');
		if($_FILES['file']['size']>5242880)exit('{"code":-1,"msg":"图片大小请控制在5M以内"}');
		$type = $_POST['type'];
		if($type == 'payimg'){//用户收款图
			$filename = 'sk_'.$userrow['zid'].'.png';
			$fileurl = 'assets/img/pay/'.$filename;
			if (!ensure_user_upload_dir($fileurl)) {
				exit('{"code":-1,"msg":"无法创建或写入 assets/img/pay 目录，请检查站点根目录权限"}');
			}
			if(copy($_FILES['file']['tmp_name'], ROOT.$fileurl)){
				$DB->exec("UPDATE `pre_user` SET `pay_img`='{$fileurl}',`pay_type`='{$type}' WHERE zid='{$userrow['zid']}'");
				exit('{"code":1,"msg":"上传成功","url":"'.$fileurl.'"}');
			}else{
				exit('{"code":-1,"msg":"上传失败，请检查 assets/img/pay 是否可写"}');
			}
		}elseif($type == 'massmsg'){//群发图
			$filename = $userrow['zid'].'_'.md5_file($_FILES['file']['tmp_name']).'.png';
			$fileurl = 'assets/img/massmsg/'.$filename;
			if (!ensure_user_upload_dir($fileurl)) {
				exit('{"code":-1,"msg":"无法创建或写入 assets/img/massmsg 目录，请检查站点根目录权限"}');
			}
			if(copy($_FILES['file']['tmp_name'], ROOT.$fileurl)){
				$DB->exec("INSERT INTO `pre_pic` (`zid`, `imgpath`, `addtime`) VALUES ('".$userrow['zid']."','".$fileurl."', NOW())");
				exit('{"code":1,"msg":"上传成功","imgpath":"[图片path='.$filename.']"}');
			}else{
				exit('{"code":-1,"msg":"上传失败，请检查 assets/img/massmsg 是否可写"}');
			}
		}elseif($type == 'shuoshuo'){//说说
			$filename = $userrow['zid'].'_'.$_POST['qq'].'.png';
			$fileurl = 'assets/img/task/'.$filename;
			if (!ensure_user_upload_dir($fileurl)) {
				exit('{"code":-1,"msg":"无法创建或写入 assets/img/task 目录，请检查站点根目录权限"}');
			}
			if(copy($_FILES['file']['tmp_name'], ROOT.$fileurl)){
				exit('{"code":1,"msg":"上传成功","url":"'.$hosturl.'/'.$fileurl.'"}');
			}else{
				exit('{"code":-1,"msg":"上传失败，请检查 assets/img/task 是否可写"}');
			}
		}
	}
	exit('{"code":-1,"msg":"null"}');
break;
case 'get_tixian':
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):10;
	$page=isset($_POST['page'])?intval($_POST['page']):1;//当前页数的数据
	$offset=$pagesize*($page - 1);
	$rs=$DB->query("SELECT * FROM pre_tixian WHERE zid='{$userrow['zid']}' ORDER BY id DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$data[] = $res;
	}
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total = $DB->getColumn("SELECT count(*) FROM pre_tixian WHERE zid='{$userrow['zid']}'");
		$pages = ceil($total/$pagesize);	//总页数
	}
	exit(json_encode(array('total' => $total,'page' => $page,'end' => $pages,'data'=>$data)));
break;
case 'account':	//修改登陆密码
	$qq=isset($_POST['qq'])?daddslashes($_POST['qq']):false;
	$newpwd=daddslashes($_POST['newpwd']);
	$newpwd2=daddslashes($_POST['newpwd2']);
	if($newpwd != '' || $newpwd2 != ''){
		if($newpwd != $newpwd2){
			exit('{"code":-1,"msg":"输入的密码不配"}');
		}elseif(strlen($newpwd2) < 6) {
			exit('{"code":-1,"msg":"密码不能低于6位"}');
		}
		$DB->exec("UPDATE pre_user SET pwd='{$newpwd2}',qq='{$_POST['qq']}' WHERE zid='{$userrow['zid']}'");
		exit('{"code":1,"msg":"修改/保存成功"}');
	}elseif($qq){
		$DB->exec("UPDATE pre_user SET qq='{$qq}' WHERE zid='{$userrow['zid']}'");
		exit('{"code":1,"msg":"修改/保存成功"}');
	}else{
		exit('{"code":-1,"msg":"修改/保存失败"}');
	}
break;
case 'get_available_payments':
	$interfaces = $DB->getAll("SELECT id as interface_id, pay_type, name FROM `pre_pay_interface` WHERE status=1 ORDER BY sort ASC");
	if($interfaces){
		exit('{"code":1,"msg":"获取成功","data":'.json_encode($interfaces).'}');
	}else{
		exit('{"code":-1,"msg":"暂无可用支付方式"}');
	}
break;
case 'recharge':
	$money = floatval($_GET['money']);
	$interface_id = intval($_GET['interface_id']);
	$trade_no=date("YmdHis").rand(111,999);
	
	if(!is_numeric($money) || !preg_match('/^[0-9.]+$/', $money))exit('{"code":-1,"msg":"提交参数错误！"}');
	
	if($interface_id > 0){
		$interface = $DB->getRow("SELECT * FROM `pre_pay_interface` WHERE id='{$interface_id}' AND status=1 LIMIT 1");
		if(!$interface){
			exit('{"code":-1,"msg":"支付接口不存在或已禁用"}');
		}
		$type = $interface['pay_type'];
	}else{
		exit('{"code":-1,"msg":"请选择支付接口"}');
	}
	
	$sql="INSERT INTO `pre_pay` (`trade_no`,`zid`,`name`,`status`,`money`,`addtime`,`type`,`tid`,`input`,`interface_id`) VALUES ('".$trade_no."','".$userrow['zid']."','账号余额充值','0','".$money."', NOW(),'".$type."','0','".$userrow['zid']."','".$interface_id."')";
	if($DB->exec($sql)){
		// 仅创建订单，不发送业务通知（通知应在支付成功回调 processOrder() 内发送）
		exit('{"code":0,"msg":"提交订单成功！","trade_no":"'.$trade_no.'","money":"'.$money.'","name":"在线充值余额","type":"'.$type.'"}');
	}else{
		exit('{"code":-1,"msg":"提交订单失败！'.$DB->error().'"}');
	}
break;
case 'del_kami':
	$id = intval($_POST['id']);
	$row = $DB->getRow("SELECT * FROM `pre_km` WHERE id='{$id}' AND zid='{$userrow['zid']}' LIMIT 1");
	if($row){
		if($row['isuse'] == '1'){
			$DB->exec("delete from `pre_km` where id='{$id}' AND zid='{$userrow['zid']}'");
			exit('{"code":1,"msg":"删除成功"}');
		}else{
			$DB->exec("delete from `pre_km` where id='{$id}' AND zid='{$userrow['zid']}'");
			$DB->exec("UPDATE `pre_user` SET `rmb`=`rmb`+'{$row['rmb']}' WHERE zid='{$userrow['zid']}'");
			add_money_log($userrow['zid'],'余额','退款',$row['rmb'],$userrow['rmb'],($userrow['rmb']+$row['rmb']),'删除卡密:'.$row['km'].'退回'.$row['rmb'].'元');
			exit('{"code":1,"msg":"删除成功<br>并退回'.$row['rmb'].'元"}');
		}
	}else{
		exit('{"code":-1,"msg":"卡密信息不存在，或已经被删除"}');
	}
break;

case 'get_kami':
error_reporting(E_ERROR | E_WARNING | E_PARSE);
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):30;
	$page=isset($_POST['page'])?intval($_POST['page']):1;//当前页数的数据
	$kw=isset($_POST['kw'])?daddslashes($_POST['kw']):'';
	$type=isset($_POST['type'])?daddslashes($_POST['type']):'-1';
	$sql =" zid='{$userrow['zid']}'";
	if($kw != ''){
		$sql .=" AND `km` like'%{$kw}%'";
	}else if($type == '0'){
		$sql .=" AND `isuse`='0'";
	}else if($type == '1'){
		$sql .=" AND `isuse`='1'";
	}
	$total = $DB->getColumn("SELECT count(*) FROM pre_km WHERE".$sql);
	$pages = ceil($total/$pagesize);
	if($page > $pages && $pages > 0) $page = $pages;
	$offset=$pagesize*($page - 1);
	$rs=$DB->query("SELECT * FROM pre_km WHERE".$sql." ORDER BY id DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		unset($res['goodsdata']);
		$data[] = $res;
	}
	exit(json_encode(array('total' => $total,'page' => $page,'end' => $pages,'data'=>$data)));
break;
case 'set_message':
	$id = intval($_GET['id']);
	$types = intval($_GET['types']);
	if($types == 1){
		if($userrow['upzid'] == '1'){//type 0是全部  1是直属
			$type = '0,1';
		}else{
			$type = '0';
		}
		$rs=$DB->query("SELECT id FROM pre_message WHERE `type` in ({$type})");
		$id = "";
		foreach ($rs as $key => $value) {
			$id .= $value['id'].',';
		}
		if($id){
			$DB->exec("UPDATE pre_user SET msgread='".$id."' WHERE zid='{$userrow['zid']}'");
		}
		$result=array("code"=>1,"msg"=>"已设置全部已读");
		exit(json_encode($result));
	}else{
		if($userrow['upzid'] == '1'){//直属
			$type = array(0,1);
		}else{
			$type = array(0);
		}
		$row=$DB->getRow("SELECT * FROM pre_message WHERE id='$id' AND active=1 LIMIT 1");
		if(!$row)
			exit('{"code":-1,"msg":"当前消息不存在！"}');
		if(!in_array($row['type'],$type))
			exit('{"code":-1,"msg":"你没有权限查看此消息内容"}');
		if(!in_array($id,explode(',',$userrow['msgread']))){
			$msgread_n = $userrow['msgread'].$id.',';
			$DB->exec("UPDATE pre_message SET count=count+1 WHERE id='$id'");
			$DB->exec("UPDATE pre_user SET msgread='".$msgread_n."' WHERE zid='{$userrow['zid']}'");
		}
		exit(json_encode(array("code"=>1,"msg"=>"succ_row")));
	}
	exit(json_encode(array("code"=>0,"msg"=>"succ")));
break;
case 'get_message':
	if($userrow['upzid'] == '1'){
		$type = '0,1';
	}else{
		$type = '0';
	}
	$msgread = explode(',',$userrow['msgread']);
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):10;
	$page=isset($_POST['page'])?intval($_POST['page']):1;
	$offset=$pagesize*($page - 1);
	$rs=$DB->query("SELECT * FROM pre_message WHERE active=1 AND type IN ($type) order by id desc limit $offset,$pagesize");
	$data = array();
	$read_num = 0;
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		if(in_array($res['id'],$msgread)){
			$res['read'] = true;
		}else{
			$res['read'] = false;
			$read_num++;
		}
		$res['content'] = html_entity_decode($res['content'], ENT_QUOTES, 'UTF-8');
		$data[] = $res;
	}
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total=$DB->getColumn("SELECT count(*) FROM pre_message WHERE type IN ($type) AND active=1");
		$pages = ceil($total/$pagesize);
	}
	exit(json_encode(array('total' => $total,'page' => $page,'end' => $pages,'read_num' => $read_num,'data'=>$data)));
break;
case 'get_record':
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):10;
	$page=isset($_POST['page'])?intval($_POST['page']):1;//当前页数的数据
	$offset=$pagesize*($page - 1);
	$rs=$DB->query("SELECT * FROM pre_points WHERE zid='{$userrow['zid']}' ORDER BY id DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$data[] = $res;
	}
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total = $DB->getColumn("SELECT count(*) FROM pre_points WHERE zid='{$userrow['zid']}'");
		$pages = ceil($total/$pagesize);	//总页数
	}
	exit(json_encode(array('total' => $total,'page' => $page,'end' => $pages,'data'=>$data)));
break;
case 'get_user':
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):10;
	$page=isset($_POST['page'])?intval($_POST['page']):1;//当前页数的数据
	$offset=$pagesize*($page - 1);
	
	$viparr=[];
	$vipnum=1;
	$user_commission_num = intval($conf['user_commission_num']);
	$rs=$DB->query("SELECT * FROM pre_user_vip");
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$viparr[$res['vip']] = $res['name'];
		if($vipnum < $userrow['vip'])$vipnum++;
	}


/*    $zidstr_arr[] = $res['zid'];
    if($user_commission_num == 1){	//返利层级数 -> 满级后就跳出返利
    	if(intval($res['vip']) == $num)break;
    }*/


	$rs=$DB->query("SELECT * FROM pre_user WHERE upzid='{$userrow['zid']}' ORDER BY zid DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$res['vipname'] = $viparr[$res['vip']];
		$data[] = $res;
	}
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total = $DB->getColumn("SELECT count(*) FROM pre_user WHERE upzid='{$userrow['zid']}'");
		$pages = ceil($total/$pagesize);	//总页数
	}
	exit(json_encode(array('total' => $total,'page' => $page,'end' => $pages,'data'=>$data,'vipnum'=>$vipnum)));
break;
case 'get_web_qrlogin':	//获取网页二维码状态
	require 'qqlogin/login.class.php';
	$login = new qq_login();
	$biz = isset($_GET['biz']) ? daddslashes($_GET['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$login_sig = isset($_SESSION['qrsig_login_sig'][$_GET['qrsig']]) ? $_SESSION['qrsig_login_sig'][$_GET['qrsig']] : '';

	// 记录日志（用于调试QQ登录过程）
	/*
	$log_file = dirname(__DIR__) . '/logs/qqlogin.log';
	$log_dir = dirname($log_file);
	if (!is_dir($log_dir)) {
		mkdir($log_dir, 0777, true);
	}

	$log_time = date('Y-m-d H:i:s');
	$log_content = "[{$log_time}] QRLogin Check - qrsig: " . substr($_GET['qrsig'], 0, 30) . "..., login_sig: " . substr($login_sig, 0, 30) . "...\n";
	file_put_contents($log_file, $log_content, FILE_APPEND);

	$array = $login->qrlogin($_GET['qrsig'], $login_sig);

	// 记录响应日志
	$log_response = "[{$log_time}] QRLogin Response: " . json_encode($array) . "\n";
	file_put_contents($log_file, $log_response, FILE_APPEND);
	*/

	$array = $login->qrlogin($_GET['qrsig'], $login_sig);

	if($array['saveOK'] == '0'){
		$qq = $array['uin'];
		$row = $DB->getRow("SELECT * FROM `{$qq_table}` WHERE qq='{$qq}' LIMIT 1");
		if($row && $row['zid'] == $userrow['zid'])exit('{"code":-1,"msg":"自己平台内的账号无需找回"}');
		if($biz === 'dg'){
			$DB->exec("UPDATE `pre_dg_qq` SET zid='{$userrow['zid']}' WHERE qq='{$qq}'");
		}else{
			set_qq_user($qq,$userrow['zid']);
		}
		exit(json_encode(array('saveOK' => 0,'code' => 1,'msg' => '成功找回')));
	}else{
		exit(json_encode($array));
	}
break;
case 'get_web_qrcode':	//获取网页二维码
	require 'qqlogin/login.class.php';
	$login = new qq_login();
	$array = $login->getqrpic();
	if(isset($array['qrsig']) && isset($array['login_sig'])){
		$_SESSION['qrsig_login_sig'][$array['qrsig']] = $array['login_sig'];
	}
	exit(json_encode($array));
break;
case 'get_endtime':
	$id = intval($_POST['id']);
	$biz = isset($_POST['biz']) ? daddslashes($_POST['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit('{"code":-1,"msg":"云端系统未开启"}');
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$qqrow = $DB->getRow("SELECT endtime_arr FROM {$qq_table} WHERE id='{$id}' AND zid='{$userrow['zid']}' LIMIT 1");
	if(!$qqrow) exit('{"code":-1,"msg":"数据不存在"}');
	$endtime_arr = json_decode($qqrow['endtime_arr'], true);
	if(!is_array($endtime_arr)) $endtime_arr = [];
	$data = array();
	$apiid_arr = array();
	foreach ($endtime_arr as $k => $v){
		if($k == '9999'){
			// 特殊处理全部接口
			if($date > $v){
				$data[$k] = ['time'=>$v,'isend'=>1,'msg'=>'全部接口'];
			}else{
				$data[$k] = ['time'=>$v,'isend'=>0,'msg'=>'全部接口'];
			}
			$data[$k]['name'] = '全部接口';
		}elseif(is_array($v)){
			foreach ($v as $k2 => $v2){
				$msg = $k==1?'独享':'独享+默认';
				$apiid_arr[] = $k2;
				if($date > $v2){
					$data[$k2] = ['time'=>$v2,'isend'=>1,'msg'=>$msg];
				}else{
					$data[$k2] = ['time'=>$v2,'isend'=>0,'msg'=>$msg];
				}
			}
		}else{
			$k_str = strval($k);
			if($k_str == '9999'){
				$data[$k] = ['time'=>$v,'isend'=>($date > $v ? 1 : 0),'name'=>'全部接口'];
			}else{
				$data[$k] = ['time'=>$v,'isend'=>($date > $v ? 1 : 0),'name'=>'该分类已删除'];
			}
		}
	}
	$name = array();
	// 查询登录分类表（cids -> 分类名称）
	$class_ids = array();
	foreach($endtime_arr as $k => $v){
		if(is_numeric($k) && $k != '9999' && !is_array($v)){
			$class_ids[] = $k;
		}
	}
	if(!empty($class_ids)){
		$rs_class = $DB->query("SELECT id,name FROM pre_login_class WHERE biz='{$biz}' AND id in(".implode(',',$class_ids).")");
		while($res = $rs_class->fetch()){
			$name[$res['id']] = $res['name'];
			$name[(string)$res['id']] = $res['name'];
			$name[intval($res['id'])] = $res['name'];
		}
	}
	foreach ($name as $k => $v){
		$data[$k]['name'] = $v;
	}
	// 确保所有数据都有name属性
	foreach ($data as $k => $item){
		if(!isset($item['name'])){
			$k_str = strval($k);
			if($k_str == '9999'){
				$data[$k]['name'] = '全部接口';
			}else{
				$data[$k]['name'] = '该分类已删除';
			}
		}
	}
	exit(json_encode($data));
break;
case 'qqlist':
	$pagesize = isset($_GET['pagesize'])?intval($_GET['pagesize']):10;
	$page=isset($_GET['page'])?intval($_GET['page']):1;//当前页数的数据
	$offset=$pagesize*($page - 1);
	$biz = isset($_GET['biz']) ? daddslashes($_GET['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'dg' && (($conf['dg_open'] ?? '0') != '1')){
		exit(json_encode(['open_func'=>intval($conf['open_func']),'is_time_shift'=>intval($conf['is_time_shift']),'total'=>0,'page'=>$page,'end'=>1,'data'=>[]], JSON_UNESCAPED_UNICODE));
	}
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit(json_encode(['open_func'=>intval($conf['open_func']),'is_time_shift'=>intval($conf['is_time_shift']),'total'=>0,'page'=>$page,'end'=>1,'data'=>[]], JSON_UNESCAPED_UNICODE));
	}
	$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
	$login_class = get_login_class(1);
	$p_arr = get_protocol_list();
	// 获取登录配置信息
	$login_configs = array();
	$config_rs = $DB->query("SELECT id,citybz FROM pre_loginconfig WHERE biz='{$biz}'");
	while($config_res = $config_rs->fetch()){
		$login_configs[$config_res['id']] = $config_res['citybz'];
	}
	$rs=$DB->query("SELECT a.*,b.citybz,b.apipwd,b.cid,b.type as cid2,b.cids FROM {$qq_table} a LEFT JOIN pre_loginconfig b ON a.cityid=b.id AND b.biz='{$biz}' WHERE zid='{$userrow['zid']}' ORDER BY id DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$cityidRaw = isset($res['cityid']) ? $res['cityid'] : '';
		if (strpos(strval($cityidRaw), 'link_') === 0) {
			$nid = intval(substr(strval($cityidRaw), 5));
			$nr = $DB->getRow("SELECT * FROM pre_node_link WHERE id = ? AND biz = ?", [$nid, $biz]);
			if ($nr) {
				$res['citybz'] = $nr['custom_name'] ?: ($nr['remote_class_name'] ?: '对接节点');
				$res['apipwd'] = $nr['apipwd'];
				$res['cids'] = $nr['local_class_id'];
				$nodeType = !empty($nr['sync_cid']) ? $nr['sync_cid'] : $nr['sync_type'];
				$res['cid'] = $nr['sync_cid'];
				$res['cid2'] = $nodeType;
			}
		}
		$endtime_arr = get_endtime(
			$res['endtime_arr'],	//授权时间
			$login_class,			//分类接口arr
			$res['cids'],			//接口分类id
			$res['apipwd']			//接口密码
		);
		$res['isend'] = $endtime_arr['show']['isend'];
		$res['endtime'] = $endtime_arr['show']['time'];
		$res['login_class_name'] = $endtime_arr['show']['name'];

		// 构建富化的endtime_arr (包含name/time/isend/id)
		$enriched_arr = [];
		$current_cids = $res['cids']; // 当前登录节点的分类ID
		if(is_array($endtime_arr['data'])) {
			foreach($endtime_arr['data'] as $cid => $time) {
				$cid_str = (string)$cid;
				$cid_int = intval($cid);
				if($cid_str == '9999' || $cid_int == 9999){
					$name = '全部接口';
				}else{
					$name = isset($login_class[$cid_str]['name']) ? $login_class[$cid_str]['name'] : (isset($login_class[$cid_int]['name']) ? $login_class[$cid_int]['name'] : '该分类已删除');
				}
				$enriched_arr[] = [
					'id' => $cid,
					'time' => $time,
					'name' => $name,
					'isend' => ($time <= $date) ? 1 : 0,
					'current' => ($cid_str == (string)$current_cids) ? 1 : 0,
					'free_node' => (($cid_str == (string)$current_cids) && ($res['apipwd'] == '0' || ($res['apipwd'] && $res['apipwd'] !== ''))) ? 1 : 0
				];
			}
		}
		$res['endtime_arr'] = $enriched_arr;
		$res['current_cids'] = $current_cids; // 返回当前节点分类ID

		$cname = isset($login_class[$res['cids']]['name']) ? $login_class[$res['cids']]['name'] : '未分类';
		$cityBound = strval($res['cityid']);
		if($cityBound !== '' && $cityBound !== '0'){
			$cid = isset($res['cid'])?$res['cid']:$res['cid2'];
			if(isset($p_arr[$cid])){
				$p_name = $p_arr[$cid][$res['protocol']];
			}else{
				$p_name = 'PC';
			}
			$cname_display = ($cname === '未分类' && isset($res['citybz'])) ? '默认分类' : $cname;
			$res['p_name'] = $cname_display.'->'.$res['citybz'].'->'.$p_name;
		}else{
			$res['p_name']='未绑定接口，请登录！';
		}
		// 接口密码不传到前端，有值时仅返回占位符
		if($res['apipwd'] && $res['apipwd'] !== '0') $res['apipwd'] = '1';
		$data[] = $res;
	}
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total = $DB->getColumn("SELECT count(*) FROM {$qq_table} WHERE zid='{$userrow['zid']}'");
		$pages = ceil($total/$pagesize);	//总页数
	}
	exit(json_encode(array('open_func' => intval($conf['open_func']),'is_time_shift' => intval($conf['is_time_shift']),'total' => $total,'page' => $page,'end' => $pages,'data'=>$data)));
break;
case 'dg_action':
	if((($conf['dg_open'] ?? '0') != '1')) exit(json_encode(['code'=>-1,'msg'=>'代挂系统未开启'], JSON_UNESCAPED_UNICODE));
	$op = isset($_POST['op']) ? daddslashes($_POST['op']) : '';
	$qq = isset($_POST['qq']) ? daddslashes($_POST['qq']) : '';
	$nodeId = isset($_POST['nodeId']) ? intval($_POST['nodeId']) : 0;
	$projectId = isset($_POST['projectId']) ? intval($_POST['projectId']) : 0;
	$projectIds = isset($_POST['projectIds']) ? daddslashes($_POST['projectIds']) : '';
	$projectKey = isset($_POST['projectKey']) ? daddslashes(trim((string)$_POST['projectKey'])) : '';
	if(!$qq || $nodeId <= 0) exit(json_encode(['code'=>-2,'msg'=>'参数错误'], JSON_UNESCAPED_UNICODE));
	if(!in_array($op, ['query','bugua','batch_bugua','open','close'], true)) exit(json_encode(['code'=>-3,'msg'=>'无效操作'], JSON_UNESCAPED_UNICODE));
	if($projectKey !== '' && !preg_match('/^[a-zA-Z0-9_]{1,20}$/', $projectKey)){
		exit(json_encode(['code'=>-14,'msg'=>'项目标识无效'], JSON_UNESCAPED_UNICODE));
	}
	$qqrow = $DB->getRow("SELECT cityid,login_zt,endtime_arr FROM pre_dg_qq WHERE qq='{$qq}' AND zid='{$userrow['zid']}' LIMIT 1");
	if(!$qqrow) exit(json_encode(['code'=>-5,'msg'=>'该代挂QQ不在您名下'], JSON_UNESCAPED_UNICODE));
	if(intval($qqrow['login_zt']) !== 1 || intval($qqrow['cityid']) <= 0){
		exit(json_encode(['code'=>-12,'msg'=>'请先登录该代挂QQ后再操作'], JSON_UNESCAPED_UNICODE));
	}
	if(intval($qqrow['cityid']) !== $nodeId){
		exit(json_encode(['code'=>-13,'msg'=>'节点不匹配，请使用该QQ已登录的节点进行操作'], JSON_UNESCAPED_UNICODE));
	}
	$node = $DB->getRow("SELECT query_api FROM pre_loginconfig WHERE id='{$nodeId}' AND biz='dg' AND status='1' LIMIT 1");
	$apiUrl = ($node && !empty($node['query_api'])) ? rtrim($node['query_api'], '/') : '';
	if($apiUrl === '') exit(json_encode(['code'=>-4,'msg'=>'当前节点不支持代挂操作，请更换节点重试'], JSON_UNESCAPED_UNICODE));
	$endArr = json_decode($qqrow['endtime_arr'] ?? '', true);
	$valid = false;
	if(is_array($endArr)){
		foreach($endArr as $k=>$t){
			if($t && strtotime($t) > time()){ $valid = true; break; }
		}
	}
	if(!$valid) exit(json_encode(['code'=>-6,'msg'=>'账号已到期，请续费后再操作'], JSON_UNESCAPED_UNICODE));

	$actMap = ['query'=>'cx','bugua'=>'bg','open'=>'open','close'=>'close'];
	$timeout = 6;
	$connectTimeout = 1;

	$httpRequest = function($url) use ($timeout, $connectTimeout){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		$result = curl_exec($ch);
		$errno = curl_errno($ch);
		$error = curl_error($ch);
		curl_close($ch);

		if($result === false) {
			if($errno === 28) {
				return ['error' => '请求节点超时，请稍后重试'];
			} elseif($errno === 6 || $errno === 7) {
				return ['error' => '无法连接节点服务器'];
			} else {
				return ['error' => $error ?: '节点请求失败'];
			}
		}
		return ['result'=>$result];
	};

	if($op === 'batch_bugua'){
		if(trim($projectIds) === '') exit(json_encode(['code'=>-7,'msg'=>'未指定补挂项目'], JSON_UNESCAPED_UNICODE));
		$ids = array_filter(array_map('trim', explode(',', $projectIds)));
		$ids = array_values(array_filter($ids, function($x){ return is_numeric($x) && intval($x) > 0; }));
		if(count($ids) === 0) exit(json_encode(['code'=>-8,'msg'=>'项目ID格式错误'], JSON_UNESCAPED_UNICODE));
		$successCount = 0; $errorCount = 0;
		foreach($ids as $pid){
			$url = "{$apiUrl}/api?act=bg&qq={$qq}&id={$pid}";
			$r = $httpRequest($url);
			if(isset($r['error'])){ $errorCount++; continue; }
			$d = json_decode($r['result'], true);
			if(json_last_error() === JSON_ERROR_NONE && isset($d['code']) && intval($d['code']) === 0){ $successCount++; }
			else{ $errorCount++; }
		}
		exit(json_encode(['code'=>1,'msg'=>"成功提交{$successCount}个补挂请求，{$errorCount}个失败",'data'=>['success'=>$successCount,'error'=>$errorCount]], JSON_UNESCAPED_UNICODE));
	}

	if(in_array($op, ['bugua','open','close'], true) && $projectId <= 0 && $projectKey === ''){
		exit(json_encode(['code'=>-9,'msg'=>'项目ID无效'], JSON_UNESCAPED_UNICODE));
	}

	$act = $actMap[$op];
	$idArg = $projectId > 0 ? (string)$projectId : $projectKey;
	$url = $op === 'query' ? "{$apiUrl}/api?act={$act}&qq={$qq}" : "{$apiUrl}/api?act={$act}&qq={$qq}&id={$idArg}";
	$r = $httpRequest($url);
	if(isset($r['error'])) exit(json_encode(['code'=>-10,'msg'=>$r['error']], JSON_UNESCAPED_UNICODE));
	$d = json_decode($r['result'], true);
	if(json_last_error() === JSON_ERROR_NONE){
		if(isset($d['code']) && intval($d['code']) === 0){
			exit(json_encode(['code'=>1,'msg'=>'操作成功','data'=>$d['data'] ?? $d], JSON_UNESCAPED_UNICODE));
		}
		$isPcNotPurchased = ($projectKey === 'dnzx' && isset($d['code']) && intval($d['code']) === 500 && strtolower(trim((string)($d['msg'] ?? ''))) === 'success');
		if($isPcNotPurchased){
			exit(json_encode(['code'=>-15,'msg'=>'未购买电脑加速，请先购买后再操作','data'=>$d], JSON_UNESCAPED_UNICODE));
		}
		exit(json_encode(['code'=>-11,'msg'=>$d['msg'] ?? '节点返回数据错误','data'=>$d], JSON_UNESCAPED_UNICODE));
	}
	exit(json_encode(['code'=>1,'msg'=>'操作成功','data'=>$r['result']], JSON_UNESCAPED_UNICODE));
break;
case 'qzone_qqlist':
	// 秒赞版QQ列表
	$qzone_table = (defined('DBQZ') ? DBQZ : 'pre_') . 'qzone_qq';
	$has_qzone = $DB->getColumn("SHOW TABLES LIKE '" . str_replace("'","\\'",$qzone_table) . "'");
	if(!$has_qzone){
		exit(json_encode(['code' => -1, 'msg' => '秒赞系统未安装', 'total' => 0, 'data' => []]));
	}
	$pagesize = isset($_GET['pagesize'])?intval($_GET['pagesize']):10;
	$page = isset($_GET['page'])?intval($_GET['page']):1;
	$offset = $pagesize*($page - 1);
	$user_id = $userrow['zid'];
	
	$rs = $DB->query("SELECT * FROM `{$qzone_table}` WHERE user_id='{$user_id}' ORDER BY id DESC LIMIT {$offset},{$pagesize}");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$item = [
			'id' => $res['id'],
			'qq' => $res['qq'],
			'nickname' => $res['nickname'] ?? '',
			'login_zt' => ($res['login_status'] == 0) ? 1 : 0, // 0表示正常
			'endtime' => $res['vip_time'] ?? '',
			'endtime_arr' => [],
			'login_class_name' => '秒赞版',
			'isend' => (strtotime($res['vip_time'] ?? '') < time()) ? 1 : 0
		];
		$data[] = $item;
	}
	$total = $DB->getColumn("SELECT count(*) FROM `{$qzone_table}` WHERE user_id='{$user_id}'");
	$pages = ceil($total/$pagesize) ?: 1;
	exit(json_encode(['code' => 1, 'total' => $total, 'page' => $page, 'end' => $pages, 'data' => $data]));
break;
case 'pay_kami':
	if($conf['kami_open'] != '1')exit('{"code":-1,"msg":"卡密功能已关闭"}');
	$km = daddslashes($_POST['km']);
	$qq = daddslashes($_POST['qq']);
	if(!preg_match('/^[0-9]{5,12}$/', $qq))exit('{"code":-1,"msg":"续费QQ格式不正确"}');
	if(in_array($qq,explode("-",$conf['blacklist'])))exit('{"code":-1,"msg":"你的下单账号已被拉黑，无法下单！"}');
	$kmrow = $DB->getRow("SELECT * FROM `pre_km` WHERE km='{$km}' LIMIT 1");
	if(!$kmrow)exit('{"code":-1,"msg":"卡密不存在"}');
	if($kmrow['isuse'] == '1')exit('{"code":-1,"msg":"该卡密已经被使用"}');

	$qzone_enabled = (($conf['qzone_open'] ?? ($conf['qzone_enabled'] ?? '0')) == '1');
	$cloud_enabled = (($conf['cloud_enabled'] ?? '1') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');
	$km_version = isset($kmrow['version']) && $kmrow['version'] !== '' ? $kmrow['version'] : 'cloud';

	$time_type = isset($kmrow['time']) ? intval($kmrow['time']) : 0;
	$time_num = isset($kmrow['time_num']) ? intval($kmrow['time_num']) : 0;
	$goods_type = 0;
	$shopid = intval($kmrow['shopid']);
	$tmp_goods = null;
	if($shopid > 0 && $shopid != 9999){
		$tmp_goods = $DB->getRow("SELECT * FROM `pre_goods` WHERE id='{$shopid}' LIMIT 1");
	}

	$card_type = isset($kmrow['card_type']) ? intval($kmrow['card_type']) : 0;
	$goods_id = $tmp_goods ? $shopid : ($shopid == 9999 ? 9999 : 0);
	$special_check_id = 0;
	$special_check_version = $tmp_goods && isset($tmp_goods['version']) ? normalize_goods_version($tmp_goods['version']) : normalize_goods_version($km_version);
	if($card_type == 1){
		if($tmp_goods){
			$special_check_id = $shopid;
		} elseif ($shopid > 0 && $time_num >= 1) {
			$special_check_id = $shopid;
		}
        if($special_check_id > 0){
			if(has_special_card_usage($qq, $special_check_id, $special_check_version)){
				exit('{"code":-1,"msg":"该QQ已激活过此商品的特殊卡，无法重复激活"}');
			}
		}
	}

	if($shopid == 9999){
		// 全部分类卡密
		$goods_type = 9999;
		$goods = [
			'time_type' => $kmrow['time'],
			'num' => $kmrow['time_num'],
			'type' => 9999
		];
	}elseif($tmp_goods){
		if(isset($tmp_goods['time_type'])) $time_type = intval($tmp_goods['time_type']);
		if(isset($tmp_goods['num']) && $tmp_goods['num'] > 0) $time_num = intval($tmp_goods['num']);
		if(isset($tmp_goods['version']) && $tmp_goods['version']) $km_version = $tmp_goods['version'];
		if(isset($tmp_goods['type'])) $goods_type = intval($tmp_goods['type']);
		$goods = $tmp_goods;
	}elseif($shopid > 0 && $time_num >= 1){
		$class_info = $DB->getRow("SELECT id,name FROM pre_login_class WHERE id='{$shopid}' LIMIT 1");
		if($class_info){
			$goods['time_type'] = $time_type;
			$goods['num'] = $time_num;
			$goods['type'] = $shopid;
			$goods_type = $shopid;
		}
	}
	$km_version = normalize_goods_version($km_version);
	$ret = apply_goods_services($userrow, $qq, $goods, $km_version, false);
	if($ret['code'] != 1){
		exit(json_encode(['code'=>$ret['code'], 'msg'=>$ret['msg']], JSON_UNESCAPED_UNICODE));
	}
	$km_version = $ret['version'];
	$added_days = intval($ret['added_days'] ?? 0);
	$label_parts = $ret['label_parts'] ?? [];
	$dur_label = trim((string)($ret['duration_label'] ?? ''));
	if ($dur_label === '') {
		$dur_label = ($added_days >= 1825) ? '永久' : ($added_days.'天');
	}

	$DB->exec("UPDATE `pre_km` SET `isuse`='1', `qq`='{$qq}', `usetime`=NOW() WHERE km='{$km}'");

	if($card_type == 1){
		$record_id = 0;
		if($tmp_goods){
			$record_id = $shopid;
		} elseif ($shopid > 0 && $time_num >= 1) {
			$record_id = $shopid;
		}
        if($record_id > 0){
			record_special_card_usage($qq, $record_id, $kmrow['id'], $km_version);
		}
	}

	add_money_log($userrow['zid'],'卡密','卡密','0.00',$userrow['rmb_tc'],$userrow['rmb_tc'],'QQ='.$qq.',km='.$km.',卡密激活['.$kmrow['name'].']');
	if($conf['kami_tc'] == 1 && $kmrow['zid'] != 1 && floatval($kmrow['tc_rmb']) > 0){
		$km_creator = $DB->getRow("SELECT upzid FROM pre_user WHERE zid='{$kmrow['zid']}' LIMIT 1");
		if($km_creator && $km_creator['upzid'] > 1){
			$upzid = $km_creator['upzid'];
			$up_user = $DB->getRow("SELECT zid, rmb_tc FROM pre_user WHERE zid='{$upzid}' LIMIT 1");
			if($up_user){
				$tc_rmb = floatval($kmrow['tc_rmb']);
				$DB->exec("UPDATE pre_user SET `rmb_tc`=`rmb_tc`+'{$tc_rmb}' WHERE zid='{$upzid}'");
				add_money_log($upzid,'佣金','提成',$tc_rmb,$up_user['rmb_tc'],($up_user['rmb_tc']+$tc_rmb),'用户='.$kmrow['zid'].',QQ='.$qq.',卡密激活['.$kmrow['name'].']');
			}
		}
	}
	$label_parts = array_values(array_unique(array_filter($label_parts)));
	$cat_label = count($label_parts) ? implode(' + ', $label_parts) : '服务';
	exit('{"code":1,"msg":"开通（'.$cat_label.'）成功 + '.$dur_label.'","version":"'.addslashes($km_version).'"}');
break;
case 'pay':
	$id = intval($_POST['goods']);
	$qq = daddslashes($_POST['qq']);
	$type = intval($_POST['type']);	//99是用户等级
	if(in_array($qq,explode("-",$conf['blacklist'])))exit('{"code":-1,"msg":"你的下单账号已被拉黑，无法下单！"}');
	$qzone_enabled = (($conf['qzone_open'] ?? ($conf['qzone_enabled'] ?? '0')) == '1');
	$cloud_enabled = (($conf['cloud_enabled'] ?? '1') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');

	if($type == 99){
		$user_vip = $DB->getRow("SELECT * FROM pre_user_vip WHERE id='{$id}' LIMIT 1");
		if(!$user_vip)exit('{"code":-1,"msg":"该等级数据不存在"}');
		if($userrow['vip'] >= $user_vip['vip'])exit('{"code":-1,"msg":"不能购买比自身还小的等级<br>您当前等级为：'.$userrow['vip'].'"}');

		//计算等级差价
		if(intval($conf['user_vip_cj']) == 1 && intval($userrow['vip']) > 1){
			$t = $DB->getRow("SELECT * FROM pre_user_vip WHERE vip='{$userrow['vip']}' LIMIT 1");
			$user_vip['price'] = floatval($user_vip['price'])-floatval($t['price']);
		}
		
		// 应用活动折扣
		$activity_discount = get_vip_activity_discount();
		$actual_price = round(floatval($user_vip['price']) * $activity_discount / 100, 2);
		
		if($actual_price > $userrow['rmb'])exit('{"code":-2,"msg":"余额不足请充值<br>相差 '.($actual_price-$userrow['rmb']).' 元"}');
		$DB->exec("UPDATE pre_user SET `rmb`=`rmb`-'{$actual_price}',`vip`='{$user_vip['vip']}' WHERE zid='{$userrow['zid']}'");
		add_money_log($userrow['zid'],'余额','消费',-$actual_price,$userrow['rmb'],($userrow['rmb']-$actual_price),'您购买['.$user_vip['name'].']平台等级，消费'.$actual_price.'元');
		send_user_business_notice('consume', [
			'amount' => $actual_price,
			'balance' => $userrow['rmb'] - $actual_price,
			'goods' => '平台等级-'.$user_vip['name'],
			'version' => '平台等级',
			'qq' => $qq,
			'remark' => '余额购买平台等级'
		]);
		userCommission_grade($userrow, $user_vip, $actual_price);
		exit('{"code":1,"msg":"下单成功"}');

	}else{
		$goods = $DB->getRow("SELECT * FROM pre_goods WHERE id='{$id}' LIMIT 1");
		if(!$goods)exit('{"code":-1,"msg":"该商品不存在"}');
		$has_goods_limit_once_col = $DB->getColumn("SHOW COLUMNS FROM pre_goods LIKE 'limit_once'");
		$limit_once = $has_goods_limit_once_col ? intval($goods['limit_once']) : 0;
		$goods_version = normalize_goods_version(isset($goods['version']) ? $goods['version'] : '', 'cloud');
		$precheck = apply_goods_services($userrow, $qq, $goods, $goods_version, true);
		if($precheck['code'] != 1){
			exit(json_encode(['code'=>$precheck['code'], 'msg'=>$precheck['msg']], JSON_UNESCAPED_UNICODE));
		}
		if($limit_once == 1 && has_limit_once_purchase($qq, $goods['id'], $goods_version)){
			exit('{"code":-1,"msg":"该商品限购一次，当前QQ已购买"}');
		}

		$vipnum = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
		$arr = get_price_arr($userrow,$goods,$vipnum);
		$money = $arr['price'][$userrow['zid']];

		if($money > $userrow['rmb'])exit('{"code":-2,"msg":"余额不足请充值<br>相差 '.($money-$userrow['rmb']).' 元"}');

		$ret = apply_goods_services($userrow, $qq, $goods, $goods_version, false);
		if($ret['code'] != 1){
			exit(json_encode(['code'=>$ret['code'], 'msg'=>$ret['msg']], JSON_UNESCAPED_UNICODE));
		}
		$goods_version = $ret['version'];
		$added_days = intval($ret['added_days'] ?? 0);
		$label_parts = $ret['label_parts'] ?? [];
		$label_parts = array_values(array_unique(array_filter($label_parts)));
		$cat_label = count($label_parts) ? implode(' + ', $label_parts) : '服务';
		$dur_label = trim((string)($ret['duration_label'] ?? ''));
		if ($dur_label === '') {
			$dur_label = ($added_days >= 1825) ? '永久' : ($added_days.'天');
		}
		$msg = '开通（'.$cat_label.'）成功 + '.$dur_label;
		if(1){
			$DB->exec("UPDATE `pre_user` SET `rmb`=`rmb`-'{$money}' WHERE zid='{$userrow['zid']}'");
			add_money_log($userrow['zid'],'余额','消费',-$money,$userrow['rmb'],($userrow['rmb']-$money),'QQ='.$qq.',您购买商品['.$goods['name'].']，消费 '.$money.'元');
			send_user_business_notice('consume', [
				'amount' => $money,
				'balance' => $userrow['rmb'] - $money,
				'goods' => $goods['name'],
				'version' => $goods_version,
				'qq' => $qq,
				'remark' => '余额购买商品'
			]);
			userCommission($userrow,$goods);
			if($limit_once == 1){
				record_limit_once_purchase($qq, $goods['id'], $goods_version, 0);
			}
			exit('{"code":1,"msg":"'.$msg.'","version":"'.addslashes($goods_version).'"}');
		}else{
			exit('{"code":-1,"msg":"下单失败'.$DB->error().'"}');
		}
	}
break;
case 'dopay':
	$qq = daddslashes($_GET['qq']);
	$id = daddslashes($_GET['id']);
	$grade = daddslashes($_GET['grade']);
	if(in_array($qq,explode("-",$conf['blacklist'])))exit('{"code":-1,"msg":"你的下单账号已被拉黑，无法下单！"}');
	$qzone_enabled = (($conf['qzone_open'] ?? ($conf['qzone_enabled'] ?? '0')) == '1');
	$cloud_enabled = (($conf['cloud_enabled'] ?? '1') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');

	if($grade == '99'){
		$goods = $DB->getRow("SELECT * FROM pre_user_vip WHERE id='{$id}' LIMIT 1");
		if(!$goods)exit('{"code":-1,"msg":"该等级数据不存在"}');
		if($userrow['vip'] >= $goods['vip'])exit('{"code":-1,"msg":"不能购买比自身还小的等级<br>您当前等级为：'.$userrow['vip'].'"}');
		$goods['name'] = '提升等级：' . $goods['name'];
		if(intval($conf['user_vip_cj']) == 1 && intval($userrow['vip']) > 1){
			$t = $DB->getRow("SELECT * FROM pre_user_vip WHERE vip='{$userrow['vip']}' LIMIT 1");
			$goods['price'] = floatval($goods['price'])-floatval($t['price']);
		}
		// 对于等级升级，直接使用计算好的价格（含差价）
		$money = floatval($goods['price']);
		$vip_discount = get_vip_activity_discount();
		$money = round($money * $vip_discount / 100, 2);

	}else{
		$goods = $DB->getRow("SELECT * FROM pre_goods WHERE id='{$id}' LIMIT 1");
		if(!$goods)exit('{"code":-1,"msg":"该商品不存在"}');
		$has_goods_limit_once_col = $DB->getColumn("SHOW COLUMNS FROM pre_goods LIKE 'limit_once'");
		$limit_once = $has_goods_limit_once_col ? intval($goods['limit_once']) : 0;
		$goods_version = normalize_goods_version(isset($goods['version']) ? $goods['version'] : '', 'cloud');
		$precheck = apply_goods_services($userrow, $qq, $goods, $goods_version, true);
		if($precheck['code'] != 1){
			exit(json_encode(['code'=>$precheck['code'], 'msg'=>$precheck['msg']], JSON_UNESCAPED_UNICODE));
		}
		if($limit_once == 1 && has_limit_once_purchase($qq, $goods['id'], $goods_version)){
			exit('{"code":-1,"msg":"该商品限购一次，当前QQ已购买"}');
		}
		
		$vipnum = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
		$arr = get_price_arr($userrow,$goods,$vipnum);
		$money = $arr['price'][$userrow['zid']];
	}

	$interface_id = intval($_GET['interface_id']);
	if($interface_id > 0){
		$interface = $DB->getRow("SELECT * FROM `pre_pay_interface` WHERE id='{$interface_id}' AND status=1 LIMIT 1");
		if(!$interface){
			exit('{"code":-1,"msg":"支付接口不存在或已禁用"}');
		}
		$type = $interface['pay_type'];
	}else{
		exit('{"code":-1,"msg":"请选择支付接口"}');
	}
	
	$trade_no=date("YmdHis").rand(111,999);
	if($money <= 0)exit('{"code":-1,"msg":"金额异常"}');
	$sql="INSERT INTO `pre_pay` (`trade_no`,`zid`,`name`,`status`,`money`,`addtime`,`type`,`tid`,`input`,`interface_id`) VALUES ('".$trade_no."','".$userrow['zid']."','".$goods['name']."','0','".$money."', NOW(),'".$type."','".$goods['id']."','".$qq."','".$interface_id."')";
	if($DB->exec($sql)){
		// 仅创建订单，不发送业务通知（通知应在支付成功回调 processOrder() 内发送）
		exit('{"code":0,"msg":"提交订单成功！","trade_no":"'.$trade_no.'","money":"'.$money.'","name":"在线开通","type":"'.$type.'"}');
	}else{
		exit('{"code":-1,"msg":"提交订单失败！'.$DB->error().'"}');
	}
break;
case 'get_goods':	//商品列表可以写入 缓存
	$data = array();
	$code = -1;
	$qzone_enabled = (($conf['qzone_open'] ?? ($conf['qzone_enabled'] ?? '0')) == '1');
	$cloud_enabled = (($conf['cloud_enabled'] ?? '1') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');

	$class=[];//默认分类
	$class2=[];//可见分类列表
	$show_apiclass = intval($conf['show_apiclass']);
	
	// 加载所有可见分类（active=0）
	$rs2=$DB->query("SELECT * FROM pre_login_class WHERE active='0' ORDER BY sort ASC");
	while($res2 = $rs2->fetch(PDO::FETCH_ASSOC)){
		if($show_apiclass == 0){
			$class[] = $res2;
		}
		$class2[$res2['id']] = $res2['name'];
	}

	$class2['9999'] = '全部接口';
	if($conf['show_all_goods']==1 && $show_apiclass == 0){
		$class[] = [
			'id' => '9999',
			'name' => '全部接口'
		];
	}

	//获取商品
	$pricerow = get_database('pre_price',1);
	$vipnum = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
	$rs=$DB->query("SELECT * FROM pre_goods WHERE status='1' ORDER BY sort ASC");
	$tri_pairs = []; // tri_all 组合分类: "cloudId:dgId" => "云端名称 + 代挂名称"
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		if(!isset($res['version']) || $res['version'] === '') $res['version'] = 'qzone';
		if($res['version'] === 'all') $res['version'] = 'cloud_all';
		if($res['version'] != 'qzone'){
			// 仅处理在可见分类下的商品（或者全部分类 ID 为 9999 的特殊商品）
			if($res['version'] === 'tri_all'){
				$type_cloud = intval($res['type_cloud'] ?? $res['type']);
				$type_dg = intval($res['type_dg'] ?? 0);
				if(!isset($class2[$type_cloud])) continue;
				// tri_all 允许代挂分类缺失时至少显示云端分类一侧
			}else{
				if(!isset($class2[$res['type']])) continue;
			}
		}

		// 计算用户等级折扣价格
		$arr = get_price_arr($userrow,$res,$vipnum);

		// 添加活动信息
		$activity_active = is_activity_active($res) ? 1 : 0;
		$activity_discount = get_activity_discount($res);

		// 返回价格信息
		// base_price = 商品原价
		// user_discount_price = 用户等级折扣后的价格（不含活动折扣）
		// price = 最终价格（含活动折扣）
		$res['base_price'] = floatval($res['price']); // 商品原始价格
		$res['user_discount_price'] = $arr['user_discount_price']; // 用户等级折扣后的价格
		$res['price'] = $arr['price'][$userrow['zid']]; // 最终价格（含活动折扣）

		$res['activity_active'] = $activity_active;
		$res['activity_discount'] = $activity_discount;
		if($activity_active == 1){
			$res['activity_start_text'] = isset($res['activity_start']) ? $res['activity_start'] : '';
			$res['activity_end_text'] = isset($res['activity_end']) ? $res['activity_end'] : '';
		}

		if($res['version'] == 'qzone' && !$qzone_enabled) continue;
		if($res['version'] == 'cloud' && !$cloud_enabled) continue;
		if($res['version'] == 'dg' && !$dg_enabled) continue;
		if($res['version'] == 'cloud_all' && !($qzone_enabled && $cloud_enabled)) continue;
		if($res['version'] == 'dg_all' && !($qzone_enabled && $dg_enabled)) continue;
		if($res['version'] == 'tri_all' && !($qzone_enabled && $cloud_enabled && $dg_enabled)) continue;

		if($res['version'] == 'qzone'){
			$data['qzone'][] = $res;
		}else{
			if($res['version'] === 'tri_all'){
				$type_cloud = intval($res['type_cloud'] ?? $res['type']);
				$type_dg = intval($res['type_dg'] ?? 0);
				$pair_key = $type_dg > 0 ? ($type_cloud.':'.$type_dg) : (string)$type_cloud;
				// 组合分类名称（两个都是“全部接口”时只显示一个）
				$cloud_name = $class2[$type_cloud] ?? ('云端('.$type_cloud.')');
				$dg_name = ($type_dg > 0) ? ($class2[$type_dg] ?? ('代挂('.$type_dg.')')) : '';
				if($type_cloud === 9999 && $type_dg === 9999){
					$pair_name = $cloud_name; // 只显示“全部接口”
				}else{
					$pair_name = $dg_name ? ($cloud_name.' + '.$dg_name) : $cloud_name;
				}
				$tri_pairs[$pair_key] = $pair_name;
				$data[$pair_key][] = $res;
			}else{
				if(isset($class2[$res['type']])){
					$data[$res['type']][] = $res;
				}
			}
		}
	}//获取商品 end

	//等级分类
	if(intval($conf['show_grade'])==0){
		$gradeid = '99';
		$vip = intval($userrow['vip']);
		$upzid = intval($userrow['upzid']);
		$grade_same_level = intval($conf['grade_same_level']);	//0允许1不允许
		$vip_num = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
		if($upzid >= 1000){
			if($vip != $vip_num){
				$urow = $DB->getRow("SELECT vip FROM pre_user WHERE zid='{$upzid}'");
				$vip_num = intval($urow['vip']);
			}
		}
		$vip_row = [];
		$rs=$DB->query("SELECT * FROM pre_user_vip ORDER BY vip ASC");
		while($res = $rs->fetch(PDO::FETCH_ASSOC)){
			$vip_row[$res['vip']] = $res;
		}
		$_vip_price = floatval($vip_row[$vip]['price']);
		for ($i=1; $i <= $vip_num; $i++) {
			if($i == 1)continue;
			if($upzid != 1){
				if($grade_same_level == 1){//不允许开通同级
					if($i >= $vip_num)continue;
				}else{
					if($i > $vip_num)continue;
				}
			}

			$res = $vip_row[$i];
			$vip_price = floatval($res['price']);
			if(intval($conf['user_vip_cj']) == 1 && $vip > 1){
				$vip_price = $vip_price-$_vip_price;
				$vip_price = $vip_price<0?0:$vip_price;
			}

			$data[$gradeid][] = [
				"id" => $res['id'],
				"sort" => 0,
				"name" => $res['name'].($i==$vip?'_ 当前等级':''),
				"type" => $gradeid,
				"num" => intval($res['vip']),
				"time_type" => 0,
				"price" => $vip_price,
				"priceid" => 0,
				"status" => 1,
				"desc" => $res['desc']
			];
		}
		if(is_array($data[$gradeid])){
			$class2[$gradeid] = '等级提升';
			$class[] = [
				'id' => $gradeid,
				'name' => '等级提升'
			];
		}
	}//等级分类 end

	// 将 tri_all 组合分类追加到可见分类列表（仅在展示分类模式下）
	if($show_apiclass == 0 && !empty($tri_pairs)){
		foreach($tri_pairs as $k=>$v){
			$class[] = ['id' => $k, 'name' => $v];
		}
	}
	if(count($data)!=0)$code = 1;
	exit(json_encode(array('code' => $code,'data' => $data,'class' => $class,'show_apiclass' => $show_apiclass)));	
break;
case 'add_kami':
	$cid = intval($_POST['cid']);
	$goods_id = intval($_POST['goods']);
	$num = intval($_POST['num']);
	$kmqz = daddslashes($_POST['kmqz']);
	$version = isset($_POST['version']) ? daddslashes($_POST['version']) : 'cloud';
	if(!in_array($version, ['cloud','dg','qzone','cloud_all','dg_all','tri_all','all'], true))exit('{"code":-1,"msg":"版本参数错误"}');
	$qzone_enabled = (($conf['qzone_open'] ?? ($conf['qzone_enabled'] ?? '0')) == '1');
	$cloud_enabled = (($conf['cloud_enabled'] ?? '1') == '1');
	$dg_enabled = (($conf['dg_open'] ?? '0') == '1');
	if($version == 'all') $version = 'cloud_all';
	$need_qzone = in_array($version, ['qzone','cloud_all','dg_all','tri_all'], true);
	$need_cloud = in_array($version, ['cloud','cloud_all','tri_all'], true);
	$need_dg = in_array($version, ['dg','dg_all','tri_all'], true);
	if($need_qzone && !$qzone_enabled)exit('{"code":-1,"msg":"秒赞系统未开启，无法生成该版本卡密"}');
	if($need_cloud && !$cloud_enabled)exit('{"code":-1,"msg":"云端系统未开启，无法生成该版本卡密"}');
	if($need_dg && !$dg_enabled)exit('{"code":-1,"msg":"代挂系统未开启，无法生成该版本卡密"}');
	$time = isset($_POST['time']) ? intval($_POST['time']) : 1;
	$time_num = isset($_POST['time_num']) ? intval($_POST['time_num']) : 30;
	$time_arr = [0=>'月',1=>'天',2=>'时',3=>'年'];

	if($version == 'qzone'){
		if($goods_id > 0){
			$goods_info = $DB->getRow("SELECT * FROM pre_goods WHERE id='{$goods_id}' AND version='qzone' LIMIT 1");
			if(!$goods_info)exit('{"code":-1,"msg":"秒赞版商品不存在"}');
			$vipnum = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
			$arr = get_price_arr($userrow,$goods_info,$vipnum);
			$money = $arr['price'][$userrow['zid']] * $num;
			$km_time = isset($goods_info['time_type']) ? $goods_info['time_type'] : 1;
			$km_time_num = isset($goods_info['num']) ? $goods_info['num'] : 30;
		}else{
			$goods_info = ['id'=>0,'name'=>'秒赞版_'.$time_num.$time_arr[$time],'price'=>0,'time_type'=>$time,'num'=>$time_num,'type'=>0];
			$km_time = $time;
			$km_time_num = $time_num;
			$money = 0;
		}
	}else{
		$goods_info = $DB->getRow("SELECT * FROM pre_goods WHERE id='{$goods_id}' LIMIT 1");
		if(!$goods_info)exit('{"code":-1,"msg":"该商品不存在"}');
		$goods_version = isset($goods_info['version']) && $goods_info['version'] !== '' ? $goods_info['version'] : 'cloud';
		if($goods_version === 'all') $goods_version = 'cloud_all';
		if($version === 'cloud' && $goods_version !== 'cloud')exit('{"code":-1,"msg":"请选择云端版商品"}');
		if($version === 'dg' && $goods_version !== 'dg')exit('{"code":-1,"msg":"请选择代挂版商品"}');
		if($version === 'cloud_all' && $goods_version !== 'cloud_all')exit('{"code":-1,"msg":"请选择云端通用商品"}');
		if($version === 'dg_all' && $goods_version !== 'dg_all')exit('{"code":-1,"msg":"请选择代挂通用商品"}');
		if($version === 'tri_all' && $goods_version !== 'tri_all')exit('{"code":-1,"msg":"请选择三版通用商品"}');
		$vipnum = $DB->getColumn("SELECT count(*) FROM pre_user_vip");
		$arr = get_price_arr($userrow,$goods_info,$vipnum);
		$money = $arr['price'][$userrow['zid']] * $num;
		$version = $goods_version;
		$km_time = isset($goods_info['time_type']) ? $goods_info['time_type'] : 0;
		$km_time_num = isset($goods_info['num']) ? $goods_info['num'] : 0;
	}

	if($goods_id > 0 && !empty($goods_info) && intval($goods_info['limit_once']) === 1){
		exit('{"code":-1,"msg":"限购商品不支持生成卡密"}');
	}

	if($money > $userrow['rmb'])exit('{"code":-2,"msg":"余额不足请充值<br>相差 '.($money-$userrow['rmb']).' 元"}');

	$DB->exec("UPDATE pre_user SET `rmb`=`rmb`-'{$money}' WHERE zid='{$userrow['zid']}'");
	// 卡密类型命名：商品名称_全部接口（当商品分类为全部接口时）
	$km_type_name = $goods_info['name'];
	if(intval($goods_info['type']) === 9999){
		$km_type_name = $goods_info['name'].'_全部接口';
	}
	add_money_log($userrow['zid'],'余额','消费',-$money,$userrow['rmb'],($userrow['rmb']-$money),'生成['.$km_type_name.']卡密 '.$num.' 张，消费'.$money.'元');
	send_user_business_notice('consume', [
		'amount' => $money,
		'balance' => $userrow['rmb'] - $money,
		'goods' => '生成卡密-'.$km_type_name.' x'.$num,
		'version' => $version,
		'qq' => '',
		'remark' => '余额生成卡密'
	]);

	// 预计算提成金额（生成时锁定提成）
	$single_price = $money / $num;
	$tc_rmb = calc_kami_tc_rmb($userrow, $goods_info, $single_price);

	$kmarr = array();
	for($i=1;$i<=$num;$i++){
		// 生成包含字母和数字的随机字符串
		$random_str = '';
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
		$chars_length = strlen($chars);
		for($j=0;$j<12;$j++){
			$random_str .= $chars[rand(0, $chars_length - 1)];
		}
		// 构建卡密：前缀 + _ + 随机字符串
		if(!empty($kmqz)){
			$km = $kmqz . '_' . $random_str;
		}else{
			$km = $random_str;
		}
		$has_km_version_col = $DB->getColumn("SHOW COLUMNS FROM pre_km LIKE 'version'");
		$has_km_time_col = $DB->getColumn("SHOW COLUMNS FROM pre_km LIKE 'time'");
		$has_km_time_num_col = $DB->getColumn("SHOW COLUMNS FROM pre_km LIKE 'time_num'");
		$km_cols = ['zid','km','name','shopid','rmb','tc_rmb','isuse','addtime'];
		$km_vals = ["'".$userrow['zid']."'", "'".$km."'", "'".$km_type_name."'", "'".$goods_info['id']."'", "'".$single_price."'", "'".$tc_rmb."'", "'0'", "NOW()"];
		if($has_km_version_col){
			$km_cols[] = 'version';
			$km_vals[] = "'".$version."'";
		}
		if($has_km_time_col){
			$km_cols[] = 'time';
			$km_vals[] = "'".$km_time."'";
		}
		if($has_km_time_num_col){
			$km_cols[] = 'time_num';
			$km_vals[] = "'".$km_time_num."'";
		}
		$DB->exec("INSERT INTO `pre_km` (`".implode('`,`',$km_cols)."`) VALUES (".implode(',',$km_vals).")");
		$kmarr[] = $km;
	}
	exit(json_encode(array('code'=>1,'msg'=>'生成成功','km'=>implode("\r\n",$kmarr))));
break;

case 'getapi':
	$biz = isset($_GET['biz']) ? daddslashes($_GET['biz']) : 'cloud';
	$biz = $biz === 'dg' ? 'dg' : 'cloud';
	if($biz === 'dg' && (($conf['dg_open'] ?? '0') != '1')){
		exit(json_encode(['data'=>[],'class'=>[],'protocol'=>[],'login_config'=>['login_tip'=>'','open_qq_quick'=>0,'api_error_tip'=>html_entity_decode($conf['api_error_tip'] ?? '本节点可能存在异常，请选择其他节点'),'login_select_open'=>1,'show_apiclass'=>intval($conf['show_apiclass'])]], JSON_UNESCAPED_UNICODE));
	}
	if($biz === 'cloud' && (($conf['cloud_enabled'] ?? '1') != '1')){
		exit(json_encode(['data'=>[],'class'=>[],'protocol'=>[],'login_config'=>['login_tip'=>'','open_qq_quick'=>0,'api_error_tip'=>html_entity_decode($conf['api_error_tip'] ?? '本节点可能存在异常，请选择其他节点'),'login_select_open'=>1,'show_apiclass'=>intval($conf['show_apiclass'])]], JSON_UNESCAPED_UNICODE));
	}
	if($conf['login_api_sort'] == 1){
		$sort = ' online_census DESC';
	}elseif($conf['login_api_sort'] == 2){
		$sort = ' online_census ASC';
	}else{
		$sort = ' sort ASC';
	}

	$class=[];
	$class2=[];//可见分类列表
	$show_apiclass = intval($conf['show_apiclass']);
	
	// 加载所有可见分类（active=0）
	$rs2=$DB->query("SELECT id,name,free FROM pre_login_class WHERE active='0' AND biz='{$biz}' ORDER BY sort ASC");
	while($res2 = $rs2->fetch(PDO::FETCH_ASSOC)){
		if($show_apiclass == 0){
			$class[] = ['id' => $res2['id'], 'name' => $res2['name'], 'free' => $res2['free']];
		}
		$class2[$res2['id']] = $res2['name'];
	}

	$class2['9999'] = '全部接口';
	
	$protocol = [];
	$rs3=$DB->query("SELECT * FROM pre_protocol WHERE status='1' ORDER BY sort ASC");
	while($res3 = $rs3->fetch(PDO::FETCH_ASSOC)){
		$protocol[$res3['cid']][] = [
			'type' => $res3['type'],
			'name' => $res3['name'],
			'is_pwd' => $res3['is_pwd']
		];
	}
	
	$qq_check = isset($_GET['qq']) ? daddslashes($_GET['qq']) : '';
	$endtime_arr_json = '';
	if($qq_check && strlen($qq_check) >= 4){
		$qq_table = $biz === 'dg' ? 'pre_dg_qq' : 'pre_qq';
		$qqrow = $DB->getRow("SELECT endtime_arr FROM `{$qq_table}` WHERE qq='{$qq_check}' AND zid='".$userrow['zid']."' LIMIT 1");
		$endtime_arr_json = $qqrow['endtime_arr'] ?? '';
	}
	$rs=$DB->query("SELECT id,cid,cids,type,citybz,apipwd,msg,msg_type,api_error_check,show_online_census,online_census FROM `pre_loginconfig` WHERE status='1' AND biz='{$biz}' ORDER BY".$sort);
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		// 仅处理在可见分类下的接口（或者全部分类 ID 为 9999 的特殊接口）
		if(!isset($class2[$res['cids']])) continue;

		$type = $res['cid']=='' ? $res['type'] : $res['cid'];
		if($res['apipwd'] == '0' && $conf['show_free_login'] == 1) $res['citybz'] = '(免费) '.$res['citybz'];
		// apipwd 为空=收费节点(需购买)，为'0'=免费节点，有值=需要密码的免费节点
		$apipwd_value = ($res['apipwd'] && $res['apipwd'] !== '0') ? '1' : $res['apipwd'];
		$can_use = 0;
		if($qq_check){
			$is_free = ($res['apipwd'] !== '' && $res['apipwd'] !== null);
			$has_endtime = !is_end_for_can_use($endtime_arr_json ?: '{}', $res);
			$can_use = ($has_endtime || $is_free) ? 1 : 0;
		}else{
			$can_use = 1;
		}
		$item = [
			'id' => $res['id'],
			'type' => $type,
			'apipwd' => $apipwd_value,
			'citybz' => $res['citybz'],
			'msg' => $res['msg'],
			'msg_type' => $res['msg_type'],
			'api_error_check' => $res['api_error_check'],
			'show_online_census' => $res['show_online_census'],
			'online_census' => $res['online_census'],
			'can_use' => $can_use
		];
		if(isset($class2[$res['cids']])){
			$data[$res['cids']][] = $item;
		}
	}

	if (function_exists('nodeLinkGetAllNodes')) {
		$nodeLinkNodes = nodeLinkGetAllNodes($biz);
		foreach ($nodeLinkNodes as $node) {
			$nodeCids = $node['cids'] ?: 0;
			if (!isset($class2[$nodeCids])) continue;

			$apipwd_value = ($node['apipwd'] && $node['apipwd'] !== '0') ? '1' : ($node['apipwd'] ?? '');

			$item = [
				'id' => $node['id'],
				'type' => $node['type'] ?? '',
				'apipwd' => $apipwd_value,
				'citybz' => $node['citybz'],
				'msg' => $node['msg'],
				'msg_type' => $node['msg_type'] ?? 0,
				'api_error_check' => $node['api_error_check'] ?? 1,
				'show_online_census' => $node['show_online_census'],
				'online_census' => $node['online_census'],
				'can_use' => 1,
				'is_node_link' => true
			];

			$data[$nodeCids][] = $item;

			$nodeType = $node['type'] ?? '';
			$nodeProtocolJson = $node['protocol'] ?? '';
			$frameworkType = $node['framework_type'] ?? '';
			$nodeCid = $node['cid'] ?? '';

			if ($nodeType && $nodeProtocolJson) {
				$nodeProtocol = json_decode($nodeProtocolJson, true);
				if (is_array($nodeProtocol) && !empty($nodeProtocol)) {
					$formattedProtocol = [];
					foreach ($nodeProtocol as $p) {
						if (isset($p['type']) && isset($p['name'])) {
							$formattedProtocol[] = [
								'type' => $p['type'],
								'name' => $p['name'],
								'is_pwd' => $p['is_pwd'] ?? 1
							];
						}
					}
					if (!empty($formattedProtocol)) {
						$protocol[$nodeType] = $formattedProtocol;
					}
				}
			} elseif ($nodeCid && isset($protocol[$nodeCid])) {
				if ($nodeType && $nodeType !== $nodeCid) {
					$protocol[$nodeType] = $protocol[$nodeCid];
				}
			} elseif ($nodeType && !isset($protocol[$nodeType])) {
				if ($frameworkType && isset($protocol[$frameworkType])) {
					$protocol[$nodeType] = $protocol[$frameworkType];
				}
			}
		}
	}
	
	$login_config = [
		'login_tip' => html_entity_decode($conf['login_tip'] ?? ''),
		'open_qq_quick' => $conf['open_qq_quick'] ?? 0,
		'api_error_tip' => html_entity_decode($conf['api_error_tip'] ?? '本节点可能存在异常，请选择其他节点'),
		'login_select_open' => ((string)($conf['login_select_str'] ?? '1') === '0') ? 0 : 1,
		'show_apiclass' => $show_apiclass
	];
	
	exit(json_encode(array('data' => $data,'class' => $class,'protocol' => $protocol,'login_config' => $login_config)));
break;
case 'check_api':
	$id = daddslashes($_POST['id']);
	$login = $DB->getRow("SELECT * FROM pre_loginconfig WHERE id='{$id}' LIMIT 1");
	if(!$login) {
		exit(json_encode(['code' => -1, 'msg' => '节点不存在']));
	}
	$url = $login['url'];
	if(!$url){
		exit(json_encode(['code' => -1, 'msg' => 'url empty']));
	}
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, false);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
	curl_setopt($ch, CURLOPT_TIMEOUT, 5);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	$resp = curl_exec($ch);
	$err = curl_error($ch);
	$http = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
	$t = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
	curl_close($ch);
	if($resp === false && $http === 0){
		exit(json_encode(['code'=>-1,'msg'=>$err?:'request failed']));
	}
	exit(json_encode(['code'=>1,'msg'=>'ok','http'=>$http,'time'=>$t]));
break;
case 'get_carousel':
	$pagesize = isset($_POST['pagesize'])?intval($_POST['pagesize']):10;
	$page=isset($_POST['page'])?intval($_POST['page']):1;
	$keyword=isset($_POST['keyword'])?daddslashes($_POST['keyword']):'';
	$offset=$pagesize*($page - 1);
	
	$sql = "1";
	if($keyword != ''){
		$sql .= " AND title LIKE '%{$keyword}%'";
	}
	
	$rs=$DB->query("SELECT * FROM pre_carousel WHERE {$sql} ORDER BY sort ASC, id DESC LIMIT $offset,$pagesize");
	$data = array();
	while($res = $rs->fetch(PDO::FETCH_ASSOC)){
		$data[] = $res;
	}
	
	if(count($data) == 0){
		$total = 0;
		$pages = 1;
	}else{
		$total = $DB->getColumn("SELECT count(*) FROM pre_carousel WHERE {$sql}");
		$pages = ceil($total/$pagesize);
	}
	exit(json_encode(array('code' => 1, 'total' => $total, 'page' => $page, 'end' => $pages, 'data'=>$data)));
break;
default:
	exit('{"code":-4,"msg":"No Act"}');
break;
}
