query($sql);
}
/**
* 获取不同地区的订单数量
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return mysqli_result 地区订单数据结果集
*/
function getOrdersByRegion($conn, $start_date, $end_date) {
$sql = "SELECT
c.countryName,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_amount,
SUM(oi.quantity) as total_quantity
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE o.order_date BETWEEN ? AND ?
GROUP BY cu.cs_country
ORDER BY total_quantity DESC
LIMIT 10";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $start_date, $end_date);
$stmt->execute();
return $stmt->get_result();
}
/**
* 获取地区销售同比环比数据
*
* @param mysqli $conn 数据库连接
* @param string $current_start 当前周期开始日期
* @param string $current_end 当前周期结束日期
* @return array 地区销售同比环比数据
*/
function getRegionSalesComparison($conn, $current_start, $current_end) {
// 计算上一个相同时长的周期
$current_start_date = new DateTime($current_start);
$current_end_date = new DateTime($current_end);
$interval = $current_start_date->diff($current_end_date);
$prev_end_date = clone $current_start_date;
$prev_end_date->modify('-1 day');
$prev_start_date = clone $prev_end_date;
$prev_start_date->sub($interval);
$prev_start = $prev_start_date->format('Y-m-d');
$prev_end = $prev_end_date->format('Y-m-d') . ' 23:59:59';
// 获取当前周期数据
$sql = "SELECT
c.countryName,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_amount
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
WHERE o.order_date BETWEEN ? AND ?
GROUP BY cu.cs_country
ORDER BY total_amount DESC
LIMIT 5";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $current_start, $current_end);
$stmt->execute();
$current_result = $stmt->get_result();
$current_data = [];
while ($row = $current_result->fetch_assoc()) {
$current_data[$row['countryName']] = [
'order_count' => $row['order_count'],
'total_amount' => $row['total_amount']
];
}
// 获取上一个周期数据
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $prev_start, $prev_end);
$stmt->execute();
$prev_result = $stmt->get_result();
$prev_data = [];
while ($row = $prev_result->fetch_assoc()) {
$prev_data[$row['countryName']] = [
'order_count' => $row['order_count'],
'total_amount' => $row['total_amount']
];
}
// 计算同比变化
$comparison_data = [];
foreach ($current_data as $country => $current) {
$prev = $prev_data[$country] ?? ['order_count' => 0, 'total_amount' => 0];
$order_growth = $prev['order_count'] > 0
? (($current['order_count'] - $prev['order_count']) / $prev['order_count']) * 100
: 100;
$amount_growth = $prev['total_amount'] > 0
? (($current['total_amount'] - $prev['total_amount']) / $prev['total_amount']) * 100
: 100;
$comparison_data[] = [
'countryName' => $country,
'current_orders' => $current['order_count'],
'prev_orders' => $prev['order_count'],
'order_growth' => $order_growth,
'current_amount' => $current['total_amount'],
'prev_amount' => $prev['total_amount'],
'amount_growth' => $amount_growth
];
}
return $comparison_data;
}
/**
* 渲染客户国家分布图
*
* @param array $country_labels 国家标签
* @param array $country_data 国家数据
* @return void
*/
function renderCustomerCountryDistributionChart($country_labels, $country_data) {
?>
国家/地区 |
当前订单数 |
上期订单数 |
订单增长率 |
当前销售额 |
上期销售额 |
销售额增长率 |
|
|
|
%
|
¥ |
¥ |
%
|
prepare($sql);
$stmt->bind_param("ss", $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$current_amount = $row['total_amount'] ?? 0;
// 计算上一个相同时长的周期
$current_start_date = new DateTime($start_date);
$current_end_date = new DateTime($end_date);
$interval = $current_start_date->diff($current_end_date);
$prev_end_date = clone $current_start_date;
$prev_end_date->modify('-1 day');
$prev_start_date = clone $prev_end_date;
$prev_start_date->sub($interval);
$prev_start = $prev_start_date->format('Y-m-d');
$prev_end = $prev_end_date->format('Y-m-d') . ' 23:59:59';
// 获取上一周期销售额
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $prev_start, $prev_end);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$prev_amount = $row['total_amount'] ?? 0;
// 计算增长率
$growth = 0;
if ($prev_amount > 0) {
$growth = (($current_amount - $prev_amount) / $prev_amount) * 100;
}
return [
'total_amount' => $current_amount,
'growth' => $growth
];
}
/**
* 获取活跃国家数
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return array 活跃国家信息
*/
function getActiveCountries($conn, $start_date, $end_date) {
$sql = "SELECT COUNT(DISTINCT cu.cs_country) as country_count
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
WHERE o.order_date BETWEEN ? AND ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
return [
'count' => $row['country_count'] ?? 0
];
}
/**
* 获取各地区平均订单金额
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return array 各地区平均订单金额数据
*/
function getAverageOrderByRegion($conn, $start_date, $end_date) {
$sql = "SELECT
c.countryName,
AVG(o.total_amount) as avg_amount,
COUNT(o.id) as order_count
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
WHERE o.order_date BETWEEN ? AND ?
GROUP BY cu.cs_country
HAVING order_count >= 5
ORDER BY avg_amount DESC
LIMIT 10";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$regions = [];
$total_avg = 0;
$total_orders = 0;
while ($row = $result->fetch_assoc()) {
$regions[] = [
'countryName' => $row['countryName'],
'avg_amount' => $row['avg_amount'],
'order_count' => $row['order_count']
];
$total_avg += $row['avg_amount'] * $row['order_count'];
$total_orders += $row['order_count'];
}
// 计算全球平均订单金额
$global_avg = $total_orders > 0 ? $total_avg / $total_orders : 0;
return [
'regions' => $regions,
'global_avg' => $global_avg
];
}
/**
* 获取各地区产品类别偏好
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return array 各地区产品类别偏好数据
*/
function getRegionCategoryPreferences($conn, $start_date, $end_date) {
$sql = "SELECT
c.countryName,
pc.name as category_name,
SUM(oi.quantity) as total_quantity
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
JOIN product_categories pc ON p.category_id = pc.id
WHERE o.order_date BETWEEN ? AND ?
GROUP BY cu.cs_country, p.category_id
ORDER BY c.countryName, total_quantity DESC";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$preferences = [];
$current_country = '';
$country_data = [];
while ($row = $result->fetch_assoc()) {
if ($current_country != $row['countryName']) {
if (!empty($current_country)) {
$preferences[$current_country] = $country_data;
}
$current_country = $row['countryName'];
$country_data = [];
}
$country_data[] = [
'category' => $row['category_name'],
'quantity' => $row['total_quantity']
];
}
// 添加最后一个国家的数据
if (!empty($current_country)) {
$preferences[$current_country] = $country_data;
}
// 只保留前5个主要市场
$top_markets = array_slice(array_keys($preferences), 0, 5);
$filtered_preferences = [];
foreach ($top_markets as $market) {
$filtered_preferences[$market] = array_slice($preferences[$market], 0, 5);
}
return $filtered_preferences;
}
/**
* 获取地区销售增长趋势
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @param string $period 时间粒度 (day/week/month)
* @return array 地区销售增长趋势数据
*/
function getRegionGrowthTrends($conn, $start_date, $end_date, $period = 'month') {
$period_format = getPeriodFormat($period);
$sql = "SELECT
c.countryName,
DATE_FORMAT(o.order_date, ?) as time_period,
SUM(o.total_amount) as total_amount
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
WHERE o.order_date BETWEEN ? AND ?
GROUP BY cu.cs_country, time_period
ORDER BY c.countryName, time_period";
$stmt = $conn->prepare($sql);
$stmt->bind_param("sss", $period_format, $start_date, $end_date);
$stmt->execute();
$result = $stmt->get_result();
$trends = [];
$time_periods = [];
while ($row = $result->fetch_assoc()) {
if (!in_array($row['time_period'], $time_periods)) {
$time_periods[] = $row['time_period'];
}
if (!isset($trends[$row['countryName']])) {
$trends[$row['countryName']] = [];
}
$trends[$row['countryName']][$row['time_period']] = $row['total_amount'];
}
// 只保留前5个主要市场
$top_markets = array_slice(array_keys($trends), 0, 5);
$filtered_trends = [];
foreach ($top_markets as $market) {
$filtered_trends[$market] = $trends[$market];
}
return [
'time_periods' => $time_periods,
'trends' => $filtered_trends
];
}
/**
* 获取地区季节性销售分析
*
* @param mysqli $conn 数据库连接
* @return array 地区季节性销售分析数据
*/
function getRegionSeasonalAnalysis($conn) {
$sql = "SELECT
c.countryName,
MONTH(o.order_date) as month,
SUM(o.total_amount) as total_amount
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
WHERE o.order_date >= DATE_SUB(CURDATE(), INTERVAL 2 YEAR)
GROUP BY cu.cs_country, month
ORDER BY c.countryName, month";
$result = $conn->query($sql);
$seasonal = [];
$months = range(1, 12);
while ($row = $result->fetch_assoc()) {
if (!isset($seasonal[$row['countryName']])) {
$seasonal[$row['countryName']] = array_fill(1, 12, 0);
}
$seasonal[$row['countryName']][$row['month']] += $row['total_amount'];
}
// 只保留前5个主要市场
$top_markets = array_slice(array_keys($seasonal), 0, 5);
$filtered_seasonal = [];
foreach ($top_markets as $market) {
$filtered_seasonal[$market] = array_values($seasonal[$market]);
}
return [
'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
'data' => $filtered_seasonal
];
}
/**
* 获取地区销售预测数据
*
* @param mysqli $conn 数据库连接
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return array 地区销售预测数据
*/
function getRegionSalesForecast($conn, $start_date, $end_date) {
// 获取过去12个月的销售数据作为基础
$sql = "SELECT
c.countryName,
MONTH(o.order_date) as month,
YEAR(o.order_date) as year,
SUM(o.total_amount) as total_amount
FROM orders o
JOIN customer cu ON o.customer_id = cu.id
JOIN country c ON cu.cs_country = c.id
WHERE o.order_date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
GROUP BY cu.cs_country, year, month
ORDER BY c.countryName, year, month";
$result = $conn->query($sql);
$historical = [];
while ($row = $result->fetch_assoc()) {
$period = $row['year'] . '-' . str_pad($row['month'], 2, '0', STR_PAD_LEFT);
if (!isset($historical[$row['countryName']])) {
$historical[$row['countryName']] = [];
}
$historical[$row['countryName']][$period] = $row['total_amount'];
}
// 生成未来6个月的预测
$forecast = [];
$periods = [];
$current_month = (int)date('m');
$current_year = (int)date('Y');
// 收集所有历史数据点时间
$all_periods = [];
foreach ($historical as $country => $data) {
foreach (array_keys($data) as $period) {
$all_periods[$period] = true;
}
}
$all_periods = array_keys($all_periods);
sort($all_periods);
// 生成未来6个月的预测点
$future_periods = [];
for ($i = 1; $i <= 6; $i++) {
$forecast_month = ($current_month + $i) % 12;
$forecast_month = $forecast_month == 0 ? 12 : $forecast_month;
$forecast_year = $current_year + floor(($current_month + $i - 1) / 12);
$period = $forecast_year . '-' . str_pad($forecast_month, 2, '0', STR_PAD_LEFT);
$future_periods[] = $period;
}
// 合并历史和预测时间点
$all_chart_periods = array_merge($all_periods, $future_periods);
// 只选取主要的5个市场做预测
$top_markets = array_slice(array_keys($historical), 0, 5);
$forecast_data = [];
foreach ($top_markets as $market) {
$forecast_data[$market] = [];
// 为每个市场生成简单的预测
// 这里使用简单的线性增长预测
// 实际应用中可以采用更复杂的时间序列预测算法
// 计算过去几个月的平均增长率
$growth_rate = 0.05; // 默认月度增长率为5%
if (count($historical[$market]) >= 2) {
$values = array_values($historical[$market]);
$start_val = array_shift($values);
$end_val = array_pop($values);
if ($start_val > 0) {
$periods_count = count($historical[$market]) - 1;
$total_growth = ($end_val / $start_val) - 1;
$growth_rate = pow(1 + $total_growth, 1 / $periods_count) - 1;
// 限制增长率在合理范围内
$growth_rate = max(-0.2, min(0.2, $growth_rate));
}
}
// 对于历史数据,直接使用实际值
foreach ($all_periods as $period) {
$forecast_data[$market][$period] = [
'value' => $historical[$market][$period] ?? null,
'is_forecast' => false
];
}
// 对于预测数据,基于最后一个历史数据点和增长率计算
$last_period = end($all_periods);
$last_value = $historical[$market][$last_period] ?? array_values($historical[$market])[count($historical[$market])-1];
foreach ($future_periods as $i => $period) {
$forecast_value = $last_value * pow(1 + $growth_rate, $i + 1);
$forecast_data[$market][$period] = [
'value' => $forecast_value,
'is_forecast' => true
];
}
}
return [
'periods' => $all_chart_periods,
'forecast' => $forecast_data
];
}
/**
* 渲染平均订单金额分析图表
*
* @param array $region_data 地区平均订单金额数据
* @return void
*/
function renderAverageOrderByRegionChart($region_data) {
$region_labels = [];
$avg_amounts = [];
$order_counts = [];
foreach ($region_data as $region) {
$region_labels[] = $region['countryName'];
$avg_amounts[] = $region['avg_amount'];
$order_counts[] = $region['order_count'];
}
?>
$data) {
$dataset = [
'label' => $country,
'data' => [],
'backgroundColor' => $colors[$i % count($colors)][0],
'borderColor' => $colors[$i % count($colors)][1],
'borderWidth' => 2,
'fill' => false,
'tension' => 0.1
];
foreach ($time_periods as $period) {
$dataset['data'][] = $data[$period] ?? null;
}
$datasets[] = $dataset;
$i++;
}
?>
$values) {
$datasets[] = [
'label' => $country,
'data' => $values,
'backgroundColor' => $colors[$i % count($colors)][0],
'borderColor' => $colors[$i % count($colors)][1],
'borderWidth' => 2,
'fill' => false,
'tension' => 0.1
];
$i++;
}
?>
$data) {
$historical_data = [];
$forecast_data = [];
foreach ($periods as $period) {
if (isset($data[$period])) {
if ($data[$period]['is_forecast']) {
$historical_data[] = null;
$forecast_data[] = $data[$period]['value'];
} else {
$historical_data[] = $data[$period]['value'];
$forecast_data[] = null;
}
} else {
$historical_data[] = null;
$forecast_data[] = null;
}
}
$datasets[] = [
'label' => $country . ' (历史)',
'data' => $historical_data,
'backgroundColor' => $colors[$i % count($colors)][0],
'borderColor' => $colors[$i % count($colors)][1],
'borderWidth' => 2,
'fill' => false
];
$datasets[] = [
'label' => $country . ' (预测)',
'data' => $forecast_data,
'backgroundColor' => $colors[$i % count($colors)][0],
'borderColor' => $colors[$i % count($colors)][1],
'borderWidth' => 2,
'borderDash' => [5, 5],
'fill' => false
];
$i++;
}
?>
排名 |
国家/地区 |
订单数 |
产品数量 |
销售金额 |
平均订单金额 |
|
|
|
|
¥ |
¥ 0 ? $region_amounts[$i] / $region_order_counts[$i] : 0, 2); ?> |