Files
kitchen/docs/api/api_feed.php
2026-04-11 07:07:13 +08:00

824 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 📱 信息流接口
*
* 支持多种信息流类型:
* - recommend: 推荐流(热门+最新+随机混合)
* - latest: 最新发布
* - hot: 热门排行
* - follow: 关注动态需要用户ID
*
* 性能优化支持缓存、Stale模式、多格式输出
*/
$startTime = microtime(true);
define('ZBP_HOOKERROR', false);
require '../zb_system/function/c_system_base.php';
$zbp->Load();
require_once 'cache.php';
require_once 'response.php';
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Cache-Control: public, max-age=300');
$act = strtolower(trim($_GET['act'] ?? 'feed'));
$format = ApiResponse::getFormat();
$forceRefresh = isset($_GET['_refresh']) && $_GET['_refresh'] === '1';
$staleMode = isset($_GET['_stale']) && $_GET['_stale'] === '1';
$cacheableActs = array('feed', 'recommend', 'latest', 'hot', 'personal');
if (in_array($act, $cacheableActs) && !$forceRefresh) {
$cacheParams = $_GET;
unset($cacheParams['act']);
unset($cacheParams['_refresh']);
unset($cacheParams['_stale']);
unset($cacheParams['_format']);
unset($cacheParams['_pretty']);
$cachedResult = ApiCache::get('feed', $cacheParams);
if ($cachedResult !== null) {
header('X-Cache: HIT');
$cachedResult['_cached'] = true;
$cachedResult['_cache_age'] = ApiCache::getCacheAge('feed', $cacheParams);
$cachedResult['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
ApiResponse::output($cachedResult, $format);
exit;
}
if ($staleMode || isset($_SERVER['HTTP_X_STALE_CACHE'])) {
$staleResult = ApiCache::getStale('feed', $cacheParams);
if ($staleResult !== null) {
header('X-Cache: STALE');
$staleResult['_cached'] = true;
$staleResult['_stale'] = true;
$staleResult['_cache_age'] = ApiCache::getCacheAge('feed', $cacheParams);
$staleResult['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
ApiResponse::output($staleResult, $format);
exit;
}
}
}
header('X-Cache: MISS');
$result = array();
switch ($act) {
case 'feed':
case 'recommend':
$result = get_recommend_feed();
break;
case 'latest':
$result = get_latest_feed();
break;
case 'hot':
$result = get_hot_feed();
break;
case 'personal':
$result = get_personal_feed();
break;
case 'prefetch':
$result = get_prefetch_feed();
break;
case 'index':
default:
$result = get_feed_index();
break;
}
if (in_array($act, $cacheableActs) && $result['code'] === 200) {
$cacheParams = $_GET;
unset($cacheParams['act']);
unset($cacheParams['_format']);
unset($cacheParams['_pretty']);
ApiCache::set('feed', $cacheParams, $result);
}
$result['_query_time'] = round((microtime(true) - $startTime) * 1000, 2) . 'ms';
ApiResponse::output($result, $format);
exit;
/**
* 信息流接口索引
*/
function get_feed_index() {
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'description' => '信息流接口',
'types' => array(
array(
'type' => 'recommend',
'name' => '推荐流',
'description' => '热门+最新+随机混合推荐',
'example' => '?act=recommend&page=1'
),
array(
'type' => 'latest',
'name' => '最新流',
'description' => '按发布时间排序',
'example' => '?act=latest&page=1'
),
array(
'type' => 'hot',
'name' => '热门流',
'description' => '按浏览量排序',
'example' => '?act=hot&page=1'
),
array(
'type' => 'personal',
'name' => '个性化流',
'description' => '基于用户偏好推荐',
'example' => '?act=personal&user_id=xxx'
),
array(
'type' => 'prefetch',
'name' => '预加载',
'description' => '预加载下一页数据',
'example' => '?act=prefetch&pages=3'
)
),
'params' => array(
'page' => '页码默认1',
'limit' => '每页数量默认20最大50',
'user_id' => '用户ID个性化流必填',
'cate_id' => '分类筛选',
'exclude' => '排除已读ID逗号分隔'
)
)
);
}
/**
* 推荐信息流(混合推荐)
*/
function get_recommend_feed() {
global $zbp;
$page = (int) ($_GET['page'] ?? 1);
$limit = (int) ($_GET['limit'] ?? 20);
$cateId = (int) ($_GET['cate_id'] ?? 0);
$excludeIds = isset($_GET['exclude']) ? array_map('intval', explode(',', $_GET['exclude'])) : array();
if ($limit > 50) $limit = 50;
if ($limit < 1) $limit = 20;
if ($page < 1) $page = 1;
$tablePost = $zbp->db->dbpre . 'post';
$tableCategory = $zbp->db->dbpre . 'category';
$tablePostStat = $zbp->db->dbpre . 'post_stat';
$tableRecipeIdMap = $zbp->db->dbpre . 'recipe_id_map';
$offset = ($page - 1) * $limit;
$whereSql = "WHERE p.log_Type = 0 AND p.log_Status = 0";
if ($cateId > 0) {
$whereSql .= " AND p.log_CateID = $cateId";
}
if (!empty($excludeIds)) {
$excludeList = implode(',', $excludeIds);
$whereSql .= " AND p.log_ID NOT IN ($excludeList)";
}
$hotLimit = (int) ($limit * 0.4);
$latestLimit = (int) ($limit * 0.4);
$randomLimit = $limit - $hotLimit - $latestLimit;
$hotItems = array();
$hotSql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
$whereSql
ORDER BY p.log_ViewNums DESC
LIMIT $hotLimit";
$hotResults = $zbp->db->Query($hotSql);
foreach ($hotResults as $row) {
$hotItems[] = format_feed_item($row, 'hot');
}
$latestItems = array();
$latestSql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
$whereSql
ORDER BY p.log_PostTime DESC
LIMIT $latestLimit";
$latestResults = $zbp->db->Query($latestSql);
foreach ($latestResults as $row) {
$latestItems[] = format_feed_item($row, 'latest');
}
$randomItems = array();
$randomSql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
$whereSql
ORDER BY RAND()
LIMIT $randomLimit";
$randomResults = $zbp->db->Query($randomSql);
foreach ($randomResults as $row) {
$randomItems[] = format_feed_item($row, 'random');
}
$allItems = array_merge($hotItems, $latestItems, $randomItems);
shuffle($allItems);
$countSql = "SELECT COUNT(*) as total FROM $tablePost p $whereSql";
$countResult = $zbp->db->Query($countSql);
$total = (int) ($countResult[0]['total'] ?? 0);
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'type' => 'recommend',
'list' => $allItems,
'page' => $page,
'limit' => $limit,
'total' => $total,
'has_more' => ($page * $limit) < $total,
'mix_ratio' => array(
'hot' => $hotLimit,
'latest' => $latestLimit,
'random' => $randomLimit
)
)
);
}
/**
* 最新信息流
*/
function get_latest_feed() {
global $zbp;
$page = (int) ($_GET['page'] ?? 1);
$limit = (int) ($_GET['limit'] ?? 20);
$cateId = (int) ($_GET['cate_id'] ?? 0);
$excludeIds = isset($_GET['exclude']) ? array_map('intval', explode(',', $_GET['exclude'])) : array();
if ($limit > 50) $limit = 50;
if ($limit < 1) $limit = 20;
$tablePost = $zbp->db->dbpre . 'post';
$tableCategory = $zbp->db->dbpre . 'category';
$tablePostStat = $zbp->db->dbpre . 'post_stat';
$tableRecipeIdMap = $zbp->db->dbpre . 'recipe_id_map';
$offset = ($page - 1) * $limit;
$whereSql = "WHERE p.log_Type = 0 AND p.log_Status = 0";
if ($cateId > 0) {
$whereSql .= " AND p.log_CateID = $cateId";
}
if (!empty($excludeIds)) {
$excludeList = implode(',', $excludeIds);
$whereSql .= " AND p.log_ID NOT IN ($excludeList)";
}
$sql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
$whereSql
ORDER BY p.log_PostTime DESC
LIMIT $offset, $limit";
$results = $zbp->db->Query($sql);
$list = array();
foreach ($results as $row) {
$list[] = format_feed_item($row, 'latest');
}
$countSql = "SELECT COUNT(*) as total FROM $tablePost p $whereSql";
$countResult = $zbp->db->Query($countSql);
$total = (int) ($countResult[0]['total'] ?? 0);
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'type' => 'latest',
'list' => $list,
'page' => $page,
'limit' => $limit,
'total' => $total,
'has_more' => ($page * $limit) < $total
)
);
}
/**
* 热门信息流
*/
function get_hot_feed() {
global $zbp;
$page = (int) ($_GET['page'] ?? 1);
$limit = (int) ($_GET['limit'] ?? 20);
$cateId = (int) ($_GET['cate_id'] ?? 0);
$period = trim($_GET['period'] ?? 'total');
if ($limit > 50) $limit = 50;
if ($limit < 1) $limit = 20;
$tablePost = $zbp->db->dbpre . 'post';
$tableCategory = $zbp->db->dbpre . 'category';
$tablePostStat = $zbp->db->dbpre . 'post_stat';
$tableStatLog = $zbp->db->dbpre . 'recipe_stat_log';
$tableRecipeIdMap = $zbp->db->dbpre . 'recipe_id_map';
$offset = ($page - 1) * $limit;
$whereSql = "WHERE p.log_Type = 0 AND p.log_Status = 0";
if ($cateId > 0) {
$whereSql .= " AND p.log_CateID = $cateId";
}
$orderBy = 'p.log_ViewNums DESC';
if ($period === 'today') {
$today = date('Y-m-d');
$sql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name, l.view_count,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tableStatLog l
INNER JOIN $tablePost p ON l.log_id = p.log_ID
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
WHERE l.stat_date = '$today' AND p.log_Type = 0 AND p.log_Status = 0
ORDER BY l.view_count DESC
LIMIT $offset, $limit";
} else {
$sql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
$whereSql
ORDER BY $orderBy
LIMIT $offset, $limit";
}
$results = $zbp->db->Query($sql);
$list = array();
foreach ($results as $row) {
$list[] = format_feed_item($row, 'hot');
}
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'type' => 'hot',
'period' => $period,
'list' => $list,
'page' => $page,
'limit' => $limit,
'has_more' => count($list) >= $limit
)
);
}
/**
* 个性化信息流 - 智能推荐算法
*/
function get_personal_feed() {
global $zbp;
$userId = trim($_GET['user_id'] ?? '');
$page = (int) ($_GET['page'] ?? 1);
$limit = (int) ($_GET['limit'] ?? 20);
$debug = isset($_GET['_debug']) && $_GET['_debug'] === '1';
if (empty($userId)) {
return array('code' => 400, 'message' => '缺少用户ID参数');
}
if ($limit > 50) $limit = 50;
if ($limit < 1) $limit = 20;
$preference = load_user_preference_data($userId);
$preferredTags = $preference['preferred_tags'] ?? array();
$preferredCategories = $preference['preferred_categories'] ?? array();
$blockedAllergens = $preference['blocked_allergens'] ?? array();
$viewHistory = load_user_view_history($userId);
$categoryViewCount = $viewHistory['categories'] ?? array();
$adminRecommend = get_admin_recommend_config();
$topCategories = $adminRecommend['top_categories'] ?? array();
$recommendCategories = $adminRecommend['recommend_categories'] ?? array();
$tablePost = $zbp->db->dbpre . 'post';
$tableCategory = $zbp->db->dbpre . 'category';
$tablePostStat = $zbp->db->dbpre . 'post_stat';
$tableIngredient = $zbp->db->dbpre . 'recipe_ingredient';
$tableRecipeIdMap = $zbp->db->dbpre . 'recipe_id_map';
$fetchLimit = $limit * 5;
$sql = "SELECT p.log_ID, p.log_Title, p.log_Intro, p.log_CateID, p.log_PostTime, p.log_Tag,
p.log_ViewNums, c.cate_Name,
COALESCE(s.like_nums, 0) as like_nums,
COALESCE(s.recommend_nums, 0) as recommend_nums
FROM $tablePost p
LEFT JOIN $tableCategory c ON p.log_CateID = c.cate_ID
LEFT JOIN $tablePostStat s ON p.log_ID = s.log_id
WHERE p.log_Type = 0 AND p.log_Status = 0
ORDER BY p.log_PostTime DESC
LIMIT $fetchLimit";
$results = $zbp->db->Query($sql);
$scoredItems = array();
foreach ($results as $row) {
$itemId = (int) $row['log_ID'];
$cateId = (int) $row['log_CateID'];
if (!empty($blockedAllergens)) {
$hasAllergen = check_item_allergen($itemId, $blockedAllergens);
if ($hasAllergen) {
continue;
}
}
$score = calculate_item_score(
$row,
$preferredTags,
$preferredCategories,
$categoryViewCount,
$topCategories,
$recommendCategories
);
$item = format_feed_item($row, 'personal');
$item['_score'] = $score;
$item['_score_detail'] = $debug ? get_score_detail(
$row,
$preferredTags,
$preferredCategories,
$categoryViewCount,
$topCategories,
$recommendCategories
) : null;
$scoredItems[] = $item;
}
usort($scoredItems, function($a, $b) {
return $b['_score'] <=> $a['_score'];
});
$offset = ($page - 1) * $limit;
$list = array_slice($scoredItems, $offset, $limit);
foreach ($list as &$item) {
unset($item['_score']);
if (!$debug) {
unset($item['_score_detail']);
}
}
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'type' => 'personal',
'user_id' => $userId,
'list' => $list,
'page' => $page,
'limit' => $limit,
'total' => count($scoredItems),
'has_more' => ($page * $limit) < count($scoredItems),
'preference' => array(
'tags' => count($preferredTags),
'categories' => count($preferredCategories),
'blocked_allergens' => count($blockedAllergens),
'view_history_categories' => count($categoryViewCount)
),
'admin_config' => array(
'top_categories' => count($topCategories),
'recommend_categories' => count($recommendCategories)
)
)
);
}
/**
* 加载用户偏好数据
*/
function load_user_preference_data($userId) {
$cacheFile = sys_get_temp_dir() . '/user_preference_' . md5($userId) . '.json';
if (file_exists($cacheFile)) {
$data = json_decode(file_get_contents($cacheFile), true);
if ($data && isset($data['expire_time']) && $data['expire_time'] > time()) {
return $data;
}
}
return array(
'user_id' => $userId,
'preferred_tags' => array(),
'preferred_categories' => array(),
'blocked_allergens' => array(),
'expire_time' => time() + 86400
);
}
/**
* 计算内容评分
*/
function calculate_item_score($row, $preferredTags, $preferredCategories, $categoryViewCount, $topCategories, $recommendCategories) {
$score = 0;
$cateId = (int) $row['log_CateID'];
$tagStr = $row['log_Tag'] ?? '';
if (in_array($cateId, $topCategories)) {
$score += 50;
} elseif (in_array($cateId, $recommendCategories)) {
$score += 30;
}
if (in_array($cateId, $preferredCategories)) {
$score += 25;
}
if (!empty($preferredTags) && !empty($tagStr)) {
$tagIds = explode(',', $tagStr);
$matchedTags = array_intersect($tagIds, $preferredTags);
$score += count($matchedTags) * 30;
}
if (isset($categoryViewCount[$cateId])) {
$viewWeight = min($categoryViewCount[$cateId] * 5, 20);
$score += $viewWeight;
}
$viewScore = min(floor(($row['log_ViewNums'] ?? 0) / 100), 20);
$score += $viewScore;
$likeScore = min(($row['like_nums'] ?? 0) * 2, 15);
$score += $likeScore;
$recommendScore = min(($row['recommend_nums'] ?? 0) * 3, 15);
$score += $recommendScore;
$postTime = strtotime($row['log_PostTime']);
if ($postTime) {
$daysAgo = (time() - $postTime) / 86400;
if ($daysAgo < 1) {
$score += 15;
} elseif ($daysAgo < 7) {
$score += 10;
} elseif ($daysAgo < 30) {
$score += 5;
}
}
return $score;
}
/**
* 获取评分详情(调试用)
*/
function get_score_detail($row, $preferredTags, $preferredCategories, $categoryViewCount, $topCategories, $recommendCategories) {
$cateId = (int) $row['log_CateID'];
$tagStr = $row['log_Tag'] ?? '';
$detail = array(
'admin_top' => in_array($cateId, $topCategories) ? 50 : 0,
'admin_recommend' => in_array($cateId, $recommendCategories) ? 30 : 0,
'preferred_category' => in_array($cateId, $preferredCategories) ? 25 : 0,
'preferred_tags' => 0,
'view_history' => isset($categoryViewCount[$cateId]) ? min($categoryViewCount[$cateId] * 5, 20) : 0,
'hot_view' => min(floor(($row['log_ViewNums'] ?? 0) / 100), 20),
'hot_like' => min(($row['like_nums'] ?? 0) * 2, 15),
'hot_recommend' => min(($row['recommend_nums'] ?? 0) * 3, 15),
'time_bonus' => 0
);
if (!empty($preferredTags) && !empty($tagStr)) {
$tagIds = explode(',', $tagStr);
$matchedTags = array_intersect($tagIds, $preferredTags);
$detail['preferred_tags'] = count($matchedTags) * 30;
}
$postTime = strtotime($row['log_PostTime']);
if ($postTime) {
$daysAgo = (time() - $postTime) / 86400;
if ($daysAgo < 1) {
$detail['time_bonus'] = 15;
} elseif ($daysAgo < 7) {
$detail['time_bonus'] = 10;
} elseif ($daysAgo < 30) {
$detail['time_bonus'] = 5;
}
}
$detail['total'] = array_sum($detail);
return $detail;
}
/**
* 检查内容是否包含过敏原
*/
function check_item_allergen($itemId, $blockedAllergens) {
global $zbp;
$tableIngredient = $zbp->db->dbpre . 'recipe_ingredient';
$allergenMap = array(
'nuts' => array('核桃', '杏仁', '腰果', '榛子', '松子', '开心果', '栗子', '花生'),
'seafood' => array('鱼', '虾', '蟹', '贝', '海参', '鲍鱼', '扇贝'),
'dairy' => array('牛奶', '奶粉', '奶酪', '奶油', '酸奶', '黄油'),
'eggs' => array('鸡蛋', '鸭蛋', '鹅蛋', '鸽蛋', '鹌鹑蛋'),
'grains' => array('小麦', '面粉', '面包', '面条'),
'beans' => array('黄豆', '绿豆', '红豆', '蚕豆', '豌豆'),
'meat' => array('猪肉', '牛肉', '羊肉', '鸡肉', '鸭肉', '鹅肉'),
'fruits' => array('桃', '芒果', '菠萝', '草莓', '猕猴桃'),
'vegetables' => array('芹菜', '茄子', '韭菜', '香菜', '姜', '蒜'),
'mushrooms' => array('香菇', '金针菇', '木耳', '银耳'),
'seasonings' => array('胡椒', '花椒', '芥末', '味精', '料酒'),
'other' => array('蜂蜜', '巧克力', '可可', '芝麻')
);
$checkIngredients = array();
foreach ($blockedAllergens as $allergenType) {
if (isset($allergenMap[$allergenType])) {
$checkIngredients = array_merge($checkIngredients, $allergenMap[$allergenType]);
}
}
if (empty($checkIngredients)) {
return false;
}
$ingredientList = array_map(function($item) use ($zbp) {
return "'" . $zbp->db->EscapeString($item) . "'";
}, $checkIngredients);
$ingredientStr = implode(',', $ingredientList);
$sql = "SELECT COUNT(*) as cnt FROM $tableIngredient
WHERE log_id = $itemId AND ingredient_name IN ($ingredientStr)";
$result = $zbp->db->Query($sql);
return (int) ($result[0]['cnt'] ?? 0) > 0;
}
/**
* 加载用户浏览历史
*/
function load_user_view_history($userId) {
$cacheFile = sys_get_temp_dir() . '/user_view_history_' . md5($userId) . '.json';
if (file_exists($cacheFile)) {
$data = json_decode(file_get_contents($cacheFile), true);
if ($data && isset($data['expire_time']) && $data['expire_time'] > time()) {
return $data;
}
}
return array(
'categories' => array(),
'tags' => array(),
'recent_views' => array(),
'expire_time' => time() + 86400
);
}
/**
* 获取管理员推荐配置
*/
function get_admin_recommend_config() {
$configFile = dirname(__FILE__) . '/config/admin_recommend.json';
if (file_exists($configFile)) {
$data = json_decode(file_get_contents($configFile), true);
if ($data) {
return array(
'top_categories' => $data['top_categories'] ?? array(),
'recommend_categories' => $data['recommend_categories'] ?? array(),
'top_tags' => $data['top_tags'] ?? array(),
'expire_time' => time() + 3600
);
}
}
$cacheFile = sys_get_temp_dir() . '/admin_recommend_config.json';
if (file_exists($cacheFile)) {
$data = json_decode(file_get_contents($cacheFile), true);
if ($data && isset($data['expire_time']) && $data['expire_time'] > time()) {
return $data;
}
}
return array(
'top_categories' => array(),
'recommend_categories' => array(),
'top_tags' => array(),
'expire_time' => time() + 3600
);
}
/**
* 预加载多页数据
*/
function get_prefetch_feed() {
global $zbp;
$pages = (int) ($_GET['pages'] ?? 3);
$limit = (int) ($_GET['limit'] ?? 20);
if ($pages > 5) $pages = 5;
if ($pages < 1) $pages = 3;
if ($limit > 30) $limit = 30;
$allData = array();
for ($i = 1; $i <= $pages; $i++) {
$_GET['page'] = $i;
$_GET['limit'] = $limit;
$feedResult = get_recommend_feed();
if ($feedResult['code'] === 200) {
$allData['page_' . $i] = $feedResult['data'];
}
}
return array(
'code' => 200,
'message' => 'success',
'data' => array(
'type' => 'prefetch',
'pages' => $pages,
'items_per_page' => $limit,
'total_items' => $pages * $limit,
'pages_data' => $allData
)
);
}
/**
* 格式化信息流项目
*/
function format_feed_item($row, $source = 'unknown') {
global $zbp;
static $picIdCache = array();
$recipeId = (int) $row['log_ID'];
if (!isset($picIdCache[$recipeId])) {
$tableRecipeIdMap = $zbp->db->dbpre . 'recipe_id_map';
$idMapSql = "SELECT old_id FROM $tableRecipeIdMap WHERE new_log_id = $recipeId LIMIT 1";
$idMapResult = $zbp->db->Query($idMapSql);
$picIdCache[$recipeId] = !empty($idMapResult) ? (int) $idMapResult[0]['old_id'] : null;
}
$publishTime = strtotime($row['log_PostTime']);
return array(
'id' => $recipeId,
'pic_id' => $picIdCache[$recipeId],
'title' => $row['log_Title'],
'intro' => mb_substr(strip_tags($row['log_Intro'] ?? ''), 0, 100),
'category' => array(
'id' => (int) ($row['log_CateID'] ?? 0),
'name' => $row['cate_Name'] ?? ''
),
'statistics' => array(
'view_count' => (int) ($row['log_ViewNums'] ?? 0),
'like_count' => (int) ($row['like_nums'] ?? 0),
'recommend_count' => (int) ($row['recommend_nums'] ?? 0)
),
'publish_time' => $publishTime !== false ? $publishTime : null,
'source' => $source,
'url' => '?id=' . $row['log_ID']
);
}