/**
* dashboard.js - 首页逻辑
* 8个指标卡 + 区域分布(国内=中国地图按省份 / 全球=世界地图按国家,各含企业/人员Tab)
* + 行业分布(企业/人员)+ 需求关键词词云(占位)
*/
$(function () {
renderShell('综合概览', '首页 / 数据看板');
initPage('dashboard', function (user) {
loadStats();
});
// 图表状态(Tab 选中态与数据维度)
var pageData = null;
var regionState = { china: { dim: 'company' }, world: { dim: 'company' } };
var industryState = { dim: 'company' };
/** 数值安全转换:NaN / 空值一律转 0 */
function toNum(v) {
var n = parseInt(v, 10);
return isNaN(n) ? 0 : n;
}
function loadStats() {
httpGet('dashboard/stats.php').then(function (data) {
renderMetricCards(data.metrics || {});
pageData = data;
renderRegionChart('china');
renderRegionChart('world');
renderIndustryChart();
renderWordCloud(data.wordcloud || []);
});
}
/* ============ 8 个指标卡 + 图表容器 ============ */
function renderMetricCards(m) {
var cards = [
{ label: '累计企业', num: toNum(m.company_total), cls: 'c-blue' },
{ label: '累计人员', num: toNum(m.person_total), cls: 'c-green' },
{ label: '昨日新增数据(企业/人员)', num: toNum(m.company_new) + '/' + toNum(m.person_new), cls: 'c-orange' },
{ label: '待处理数据碎片', num: toNum(m.preliminary), cls: 'c-red' },
{ label: '覆盖行业', num: toNum(m.industry_count), cls: 'c-purple' },
{ label: '生产型企业', num: toNum(m.manufacturer), cls: 'c-blue' },
{ label: '集成商/代理商', num: toNum(m.integrator), cls: 'c-cyan' },
{ label: '行业媒体资源', num: toNum(m.media_resource), cls: 'c-teal' }
];
var html = '';
cards.forEach(function (c) {
html += '
' +
'
' + (c.num === undefined ? '-' : c.num) + '
' +
'
' + c.label + '
';
});
$('#page-content').html(
'' + html + '
' +
'' +
'
区域分布(国内)' +
'
' +
' 企业' +
' 人员' +
' ' +
'
区域分布(全球)' +
'
' +
' 企业' +
' 人员' +
' ' +
'
行业分布' +
'
' +
' 企业' +
' 人员' +
' ' +
'
' +
'
'
);
}
/* ============ Tab 切换(内联 onclick,数据属性精确匹配选中态) ============ */
window.switchRegionDim = function (box, dim) {
regionState[box].dim = dim;
syncTabs();
renderRegionChart(box);
};
window.switchIndustryDim = function (dim) {
industryState.dim = dim;
syncTabs();
renderIndustryChart();
};
/** 同步所有 Tab 的选中色块 */
function syncTabs() {
$('.chart-title .tabs').each(function () {
var $tabs = $(this);
var group = $tabs.data('group');
$tabs.find('.tab').each(function () {
var $t = $(this);
var val = $t.data('val');
var active = false;
if (group === 'region-china') active = (regionState.china.dim === val);
else if (group === 'region-world') active = (regionState.world.dim === val);
else if (group === 'industry') active = (industryState.dim === val);
$t.toggleClass('active', active);
});
});
}
/* ============ 区域分布(china=中国地图按省份 / world=世界地图按国家) ============ */
function renderRegionChart(box) {
var el = document.getElementById('chart-region-' + box);
if (!el || !window.echarts) return;
try {
var dim = regionState[box].dim;
var rows = ((pageData.region || {})[dim] || {})[box] || [];
rows = rows.map(function (r) {
return { name: r.name, value: toNum(r.value) };
});
var chart = echarts.getInstanceByDom(el) || echarts.init(el);
var mapName = box === 'china' ? 'china' : 'world';
var hasMap = !!(echarts.getMap && echarts.getMap(mapName));
// 世界地图:ECharts5 不支持 series.nameMap,需把中文国家名转英文(地图用英文名匹配);中文名保留给 tooltip
if (box === 'world') {
rows = rows.map(function (r) {
var en = CN_TO_EN[r.name] || r.name;
return { name: en, value: r.value, displayName: r.name };
});
}
if (!hasMap || !rows.length) {
// 地图未加载或无数据时降级为柱状图
if (!rows.length) {
chart.setOption({
title: { text: '暂无' + (dim === 'company' ? '企业' : '人员') + '数据', left: 'center', top: 'middle', textStyle: { color: '#b6bfcc', fontSize: 14 } }
});
} else {
chart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: 60, right: 20, top: 30, bottom: 80 },
xAxis: { type: 'category', data: rows.map(function (r) { return r.name; }), axisLabel: { rotate: 45 } },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: rows.map(function (r) { return r.value; }), itemStyle: { color: '#16a085' }, barMaxWidth: 40 }]
});
}
return;
}
var values = rows.map(function (r) { return r.value; });
var maxVal = Math.max.apply(null, values);
var option = {
tooltip: {
trigger: 'item',
formatter: function (p) {
// 无数据区域 p.value 为 NaN/undefined,统一显示 0
var v = p.value;
if (v === undefined || v === null || isNaN(v)) v = 0;
return ((p.data && p.data.displayName) || p.name) + ':' + v;
}
},
// 颜色深浅按数据量(数值越大颜色越深),不显示左下角图例
visualMap: {
show: false,
min: 0,
max: maxVal,
inRange: { color: ['#e8f1ff', '#1e3c72'] }
},
series: [{
type: 'map',
map: mapName,
roam: true,
label: { show: false },
emphasis: {
label: { show: true, formatter: function (p) { return ((p.data && p.data.displayName) || p.name); } },
itemStyle: { areaColor: '#f39c12' }
},
data: rows
}]
};
chart.setOption(option);
window.addEventListener('resize', function () { chart.resize(); });
} catch (e) {
console && console.error('region chart error', e);
}
}
/* ============ 行业分布(柱状图,企业/人员) ============ */
function renderIndustryChart() {
var el = document.getElementById('chart-industry');
if (!el || !window.echarts) return;
try {
var dim = industryState.dim;
var rows = ((pageData.industry || {})[dim] || []).map(function (r) {
return { name: r.name, value: toNum(r.value) };
});
var chart = echarts.getInstanceByDom(el) || echarts.init(el);
if (!rows.length) {
chart.setOption({
title: { text: '暂无' + (dim === 'company' ? '企业' : '人员') + '行业数据', left: 'center', top: 'middle', textStyle: { color: '#b6bfcc', fontSize: 14 } }
});
return;
}
chart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: 70, right: 20, top: 30, bottom: 50 },
xAxis: { type: 'category', data: rows.map(function (r) { return r.name; }), axisLabel: { rotate: 30 } },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: rows.map(function (r) { return r.value; }),
itemStyle: { color: '#2a5298', borderRadius: [3, 3, 0, 0] },
barMaxWidth: 40
}]
});
window.addEventListener('resize', function () { chart.resize(); });
} catch (e) {
console && console.error('industry chart error', e);
}
}
/* ============ 需求关键词词云(占位) ============ */
function renderWordCloud(words) {
var el = document.getElementById('chart-wordcloud');
if (!el || !window.echarts) return;
try {
var chart = echarts.getInstanceByDom(el) || echarts.init(el);
if (!words.length) {
chart.setOption({
title: { text: '暂无关键词数据(占位,后续接入分词服务)', left: 'center', top: 'middle', textStyle: { color: '#b6bfcc', fontSize: 14 } }
});
return;
}
var data = words.map(function (w) {
return {
name: w.name,
value: w.value,
symbolSize: Math.min(60, 14 + w.value * 2),
itemStyle: { color: 'hsl(' + (w.name.length * 37 % 360) + ',65%,55%)' }
};
});
chart.setOption({
tooltip: { formatter: function (p) { return p.name + ':' + toNum(p.value) + '次'; } },
series: [{
type: 'scatter',
data: data,
label: { show: true, formatter: function (p) { return p.name; }, fontSize: 12, color: '#333' },
symbol: 'circle'
}]
});
window.addEventListener('resize', function () { chart.resize(); });
} catch (e) {
console && console.error('wordcloud error', e);
}
}
});