|
|
@@ -10,6 +10,7 @@
|
|
|
let chart = null;
|
|
|
let schools = [];
|
|
|
let cityPoints = [];
|
|
|
+ let geoProvinceNames = [];
|
|
|
let cityLabelsVisible = false;
|
|
|
let inited = false;
|
|
|
let loading = false;
|
|
|
@@ -51,6 +52,30 @@
|
|
|
return '#d8d1c9';
|
|
|
}
|
|
|
|
|
|
+ /** 每省已点亮(启用且已定位)的学校数 */
|
|
|
+ function provinceCounts() {
|
|
|
+ const byShort = new Map();
|
|
|
+ for (const full of geoProvinceNames) byShort.set(shortProvince(full), full);
|
|
|
+ const counts = new Map();
|
|
|
+ for (const school of schools) {
|
|
|
+ if (!(school.enabled && school.lng != null)) continue;
|
|
|
+ const full = byShort.get(shortProvince(school.province)) || school.province;
|
|
|
+ if (!full) continue;
|
|
|
+ counts.set(full, (counts.get(full) || 0) + 1);
|
|
|
+ }
|
|
|
+ return counts;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 省份按点亮学校数分档着色(比学校点更浅,避免压过点位) */
|
|
|
+ function provinceColor(count) {
|
|
|
+ const n = Number(count) || 0;
|
|
|
+ if (n >= 10) return '#ef8455';
|
|
|
+ if (n >= 4) return '#f4a684';
|
|
|
+ if (n >= 2) return '#f8c9b2';
|
|
|
+ if (n >= 1) return '#f9dccc';
|
|
|
+ return '#f7f5f2';
|
|
|
+ }
|
|
|
+
|
|
|
function buildCityPoints(data) {
|
|
|
const points = [];
|
|
|
for (const info of Object.values(data || {})) {
|
|
|
@@ -83,8 +108,11 @@
|
|
|
padding: [8, 10],
|
|
|
textStyle: { color: '#3f3a35', fontSize: 12 },
|
|
|
formatter(params) {
|
|
|
- const school = schools.find((s) => s.id === params.data.schoolId);
|
|
|
- if (!school) return params.name;
|
|
|
+ const school = params.data && schools.find((s) => s.id === params.data.schoolId);
|
|
|
+ if (!school) {
|
|
|
+ const count = provinceCounts().get(params.name) || 0;
|
|
|
+ return `<b>${esc(params.name)}</b><br>点亮学校:${count} 所`;
|
|
|
+ }
|
|
|
const status = school.enabled ? '已启用' : '已停用';
|
|
|
const point = school.lng == null ? '未定位' : `${school.lng.toFixed(4)}, ${school.lat.toFixed(4)}`;
|
|
|
return `<b>${esc(school.name)}</b><br>${esc(school.province || '—')}${school.city ? ' · ' + esc(school.city) : ''}<br>${status} · ${opsText(school)}<br><span style="color:#9a938c">${point}</span>`;
|
|
|
@@ -97,6 +125,10 @@
|
|
|
zoom: ZOOM,
|
|
|
scaleLimit: { min: 1, max: 12 },
|
|
|
itemStyle: { areaColor: '#f7f5f2', borderColor: '#ddd6cd', borderWidth: 0.8 },
|
|
|
+ regions: [...provinceCounts().entries()].map(([name, count]) => ({
|
|
|
+ name,
|
|
|
+ itemStyle: { areaColor: provinceColor(count) },
|
|
|
+ })),
|
|
|
label: { show: true, color: '#8f8478', fontSize: 10, formatter: (p) => shortProvince(p.name) },
|
|
|
emphasis: { itemStyle: { areaColor: '#efeae4' }, label: { show: true, color: '#5b534c', fontSize: 10 } },
|
|
|
select: { disabled: true },
|
|
|
@@ -163,7 +195,15 @@
|
|
|
box.innerHTML = '';
|
|
|
return;
|
|
|
}
|
|
|
- box.innerHTML = '<span class="schools-legend-title">门店数</span>'
|
|
|
+ const litProvinces = provinceCounts();
|
|
|
+ const maxLit = Math.max(0, ...litProvinces.values());
|
|
|
+ box.innerHTML = '<span class="schools-legend-title">每省点亮学校</span>'
|
|
|
+ + '<span><i style="background:#f9dccc"></i>1</span>'
|
|
|
+ + '<span><i style="background:#f8c9b2"></i>2-3</span>'
|
|
|
+ + '<span><i style="background:#f4a684"></i>4-9</span>'
|
|
|
+ + '<span><i style="background:#ef8455"></i>10+</span>'
|
|
|
+ + '<span class="schools-legend-sep"></span>'
|
|
|
+ + '<span class="schools-legend-title">门店数</span>'
|
|
|
+ '<span><i style="background:#d8d1c9"></i>0</span>'
|
|
|
+ '<span><i style="background:#ffb894"></i>1-3</span>'
|
|
|
+ '<span><i style="background:#ff8a5c"></i>4-9</span>'
|
|
|
@@ -266,6 +306,7 @@
|
|
|
const geo = await geoRes.json();
|
|
|
const data = await listRes.json();
|
|
|
echarts.registerMap('china', geo);
|
|
|
+ geoProvinceNames = (geo.features || []).map((f) => (f.properties && f.properties.name) || '').filter(Boolean);
|
|
|
if (cityRes && cityRes.ok) {
|
|
|
try { cityPoints = buildCityPoints(await cityRes.json()); } catch { cityPoints = []; }
|
|
|
}
|