Compare commits
31 Commits
df5b4c531f
...
main
Author | SHA1 | Date | |
---|---|---|---|
cbabf9c956 | |||
ec35818b13 | |||
9349d582b6 | |||
b821e316ca | |||
13730b1e92 | |||
caca8500b6 | |||
3e3343fa81 | |||
649195dfeb | |||
8ad6275847 | |||
6a1a67ac07 | |||
a941049482 | |||
fb715c2a83 | |||
f3b79dc883 | |||
0f199e5d29 | |||
e85799be93 | |||
59ed6b110e | |||
ef4c4afafc | |||
933bb91be7 | |||
06d1f924f2 | |||
3998fc722f | |||
c088fee4c1 | |||
21dee17af4 | |||
882c261b17 | |||
1a99814db1 | |||
348b076093 | |||
a783438696 | |||
321d9b41b4 | |||
bb17c3214c | |||
0d2a8cde19 | |||
c535201e77 | |||
6112cc1813 |
67
Controller/EducationDataController.py
Normal file
67
Controller/EducationDataController.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from fastapi import APIRouter, Query
|
||||
from Model.EducationDataModel import EducationDataModel
|
||||
|
||||
|
||||
# 创建APIRouter实例
|
||||
router = APIRouter(prefix="/EducationData", tags=["教育统计数据"])
|
||||
|
||||
|
||||
@router.get("/byYear")
|
||||
async def get_education_data_by_year(
|
||||
year: int = Query(default=2023, ge=2015, le=2028,
|
||||
description="年份: 2015-2028范围内的年份")
|
||||
):
|
||||
"""获取指定年份所有学段的教育数据"""
|
||||
try:
|
||||
# 调用EducationDataModel的方法获取数据
|
||||
data = EducationDataModel.get_education_data_by_year(year)
|
||||
|
||||
# 返回包含状态和数据的响应
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": data
|
||||
}
|
||||
except Exception as e:
|
||||
# 异常处理
|
||||
return {
|
||||
"code": 500,
|
||||
"message": f"获取数据失败: {str(e)}",
|
||||
"data": []
|
||||
}
|
||||
|
||||
|
||||
@router.get("/populationByYear")
|
||||
async def get_population_data_by_year(
|
||||
year: int = Query(default=2023, ge=2015, le=2028,
|
||||
description="年份: 2015-2028范围内的年份")
|
||||
):
|
||||
"""获取指定年份的云南省人口数据"""
|
||||
try:
|
||||
# 调用EducationDataModel的方法获取人口数据
|
||||
data = EducationDataModel.get_population_data_by_year(year)
|
||||
|
||||
if data:
|
||||
# 返回包含状态和数据的响应
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": data
|
||||
}
|
||||
else:
|
||||
# 未找到数据的情况
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"未找到{year}年的云南省人口数据",
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
# 异常处理
|
||||
return {
|
||||
"code": 500,
|
||||
"message": f"获取数据失败: {str(e)}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,21 +1,24 @@
|
||||
from fastapi import APIRouter
|
||||
from fastapi import APIRouter, Query
|
||||
|
||||
from Model.RuYuanZaiYuanCountModel import RuYuanZaiYuanModel
|
||||
|
||||
# 创建APIRouter实例
|
||||
router = APIRouter(prefix="/RuYuanZaiYuan", tags=["大屏展示"])
|
||||
|
||||
# 默认的根路由
|
||||
@router.get("/")
|
||||
async def root():
|
||||
return {"message": "Welcome to YunNan Education World!"}
|
||||
|
||||
@router.get("/school/preschool/chart")
|
||||
async def get_preschool_education_chart_config():
|
||||
return RuYuanZaiYuanModel.generate_preschool_education_config()
|
||||
|
||||
@router.get("/school/preschool/inschool/chart")
|
||||
async def get_preschool_in_school_chart_config():
|
||||
return RuYuanZaiYuanModel.generate_in_school_education_config()
|
||||
router = APIRouter(prefix="/RuYuanZaiYuan", tags=["入校、在校人数统计"])
|
||||
|
||||
|
||||
@router.get("/school/chart")
|
||||
async def get_education_chart_config(
|
||||
education_stage: str = Query(default="preschool", pattern="^(preschool|primary|junior|senior)$",
|
||||
description="教育阶段: preschool(学前), primary(小学), junior(初中), senior(高中)")
|
||||
):
|
||||
return RuYuanZaiYuanModel.generate_preschool_education_config(education_stage)
|
||||
|
||||
@router.get("/school/inschool/chart")
|
||||
async def get_in_school_chart_config(
|
||||
education_stage: str = Query(default="preschool", pattern="^(preschool|primary|junior|senior)$",
|
||||
description="教育阶段: preschool(学前), primary(小学), junior(初中), senior(高中)")
|
||||
):
|
||||
return RuYuanZaiYuanModel.generate_in_school_education_config(education_stage)
|
||||
|
||||
|
||||
|
||||
|
BIN
Controller/__pycache__/EducationDataController.cpython-310.pyc
Normal file
BIN
Controller/__pycache__/EducationDataController.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
350
Model/EducationDataModel.py
Normal file
350
Model/EducationDataModel.py
Normal file
@@ -0,0 +1,350 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
class EducationDataModel:
|
||||
# 定义支持的教育阶段映射
|
||||
EDUCATION_STAGES = {
|
||||
'preschool': '学前',
|
||||
'primary': '小学',
|
||||
'junior': '初中',
|
||||
'senior': '高中',
|
||||
'vocational': '中职'
|
||||
}
|
||||
|
||||
# 获取脚本所在目录的绝对路径
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
# 使用绝对路径定义数据目录和文件
|
||||
DATA_DIR = os.path.join(BASE_DIR, '../Data')
|
||||
SCHOOL_COUNT_FILE = os.path.join(DATA_DIR, 'SchoolCount.json')
|
||||
TEACHER_COUNT_FILE = os.path.join(DATA_DIR, 'TeacherCount.json')
|
||||
ENROLLMENT_COUNT_FILE = os.path.join(DATA_DIR, 'ZaiXiaoShengCount.json')
|
||||
ADMISSION_COUNT_FILE = os.path.join(DATA_DIR, 'ZhaoShengCount.json')
|
||||
POPULATION_FILE = os.path.join(DATA_DIR, 'RenKou.json') # 新增:人口数据文件路径
|
||||
|
||||
@staticmethod
|
||||
def load_json_file(file_path):
|
||||
"""加载JSON文件数据"""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f"加载文件 {file_path} 失败: {e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_province_data(data):
|
||||
"""从数据中提取云南省的数据"""
|
||||
if not data or not isinstance(data, list):
|
||||
return None
|
||||
|
||||
# 查找云南省的数据
|
||||
for item in data:
|
||||
if item.get('area_name') == '云南省':
|
||||
return item
|
||||
|
||||
print("未找到云南省的数据")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_school_count_by_year_and_stage(year, stage):
|
||||
"""获取指定年份和学段的学校总数"""
|
||||
school_data = EducationDataModel.load_json_file(EducationDataModel.SCHOOL_COUNT_FILE)
|
||||
province_data = EducationDataModel.get_province_data(school_data)
|
||||
|
||||
if not province_data:
|
||||
return 0
|
||||
|
||||
# 根据学段获取对应的学校数据字段名
|
||||
stage_field_mapping = {
|
||||
'preschool': 'preschool_schools',
|
||||
'primary': 'primary_schools',
|
||||
'junior': 'junior_schools',
|
||||
'senior': 'senior_schools',
|
||||
'vocational': 'vocational_schools'
|
||||
}
|
||||
|
||||
field_name = stage_field_mapping.get(stage)
|
||||
if not field_name or field_name not in province_data:
|
||||
print(f"学段 {stage} 对应的学校数据字段不存在")
|
||||
return 0
|
||||
|
||||
year_data = province_data[field_name].get(str(year))
|
||||
if not year_data:
|
||||
print(f"年份 {year} 的学校数据不存在")
|
||||
return 0
|
||||
|
||||
# 计算学校总数 - 处理vocational_schools的特殊格式
|
||||
try:
|
||||
# 对于vocational学段,数据可能是直接的数值而不是字典
|
||||
if stage == 'vocational' and isinstance(year_data, int):
|
||||
return year_data
|
||||
# 对于其他学段或正常字典格式
|
||||
elif isinstance(year_data, dict):
|
||||
if 'urban' in year_data and 'town' in year_data and 'rural' in year_data:
|
||||
total_schools = year_data.get('urban', 0) + year_data.get('town', 0) + year_data.get('rural', 0)
|
||||
return total_schools
|
||||
elif 'total' in year_data:
|
||||
# 如果没有分区数据但有total字段,使用total
|
||||
return year_data.get('total', 0)
|
||||
else:
|
||||
print(f"年份 {year} 的学校数据缺少必要的字段")
|
||||
return 0
|
||||
else:
|
||||
print(f"年份 {year} 的学校数据格式不正确")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"计算学校总数时出错: {e}")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_teacher_count_by_year_and_stage(year, stage):
|
||||
"""获取指定年份和学段的教职工总数"""
|
||||
teacher_data = EducationDataModel.load_json_file(EducationDataModel.TEACHER_COUNT_FILE)
|
||||
province_data = EducationDataModel.get_province_data(teacher_data)
|
||||
|
||||
if not province_data:
|
||||
return 0
|
||||
|
||||
# 根据学段获取对应的教职工数据字段名
|
||||
stage_field_mapping = {
|
||||
'preschool': 'preschool_teachers',
|
||||
'primary': 'primary_teachers',
|
||||
'junior': 'junior_teachers',
|
||||
'senior': 'senior_teachers',
|
||||
'vocational': 'vocational_teachers'
|
||||
}
|
||||
|
||||
field_name = stage_field_mapping.get(stage)
|
||||
if not field_name or field_name not in province_data:
|
||||
print(f"学段 {stage} 对应的教职工数据字段不存在")
|
||||
return 0
|
||||
|
||||
year_data = province_data[field_name].get(str(year))
|
||||
if not year_data or not isinstance(year_data, dict):
|
||||
print(f"年份 {year} 的教职工数据不存在或格式不正确")
|
||||
return 0
|
||||
|
||||
# 优先使用total_staff,如果为0或不存在,则返回教师总数
|
||||
try:
|
||||
total_staff = year_data.get('total_staff', 0)
|
||||
if total_staff == 0:
|
||||
total_staff = year_data.get('total_teacher', 0)
|
||||
return total_staff
|
||||
except Exception as e:
|
||||
print(f"获取教职工总数时出错: {e}")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_enrollment_count_by_year_and_stage(year, stage):
|
||||
"""获取指定年份和学段的在校生总数"""
|
||||
enrollment_data = EducationDataModel.load_json_file(EducationDataModel.ENROLLMENT_COUNT_FILE)
|
||||
province_data = EducationDataModel.get_province_data(enrollment_data)
|
||||
|
||||
if not province_data or 'student_data' not in province_data:
|
||||
print("未找到学生数据")
|
||||
return 0
|
||||
|
||||
stage_data = province_data['student_data'].get(stage)
|
||||
if not stage_data:
|
||||
print(f"学段 {stage} 的学生数据不存在")
|
||||
return 0
|
||||
|
||||
year_data = stage_data.get(str(year))
|
||||
if not year_data or not isinstance(year_data, dict):
|
||||
print(f"年份 {year} 的学生数据不存在或格式不正确")
|
||||
return 0
|
||||
|
||||
# 返回在校生总数 - 处理vocational数据只有total字段的情况
|
||||
try:
|
||||
if 'urban' in year_data and 'town' in year_data and 'rural' in year_data:
|
||||
# 通过累加城区、镇区、乡村数据计算总数
|
||||
total_enrollment = year_data.get('urban', 0) + year_data.get('town', 0) + year_data.get('rural', 0)
|
||||
return total_enrollment
|
||||
elif 'total' in year_data and stage == 'vocational':
|
||||
# 对于vocational学段,如果只有total字段,使用total
|
||||
return year_data.get('total', 0)
|
||||
else:
|
||||
# 对于其他学段,如果没有分区数据,直接报错
|
||||
print(f"年份 {year} 的学生数据缺少城区、镇区或乡村字段")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"获取在校生总数时出错: {e}")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_admission_count_by_year_and_stage(year, stage):
|
||||
"""获取指定年份和学段的招生总数"""
|
||||
admission_data = EducationDataModel.load_json_file(EducationDataModel.ADMISSION_COUNT_FILE)
|
||||
province_data = EducationDataModel.get_province_data(admission_data)
|
||||
|
||||
if not province_data or 'education_data' not in province_data:
|
||||
print("未找到教育数据")
|
||||
return 0
|
||||
|
||||
stage_data = province_data['education_data'].get(stage)
|
||||
if not stage_data:
|
||||
print(f"学段 {stage} 的教育数据不存在")
|
||||
return 0
|
||||
|
||||
year_data = stage_data.get(str(year))
|
||||
if not year_data or not isinstance(year_data, dict):
|
||||
print(f"年份 {year} 的教育数据不存在或格式不正确")
|
||||
return 0
|
||||
|
||||
# 返回招生总数 - 处理vocational数据只有total字段的情况
|
||||
try:
|
||||
if 'urban' in year_data and 'town' in year_data and 'rural' in year_data:
|
||||
# 通过累加城区、镇区、乡村数据计算总数
|
||||
total_admission = year_data.get('urban', 0) + year_data.get('town', 0) + year_data.get('rural', 0)
|
||||
return total_admission
|
||||
elif 'total' in year_data and stage == 'vocational':
|
||||
# 对于vocational学段,如果只有total字段,使用total
|
||||
return year_data.get('total', 0)
|
||||
else:
|
||||
# 对于其他学段,如果没有分区数据,直接报错
|
||||
print(f"年份 {year} 的教育数据缺少城区、镇区或乡村字段")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"获取招生总数时出错: {e}")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def get_education_data_by_year(year):
|
||||
"""获取指定年份所有学段的教育数据"""
|
||||
result = []
|
||||
|
||||
for stage_code, stage_name in EducationDataModel.EDUCATION_STAGES.items():
|
||||
# 获取各类数据(增加异常处理)
|
||||
try:
|
||||
school_count = EducationDataModel.get_school_count_by_year_and_stage(year, stage_code)
|
||||
teacher_count = EducationDataModel.get_teacher_count_by_year_and_stage(year, stage_code)
|
||||
enrollment_count = EducationDataModel.get_enrollment_count_by_year_and_stage(year, stage_code)
|
||||
admission_count = EducationDataModel.get_admission_count_by_year_and_stage(year, stage_code)
|
||||
|
||||
# 转换为万人单位
|
||||
teacher_count_10k = round(teacher_count / 10000, 2) if teacher_count else 0
|
||||
enrollment_count_10k = round(enrollment_count / 10000, 2) if enrollment_count else 0
|
||||
admission_count_10k = round(admission_count / 10000, 2) if admission_count else 0
|
||||
|
||||
# 添加到结果列表
|
||||
result.append({
|
||||
'education_stage': stage_name,
|
||||
'school_count': school_count,
|
||||
'teacher_count_10k': teacher_count_10k,
|
||||
'enrollment_count_10k': enrollment_count_10k,
|
||||
'admission_count_10k': admission_count_10k
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"处理学段 {stage_name} 时出错: {e}")
|
||||
# 出错时添加一个默认的空数据条目
|
||||
result.append({
|
||||
'education_stage': stage_name,
|
||||
'school_count': 0,
|
||||
'teacher_count_10k': 0,
|
||||
'enrollment_count_10k': 0,
|
||||
'admission_count_10k': 0
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
# 新增:人口数据相关方法
|
||||
@staticmethod
|
||||
def get_population_data_by_year(year):
|
||||
"""获取指定年份的云南省人口数据"""
|
||||
# 加载人口数据文件
|
||||
population_data = EducationDataModel.load_json_file(EducationDataModel.POPULATION_FILE)
|
||||
# 获取云南省数据
|
||||
yunnan_data = EducationDataModel.get_province_data(population_data)
|
||||
|
||||
if not yunnan_data:
|
||||
print(f"未获取到云南省{year}年的人口数据")
|
||||
return None
|
||||
|
||||
year_str = str(year)
|
||||
result = {
|
||||
'year': year,
|
||||
'total_population': yunnan_data.get('total_population', {}).get(year_str, 0), # 万人
|
||||
'birth_population': yunnan_data.get('birth_population', {}).get(year_str, 0), # 原数据单位为个
|
||||
'urban_population': yunnan_data.get('urban_population', {}).get(year_str, 0), # 万人
|
||||
'rural_population': yunnan_data.get('rural_population', {}).get(year_str, 0), # 万人
|
||||
'urbanization_rate': yunnan_data.get('urbanization_rate', {}).get(year_str, 0) # %
|
||||
}
|
||||
|
||||
# 将新生人口转换为万人(如果是整数)
|
||||
if isinstance(result['birth_population'], int):
|
||||
result['birth_population'] = round(result['birth_population'] / 10000, 1)
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def print_population_data(population_data):
|
||||
"""打印人口数据"""
|
||||
if not population_data:
|
||||
print("没有可打印的人口数据")
|
||||
return
|
||||
|
||||
year = population_data.get('year', '未知')
|
||||
print(f"云南省 {year}年人口概览")
|
||||
print("-------------------")
|
||||
print(f"总人口 {population_data.get('total_population', 0):,} 万人")
|
||||
print(f"新生人口 {population_data.get('birth_population', 0)} 万人")
|
||||
print(f"城镇人口 {population_data.get('urban_population', 0):,} 万人")
|
||||
print(f"乡村人口 {population_data.get('rural_population', 0):,} 万人")
|
||||
print(f"城镇化率 {population_data.get('urbanization_rate', 0):.2f} %")
|
||||
|
||||
# 验证数据一致性
|
||||
total = population_data.get('total_population', 0)
|
||||
urban_rural_sum = population_data.get('urban_population', 0) + population_data.get('rural_population', 0)
|
||||
if abs(total - urban_rural_sum) > 0.01:
|
||||
print("\n注意:总人口与城镇人口+乡村人口存在差异")
|
||||
print(f"差异值: {abs(total - urban_rural_sum):.2f} 万人")
|
||||
|
||||
@staticmethod
|
||||
def print_education_data(data, year):
|
||||
"""打印教育数据"""
|
||||
print(f"\n===== {year}年云南省各学段教育数据统计(单位:学校总数-个,其余-万人)=====")
|
||||
print(f"{'学段':<8}{'学校总数':<10}{'教职工总数':<12}{'在校生总数':<12}{'招生总数':<12}")
|
||||
print("=" * 60)
|
||||
|
||||
for item in data:
|
||||
print(f"{item['education_stage']:<8}{item['school_count']:<10}{item['teacher_count_10k']:<12.2f}{item['enrollment_count_10k']:<12.2f}{item['admission_count_10k']:<12.2f}")
|
||||
|
||||
@staticmethod
|
||||
def main(year=2023):
|
||||
"""主函数"""
|
||||
try:
|
||||
print(f"正在获取 {year} 年数据...")
|
||||
print(f"数据目录: {EducationDataModel.DATA_DIR}")
|
||||
|
||||
# 检查数据文件是否存在
|
||||
for file_path in [EducationDataModel.SCHOOL_COUNT_FILE,
|
||||
EducationDataModel.TEACHER_COUNT_FILE,
|
||||
EducationDataModel.ENROLLMENT_COUNT_FILE,
|
||||
EducationDataModel.ADMISSION_COUNT_FILE,
|
||||
EducationDataModel.POPULATION_FILE]: # 新增:检查人口数据文件
|
||||
if os.path.exists(file_path):
|
||||
print(f"找到数据文件: {file_path}")
|
||||
else:
|
||||
print(f"警告:数据文件不存在: {file_path}")
|
||||
|
||||
# 获取并打印教育数据
|
||||
education_data = EducationDataModel.get_education_data_by_year(year)
|
||||
if education_data:
|
||||
EducationDataModel.print_education_data(education_data, year)
|
||||
else:
|
||||
print("未获取到任何教育数据")
|
||||
|
||||
# 新增:获取并打印人口数据
|
||||
print("\n" + "=" * 50)
|
||||
population_data = EducationDataModel.get_population_data_by_year(year)
|
||||
EducationDataModel.print_population_data(population_data)
|
||||
|
||||
except Exception as e:
|
||||
print(f"获取数据时发生错误: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
EducationDataModel.main()
|
@@ -1,14 +1,15 @@
|
||||
import json
|
||||
from pyecharts import options as opts
|
||||
from pyecharts.charts import Bar, Line
|
||||
from pyecharts.globals import CurrentConfig
|
||||
|
||||
from Config.Config import ONLINE_HOST
|
||||
|
||||
CurrentConfig.ONLINE_HOST = ONLINE_HOST
|
||||
|
||||
|
||||
class RuYuanZaiYuanModel:
|
||||
# 定义支持的教育阶段映射
|
||||
EDUCATION_STAGES = {
|
||||
'preschool': '学前',
|
||||
'primary': '小学',
|
||||
'junior': '初中',
|
||||
'senior': '高中'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def load_student_data():
|
||||
try:
|
||||
@@ -26,52 +27,70 @@ class RuYuanZaiYuanModel:
|
||||
return [], []
|
||||
|
||||
@staticmethod
|
||||
def generate_preschool_education_config():
|
||||
# 获取学前教育相关数据
|
||||
# enrollment_data, in_school_data = RuYuanZaiYuanModel.load_student_data()
|
||||
#
|
||||
# # 提取云南省级数据
|
||||
# yunnan_enroll = next((item for item in enrollment_data if item["area_name"] == "云南省"), None)
|
||||
#
|
||||
# if not yunnan_enroll:
|
||||
# return {}
|
||||
#
|
||||
# # 提取年份数据(2015-2024)
|
||||
# years = [str(year) for year in range(2015, 2025)]
|
||||
#
|
||||
# # 构建学前教育数据
|
||||
# urban_data = [] # 城区数据
|
||||
# town_data = [] # 镇区数据
|
||||
# rural_data = [] # 乡村数据
|
||||
# total_enroll = [] # 总入园数
|
||||
#
|
||||
# for year in years:
|
||||
# enroll_data = yunnan_enroll["education_data"]["preschool"].get(year, {})
|
||||
# urban_data.append(enroll_data.get("urban", 0) / 10000) # 转换为万人
|
||||
# town_data.append(enroll_data.get("town", 0) / 10000) # 转换为万人
|
||||
# rural_data.append(enroll_data.get("rural", 0) / 10000) # 转换为万人
|
||||
# # 计算总和作为总入园数,而非使用文件中的total字段
|
||||
# calculated_total = enroll_data.get("urban", 0) + enroll_data.get("town", 0) + enroll_data.get("rural", 0)
|
||||
# total_enroll.append(calculated_total / 10000) # 转换为万人
|
||||
def generate_preschool_education_config(education_stage='preschool'):
|
||||
# 验证教育阶段参数
|
||||
if education_stage not in RuYuanZaiYuanModel.EDUCATION_STAGES:
|
||||
education_stage = 'preschool' # 默认使用学前
|
||||
|
||||
xAxis = ["2019", "2020", "2021", "2022", "2023", "2024", "2025", "2026"]
|
||||
series_data_1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6]
|
||||
series_data_2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6]
|
||||
series_data_3 = [2.4, 5.2, 8.0, 25.4, 27.7, 73.7, 155.6]
|
||||
series_data_4 = [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3]
|
||||
line_data = [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3]
|
||||
data = {"xAxis_data": xAxis,
|
||||
"series_data_1": series_data_1,
|
||||
"series_data_2": series_data_2,
|
||||
"series_data_3": series_data_3,
|
||||
"series_data_4": series_data_4,
|
||||
"line_data": line_data
|
||||
}
|
||||
# 获取学前教育相关数据
|
||||
enrollment_data, in_school_data = RuYuanZaiYuanModel.load_student_data()
|
||||
# 提取云南省级数据
|
||||
yunnan_enroll = next((item for item in enrollment_data if item["area_name"] == "云南省"), None)
|
||||
|
||||
if not yunnan_enroll:
|
||||
return {}
|
||||
|
||||
# # 构建学前教育数据
|
||||
urban_data = [] # 城区数据
|
||||
town_data = [] # 镇区数据
|
||||
rural_data = [] # 乡村数据
|
||||
total_enroll = [] # 总人数
|
||||
|
||||
# 提取年份数据(2015-2024)
|
||||
years = [str(year) for year in range(2015, 2025)]
|
||||
|
||||
for year in years:
|
||||
# 使用传入的教育阶段参数
|
||||
enroll_data = yunnan_enroll["education_data"].get(education_stage, {}).get(year, {})
|
||||
urban_data.append(enroll_data.get("urban", 0) / 10000) # 转换为万人
|
||||
town_data.append(enroll_data.get("town", 0) / 10000) # 转换为万人
|
||||
rural_data.append(enroll_data.get("rural", 0) / 10000) # 转换为万人
|
||||
# 计算总和作为总人数
|
||||
calculated_total = enroll_data.get("urban", 0) + enroll_data.get("town", 0) + enroll_data.get("rural", 0)
|
||||
total_enroll.append(calculated_total / 10000) # 转换为万人
|
||||
|
||||
# 添加2022年基数的粉色折线
|
||||
base_year = "2022"
|
||||
# 找到2022年在years中的索引位置
|
||||
base_index = years.index(base_year) if base_year in years else 0
|
||||
# 获取2022年的总人数作为基数
|
||||
base_value = total_enroll[base_index] if base_index < len(total_enroll) else 0
|
||||
# 创建2022年基数折线数据(2022-2024年)
|
||||
base_2022_line = []
|
||||
for i, year in enumerate(years):
|
||||
# 只在2022年及之后显示基数线
|
||||
if i >= base_index:
|
||||
base_2022_line.append(base_value)
|
||||
else:
|
||||
base_2022_line.append(None) # 2022年之前不显示
|
||||
data = {
|
||||
"xAxis_data": years,
|
||||
"series_data_0": urban_data, # 城区
|
||||
"series_data_1": town_data, # 镇区
|
||||
"series_data_2": rural_data, # 乡村
|
||||
"series_data_3": total_enroll, # 总人数
|
||||
"series_data_4": base_2022_line, # 2022年基数
|
||||
"education_stage": RuYuanZaiYuanModel.EDUCATION_STAGES.get(education_stage, '学前') # 添加教育阶段名称
|
||||
}
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def generate_in_school_education_config():
|
||||
# 获取学前教育相关数据
|
||||
def generate_in_school_education_config(education_stage='preschool'):
|
||||
# 验证教育阶段参数
|
||||
if education_stage not in RuYuanZaiYuanModel.EDUCATION_STAGES:
|
||||
education_stage = 'preschool' # 默认使用学前
|
||||
|
||||
# 获取在校生相关数据
|
||||
enrollment_data, in_school_data = RuYuanZaiYuanModel.load_student_data()
|
||||
|
||||
# 提取云南省级数据
|
||||
@@ -83,15 +102,15 @@ class RuYuanZaiYuanModel:
|
||||
# 提取年份数据(2015-2024)
|
||||
years = [str(year) for year in range(2015, 2025)]
|
||||
|
||||
# 构建学前教育数据
|
||||
# 构建数据
|
||||
urban_data = [] # 城区数据
|
||||
town_data = [] # 镇区数据
|
||||
rural_data = [] # 乡村数据
|
||||
total_in_school = [] # 总在园数
|
||||
total_in_school = [] # 总人数
|
||||
|
||||
for year in years:
|
||||
# 将education_data改为student_data
|
||||
in_school_year_data = yunnan_in_school["student_data"]["preschool"].get(year, {})
|
||||
# 使用传入的教育阶段参数
|
||||
in_school_year_data = yunnan_in_school["student_data"].get(education_stage, {}).get(year, {})
|
||||
|
||||
# 先获取原始数据
|
||||
urban_val = in_school_year_data.get("urban", 0)
|
||||
@@ -111,7 +130,7 @@ class RuYuanZaiYuanModel:
|
||||
base_year = "2022"
|
||||
# 找到2022年在years中的索引位置
|
||||
base_index = years.index(base_year) if base_year in years else 0
|
||||
# 获取2022年的总在园数作为基数
|
||||
# 获取2022年的总人数作为基数
|
||||
base_value = total_in_school[base_index] if base_index < len(total_in_school) else 0
|
||||
# 创建2022年基数折线数据(2022-2024年)
|
||||
base_2022_line = []
|
||||
@@ -122,137 +141,14 @@ class RuYuanZaiYuanModel:
|
||||
else:
|
||||
base_2022_line.append(None) # 2022年之前不显示
|
||||
|
||||
# 构建ECharts配置
|
||||
option = {
|
||||
"tooltip": {
|
||||
"trigger": "axis",
|
||||
"axisPointer": {
|
||||
"type": "cross",
|
||||
"crossStyle": {"color": "#999"}
|
||||
},
|
||||
"textStyle": {"color": "#333"},
|
||||
"backgroundColor": "rgba(255, 255, 255, 0.8)",
|
||||
"borderColor": "rgba(0, 0, 0, 0.2)",
|
||||
"borderWidth": 1
|
||||
},
|
||||
"legend": {
|
||||
"data": ["城区", "镇区", "乡村", "总在园数", "2022年基数(万人)"],
|
||||
"top": 30,
|
||||
"textStyle": {"color": "#333"},
|
||||
"icon": "roundRect",
|
||||
"itemWidth": 12,
|
||||
"itemHeight": 12
|
||||
},
|
||||
"xAxis": [
|
||||
{
|
||||
"type": "category",
|
||||
"data": years,
|
||||
"axisPointer": {"type": "shadow"},
|
||||
"axisLabel": {"color": "#333"},
|
||||
"axisLine": {"lineStyle": {"color": "#333"}}
|
||||
}
|
||||
],
|
||||
"yAxis": [
|
||||
{
|
||||
"type": "value",
|
||||
"name": "人数",
|
||||
"min": 0,
|
||||
"max": 200, # 将左侧Y轴最大值从100修改为200万
|
||||
"interval": 40, # 调整间隔为40万,确保坐标轴上有5个主要刻度(0,40,80,120,160,200)
|
||||
"axisLabel": {
|
||||
"formatter": "{value} 万人",
|
||||
"color": "#333"
|
||||
},
|
||||
"axisLine": {"lineStyle": {"color": "#333"}},
|
||||
"splitLine": {"lineStyle": {"color": "rgba(0,0,0,0.1)"}}
|
||||
},
|
||||
{
|
||||
"type": "value",
|
||||
"name": "总在园数",
|
||||
"min": 0,
|
||||
"max": 320, # 将右侧Y轴最大值从160扩大一倍到320万
|
||||
"interval": 60, # 调整间隔为60万
|
||||
"position": "right",
|
||||
"nameLocation": "end",
|
||||
"nameGap": 30,
|
||||
"axisLabel": {
|
||||
"formatter": "{value} 万人",
|
||||
"color": "#00a859" # 改为绿色
|
||||
},
|
||||
"axisLine": {"show": True, "lineStyle": {"color": "#00a859"}}, # 改为绿色
|
||||
"axisTick": {"show": True},
|
||||
"splitLine": {"show": False}
|
||||
}
|
||||
],
|
||||
"series": [
|
||||
{
|
||||
"name": "城区",
|
||||
"type": "bar",
|
||||
"data": urban_data,
|
||||
"itemStyle": {
|
||||
"color": "#5470c6",
|
||||
"borderRadius": [6, 6, 0, 0]
|
||||
},
|
||||
"barWidth": "25%",
|
||||
"barGap": "-10%"
|
||||
},
|
||||
{
|
||||
"name": "镇区",
|
||||
"type": "bar",
|
||||
"data": town_data,
|
||||
"itemStyle": {
|
||||
"color": "#91cc75",
|
||||
"borderRadius": [6, 6, 0, 0]
|
||||
},
|
||||
"barWidth": "25%",
|
||||
"barGap": "-10%"
|
||||
},
|
||||
{
|
||||
"name": "乡村",
|
||||
"type": "bar",
|
||||
"data": rural_data,
|
||||
"itemStyle": {
|
||||
"color": "#fac858",
|
||||
"borderRadius": [6, 6, 0, 0]
|
||||
},
|
||||
"barWidth": "25%",
|
||||
"barGap": "-10%"
|
||||
},
|
||||
{
|
||||
"name": "总在园数",
|
||||
"type": "line",
|
||||
"yAxisIndex": 1,
|
||||
"data": total_in_school,
|
||||
"lineStyle": {"color": "#00a859", "width": 3}, # 改为绿色
|
||||
"symbol": "circle",
|
||||
"symbolSize": 8,
|
||||
"itemStyle": {"color": "#00a859"}, # 改为绿色
|
||||
"emphasis": {
|
||||
"focus": "series"
|
||||
},
|
||||
"z": 10 # 确保折线图显示在最上层
|
||||
},
|
||||
# 添加2022年基数的粉色折线
|
||||
{
|
||||
"name": "2022年基数(万人)",
|
||||
"type": "line",
|
||||
"yAxisIndex": 1,
|
||||
"data": base_2022_line,
|
||||
"lineStyle": {"color": "#ff9e9e", "width": 2, "type": "solid"},
|
||||
"symbol": "circle",
|
||||
"symbolSize": 6,
|
||||
"itemStyle": {"color": "#ff9e9e"},
|
||||
"emphasis": {
|
||||
"focus": "series"
|
||||
},
|
||||
"z": 5 # 确保折线图显示在柱状图之上,但在总在园数折线之下
|
||||
}
|
||||
],
|
||||
"grid": {
|
||||
"left": "3%",
|
||||
"right": "15%", # 稍微增加右侧边距,确保Y轴标签不被截断
|
||||
"bottom": "3%",
|
||||
"containLabel": True
|
||||
}
|
||||
data = {
|
||||
"xAxis_data": years,
|
||||
"series_data_0": urban_data,
|
||||
"series_data_1": town_data,
|
||||
"series_data_2": rural_data,
|
||||
"series_data_3": total_in_school,
|
||||
"series_data_4": base_2022_line,
|
||||
"education_stage": RuYuanZaiYuanModel.EDUCATION_STAGES.get(education_stage, '学前') # 添加教育阶段名称
|
||||
}
|
||||
return option
|
||||
|
||||
return data
|
||||
|
BIN
Model/__pycache__/EducationDataModel.cpython-310.pyc
Normal file
BIN
Model/__pycache__/EducationDataModel.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
Start.py
3
Start.py
@@ -4,7 +4,7 @@ from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
import uvicorn
|
||||
from Controller.RuYuanZaiYuanCountController import router as ruyuanZaiYuan_router
|
||||
|
||||
from Controller.EducationDataController import router as educationData_router
|
||||
# 创建 FastAPI 应用实例
|
||||
app = FastAPI(title="云南教育决策研究服务系统", description="云南省教育数据分析和可视化平台")
|
||||
|
||||
@@ -14,6 +14,7 @@ app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
# 包含大屏展示路由
|
||||
app.include_router(ruyuanZaiYuan_router)
|
||||
|
||||
app.include_router(educationData_router)
|
||||
# 主程序入口
|
||||
if __name__ == "__main__":
|
||||
# 启动 FastAPI 应用,监听 8100 端口
|
||||
|
274
Test/population_statistics.py
Normal file
274
Test/population_statistics.py
Normal file
@@ -0,0 +1,274 @@
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
class PopulationStatistics:
|
||||
def __init__(self, data_file):
|
||||
"""初始化人口统计类,加载数据文件"""
|
||||
self.data_file = data_file
|
||||
self.data = self.load_data()
|
||||
self.years = list(range(2015, 2025)) # 2015-2024年
|
||||
|
||||
def load_data(self):
|
||||
"""加载人口数据JSON文件"""
|
||||
try:
|
||||
with open(self.data_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
print(f"错误:找不到数据文件 {self.data_file}")
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
print(f"错误:数据文件 {self.data_file} 格式不正确")
|
||||
return []
|
||||
|
||||
def get_province_data(self):
|
||||
"""获取云南省全省数据"""
|
||||
for item in self.data:
|
||||
if item['area_name'] == '云南省' and item['area_code'] == '530000000':
|
||||
return item
|
||||
return None
|
||||
|
||||
def get_city_data(self, city_name):
|
||||
"""获取指定城市的数据"""
|
||||
for item in self.data:
|
||||
if item['area_name'] == city_name:
|
||||
return item
|
||||
return None
|
||||
|
||||
def get_all_cities(self):
|
||||
"""获取所有地市级城市列表"""
|
||||
cities = []
|
||||
# 地市级城市的area_code格式为53XX00000
|
||||
for item in self.data:
|
||||
if len(item['area_code']) == 9 and item['area_code'][-5:] == '00000' and item['area_code'] != '530000000':
|
||||
cities.append(item)
|
||||
return cities
|
||||
|
||||
def calculate_total_population_by_year(self, level='province'):
|
||||
"""按年份计算总人口
|
||||
level: 'province'(全省), 'city'(昆明市), 'all_cities'(所有地级市)
|
||||
"""
|
||||
result = {}
|
||||
|
||||
if level == 'province':
|
||||
province_data = self.get_province_data()
|
||||
if province_data:
|
||||
result = province_data['total_population']
|
||||
|
||||
elif level == 'city':
|
||||
city_data = self.get_city_data('昆明市')
|
||||
if city_data:
|
||||
result = city_data['total_population']
|
||||
|
||||
elif level == 'all_cities':
|
||||
cities = self.get_all_cities()
|
||||
for year in self.years:
|
||||
total = 0
|
||||
for city in cities:
|
||||
if str(year) in city['total_population']:
|
||||
total += city['total_population'][str(year)]
|
||||
result[str(year)] = total
|
||||
|
||||
return result
|
||||
|
||||
def calculate_urbanization_trend(self, area_name='云南省'):
|
||||
"""计算指定地区的城镇化率趋势"""
|
||||
area_data = None
|
||||
if area_name == '云南省':
|
||||
area_data = self.get_province_data()
|
||||
else:
|
||||
area_data = self.get_city_data(area_name)
|
||||
|
||||
if area_data and 'urbanization_rate' in area_data:
|
||||
return area_data['urbanization_rate']
|
||||
return {}
|
||||
|
||||
def compare_city_populations(self, year=2023):
|
||||
"""比较指定年份各城市的人口数量"""
|
||||
cities = self.get_all_cities()
|
||||
result = {}
|
||||
|
||||
for city in cities:
|
||||
if str(year) in city['total_population']:
|
||||
result[city['area_name']] = city['total_population'][str(year)]
|
||||
|
||||
# 按人口数量排序
|
||||
return dict(sorted(result.items(), key=lambda x: x[1], reverse=True))
|
||||
|
||||
def calculate_population_growth(self, area_name='云南省', start_year=2020, end_year=2023):
|
||||
"""计算指定地区在指定时间段内的人口增长率"""
|
||||
area_data = None
|
||||
if area_name == '云南省':
|
||||
area_data = self.get_province_data()
|
||||
else:
|
||||
area_data = self.get_city_data(area_name)
|
||||
|
||||
if not area_data:
|
||||
return None
|
||||
|
||||
start_pop = area_data['total_population'].get(str(start_year), 0)
|
||||
end_pop = area_data['total_population'].get(str(end_year), 0)
|
||||
|
||||
if start_pop == 0:
|
||||
return None
|
||||
|
||||
growth_rate = ((end_pop - start_pop) / start_pop) * 100
|
||||
return growth_rate
|
||||
|
||||
def analyze_birth_rate(self, area_name='云南省'):
|
||||
"""分析指定地区的出生率趋势"""
|
||||
area_data = None
|
||||
if area_name == '云南省':
|
||||
area_data = self.get_province_data()
|
||||
else:
|
||||
area_data = self.get_city_data(area_name)
|
||||
|
||||
if not area_data or 'birth_population' not in area_data or 'total_population' not in area_data:
|
||||
return {}
|
||||
|
||||
birth_rates = {}
|
||||
for year in self.years:
|
||||
year_str = str(year)
|
||||
if year_str in area_data['birth_population'] and year_str in area_data['total_population']:
|
||||
birth_pop = area_data['birth_population'][year_str]
|
||||
total_pop = area_data['total_population'][year_str]
|
||||
|
||||
# 注意:总人口单位是万人,出生人口单位是个,需要统一单位
|
||||
if total_pop > 0 and birth_pop > 0:
|
||||
birth_rate = (birth_pop / (total_pop * 10000)) * 1000 # 千分比
|
||||
birth_rates[year] = birth_rate
|
||||
|
||||
return birth_rates
|
||||
|
||||
def save_results_to_file(self, results, filename):
|
||||
"""将统计结果保存到文件"""
|
||||
# 创建结果目录
|
||||
result_dir = os.path.join(os.path.dirname(self.data_file), '../Results')
|
||||
os.makedirs(result_dir, exist_ok=True)
|
||||
|
||||
# 生成带时间戳的文件名
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
full_filename = f"{filename}_{timestamp}.txt"
|
||||
full_path = os.path.join(result_dir, full_filename)
|
||||
|
||||
# 保存结果
|
||||
with open(full_path, 'w', encoding='utf-8') as f:
|
||||
f.write(f"人口统计结果 - 生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
|
||||
for key, value in results.items():
|
||||
if isinstance(value, dict):
|
||||
f.write(f"{key}:\n")
|
||||
for k, v in value.items():
|
||||
f.write(f" {k}: {v}\n")
|
||||
else:
|
||||
f.write(f"{key}: {value}\n")
|
||||
|
||||
print(f"统计结果已保存至:{full_path}")
|
||||
return full_path
|
||||
|
||||
# 主函数演示如何使用这个类
|
||||
if __name__ == "__main__":
|
||||
# 数据文件路径
|
||||
data_file = os.path.join(os.path.dirname(__file__), '../Data/RenKou.json')
|
||||
|
||||
# 创建统计类实例
|
||||
stats = PopulationStatistics(data_file)
|
||||
|
||||
# 检查数据是否成功加载
|
||||
if not stats.data:
|
||||
print("无法加载数据,程序退出。")
|
||||
exit(1)
|
||||
|
||||
# 主菜单
|
||||
print("云南省人口数据统计分析工具")
|
||||
print("========================")
|
||||
|
||||
while True:
|
||||
print("\n请选择要执行的统计分析:")
|
||||
print("1. 查看云南省历年总人口统计")
|
||||
print("2. 查看昆明市历年总人口统计")
|
||||
print("3. 分析云南省城镇化率趋势")
|
||||
print("4. 分析昆明市城镇化率趋势")
|
||||
print("5. 比较2023年各城市人口数量")
|
||||
print("6. 计算云南省2020-2023年人口增长率")
|
||||
print("7. 分析云南省出生率趋势")
|
||||
print("8. 分析昆明市出生率趋势")
|
||||
print("9. 导出所有统计结果")
|
||||
print("0. 退出程序")
|
||||
|
||||
choice = input("请输入您的选择(0-9):")
|
||||
|
||||
if choice == '0':
|
||||
print("感谢使用,再见!")
|
||||
break
|
||||
|
||||
elif choice == '1':
|
||||
result = stats.calculate_total_population_by_year('province')
|
||||
print("\n云南省历年总人口统计(单位:万人):")
|
||||
for year, population in result.items():
|
||||
print(f"{year}年: {population}")
|
||||
|
||||
elif choice == '2':
|
||||
result = stats.calculate_total_population_by_year('city')
|
||||
print("\n昆明市历年总人口统计(单位:万人):")
|
||||
for year, population in result.items():
|
||||
print(f"{year}年: {population}")
|
||||
|
||||
elif choice == '3':
|
||||
result = stats.calculate_urbanization_trend('云南省')
|
||||
print("\n云南省历年城镇化率(单位:%):")
|
||||
for year, rate in result.items():
|
||||
print(f"{year}年: {rate}")
|
||||
|
||||
elif choice == '4':
|
||||
result = stats.calculate_urbanization_trend('昆明市')
|
||||
print("\n昆明市历年城镇化率(单位:%):")
|
||||
for year, rate in result.items():
|
||||
print(f"{year}年: {rate}")
|
||||
|
||||
elif choice == '5':
|
||||
result = stats.compare_city_populations(2023)
|
||||
print("\n2023年各城市人口数量排名(单位:万人):")
|
||||
for i, (city, population) in enumerate(result.items(), 1):
|
||||
print(f"{i}. {city}: {population}")
|
||||
|
||||
elif choice == '6':
|
||||
rate = stats.calculate_population_growth('云南省', 2020, 2023)
|
||||
if rate is not None:
|
||||
print(f"\n云南省2020-2023年人口增长率: {rate:.2f}%")
|
||||
else:
|
||||
print("\n无法计算人口增长率")
|
||||
|
||||
elif choice == '7':
|
||||
result = stats.analyze_birth_rate('云南省')
|
||||
print("\n云南省历年出生率(单位:‰):")
|
||||
for year, rate in result.items():
|
||||
print(f"{year}年: {rate:.2f}")
|
||||
|
||||
elif choice == '8':
|
||||
result = stats.analyze_birth_rate('昆明市')
|
||||
print("\n昆明市历年出生率(单位:‰):")
|
||||
for year, rate in result.items():
|
||||
print(f"{year}年: {rate:.2f}")
|
||||
|
||||
elif choice == '9':
|
||||
# 收集所有统计结果
|
||||
all_results = {
|
||||
"云南省历年总人口统计(万人)": stats.calculate_total_population_by_year('province'),
|
||||
"昆明市历年总人口统计(万人)": stats.calculate_total_population_by_year('city'),
|
||||
"云南省历年城镇化率(%)": stats.calculate_urbanization_trend('云南省'),
|
||||
"昆明市历年城镇化率(%)": stats.calculate_urbanization_trend('昆明市'),
|
||||
"2023年各城市人口数量排名(万人)": stats.compare_city_populations(2023),
|
||||
"云南省2020-2023年人口增长率(%)": stats.calculate_population_growth('云南省', 2020, 2023),
|
||||
"云南省历年出生率(‰)": stats.analyze_birth_rate('云南省'),
|
||||
"昆明市历年出生率(‰)": stats.analyze_birth_rate('昆明市')
|
||||
}
|
||||
|
||||
# 保存结果到文件
|
||||
file_path = stats.save_results_to_file(all_results, "population_statistics")
|
||||
print(f"\n所有统计结果已保存至文件:{file_path}")
|
||||
|
||||
else:
|
||||
print("\n无效的选择,请重新输入。")
|
||||
|
||||
# 等待用户按Enter键继续
|
||||
input("\n按Enter键继续...")
|
52
Test/read_population_data.py
Normal file
52
Test/read_population_data.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
# 获取脚本所在目录
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# 构建数据文件的绝对路径
|
||||
file_path = os.path.join(script_dir, '../Data/RenKou.json')
|
||||
|
||||
# 读取JSON数据
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
population_data = json.load(f)
|
||||
|
||||
# 查找云南省的数据
|
||||
for area in population_data:
|
||||
if area.get('area_name') == '云南省':
|
||||
yunnan_data = area
|
||||
break
|
||||
|
||||
# 提取2023年的人口数据
|
||||
year = '2023'
|
||||
|
||||
# 总人口(万人)
|
||||
total_population = yunnan_data.get('total_population', {}).get(year, 0)
|
||||
|
||||
# 新生人口(万人,注意原数据是整数,需要转换为万人)
|
||||
birth_population = yunnan_data.get('birth_population', {}).get(year, 0)
|
||||
# 转换为万人(如果是整数)
|
||||
if isinstance(birth_population, int):
|
||||
birth_population = round(birth_population / 10000, 1)
|
||||
|
||||
# 城镇人口(万人)
|
||||
urban_population = yunnan_data.get('urban_population', {}).get(year, 0)
|
||||
|
||||
# 乡村人口(万人)
|
||||
rural_population = yunnan_data.get('rural_population', {}).get(year, 0)
|
||||
|
||||
# 城镇化率(%)
|
||||
urbanization_rate = yunnan_data.get('urbanization_rate', {}).get(year, 0)
|
||||
|
||||
# 打印结果
|
||||
print("云南省 2023年人口概览")
|
||||
print("-------------------")
|
||||
print(f"总人口 {total_population:,} 万人")
|
||||
print(f"新生人口 {birth_population} 万人")
|
||||
print(f"城镇人口 {urban_population:,} 万人")
|
||||
print(f"乡村人口 {rural_population:,} 万人")
|
||||
print(f"城镇化率 {urbanization_rate:.2f} %")
|
||||
|
||||
# 验证数据一致性
|
||||
if abs(total_population - (urban_population + rural_population)) > 0.01:
|
||||
print("\n注意:总人口与城镇人口+乡村人口存在差异")
|
||||
print(f"差异值: {abs(total_population - (urban_population + rural_population)):.2f} 万人")
|
166
Test/test_education_interfaces.py
Normal file
166
Test/test_education_interfaces.py
Normal file
@@ -0,0 +1,166 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
# API基础URL
|
||||
BASE_URL = "http://localhost:8100/RuYuanZaiYuan"
|
||||
EDUCATION_DATA_BASE_URL = "http://localhost:8100/EducationData"
|
||||
|
||||
# 支持的教育阶段
|
||||
test_education_stages = [
|
||||
("preschool", "学前"),
|
||||
("primary", "小学"),
|
||||
("junior", "初中"),
|
||||
("senior", "高中")
|
||||
]
|
||||
|
||||
# 测试年份
|
||||
test_years = [2023, 2022, 2024]
|
||||
|
||||
|
||||
def test_school_chart_interface():
|
||||
"""测试获取教育阶段图表数据接口"""
|
||||
print("\n===== 测试 /school/chart 接口 =====")
|
||||
|
||||
for stage_code, stage_name in test_education_stages:
|
||||
url = f"{BASE_URL}/school/chart?education_stage={stage_code}"
|
||||
print(f"\n测试 {stage_name}({stage_code}) 数据:")
|
||||
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status() # 如果状态码不是200,抛出异常
|
||||
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 验证返回数据的基本结构
|
||||
assert "xAxis_data" in data, "返回数据缺少xAxis_data字段"
|
||||
assert "series_data_0" in data, "返回数据缺少series_data_0字段(城区数据)"
|
||||
assert "series_data_1" in data, "返回数据缺少series_data_1字段(镇区数据)"
|
||||
assert "series_data_2" in data, "返回数据缺少series_data_2字段(乡村数据)"
|
||||
assert "series_data_3" in data, "返回数据缺少series_data_3字段(总人数数据)"
|
||||
assert "series_data_4" in data, "返回数据缺少series_data_4字段(2022年基数数据)"
|
||||
assert "education_stage" in data, "返回数据缺少education_stage字段"
|
||||
assert data["education_stage"] == stage_name, f"教育阶段名称不匹配,期望: {stage_name},实际: {data['education_stage']}"
|
||||
|
||||
print(f"✅ {stage_name} 数据验证通过")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
except AssertionError as e:
|
||||
print(f"❌ 数据验证失败: {e}")
|
||||
|
||||
# 添加短暂延迟,避免请求过于频繁
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
# @router.get("/school/inschool/chart")
|
||||
# async def get_in_school_chart_config(
|
||||
# education_stage: str = Query(default="preschool", pattern="^(preschool|primary|junior|senior)$",
|
||||
# description="教育阶段: preschool(学前), primary(小学), junior(初中), senior(高中)")
|
||||
# ):
|
||||
# return RuYuanZaiYuanModel.generate_in_school_education_config(education_stage)
|
||||
#
|
||||
|
||||
|
||||
def test_education_data_by_year():
|
||||
"""测试获取指定年份教育数据接口"""
|
||||
print("\n===== 测试 /EducationData/byYear 接口 =====")
|
||||
|
||||
# 测试不同年份的数据
|
||||
for year in test_years:
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={year}"
|
||||
print(f"\n测试 {year} 年数据:")
|
||||
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status() # 如果状态码不是200,抛出异常
|
||||
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 验证返回数据的基本结构
|
||||
assert "code" in data, "返回数据缺少code字段"
|
||||
assert "message" in data, "返回数据缺少message字段"
|
||||
assert "data" in data, "返回数据缺少data字段"
|
||||
assert data["code"] == 200, f"状态码不匹配,期望: 200,实际: {data['code']}"
|
||||
assert isinstance(data["data"], list), "data字段应为列表类型"
|
||||
|
||||
# 验证数据内容
|
||||
if data["data"]:
|
||||
# 检查每个数据项的结构
|
||||
for item in data["data"]:
|
||||
assert "education_stage" in item, "数据项缺少education_stage字段"
|
||||
assert "school_count" in item, "数据项缺少school_count字段"
|
||||
assert "teacher_count_10k" in item, "数据项缺少teacher_count_10k字段"
|
||||
assert "enrollment_count_10k" in item, "数据项缺少enrollment_count_10k字段"
|
||||
assert "admission_count_10k" in item, "数据项缺少admission_count_10k字段"
|
||||
|
||||
# 检查数值类型
|
||||
assert isinstance(item["school_count"], (int, float)), "school_count应为数值类型"
|
||||
assert isinstance(item["teacher_count_10k"], (int, float)), "teacher_count_10k应为数值类型"
|
||||
assert isinstance(item["enrollment_count_10k"], (int, float)), "enrollment_count_10k应为数值类型"
|
||||
assert isinstance(item["admission_count_10k"], (int, float)), "admission_count_10k应为数值类型"
|
||||
|
||||
print(f"✅ {year} 年数据验证通过,共包含 {len(data['data'])} 个教育阶段的数据")
|
||||
else:
|
||||
print(f"⚠️ {year} 年未返回数据")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
except AssertionError as e:
|
||||
print(f"❌ 数据验证失败: {e}")
|
||||
|
||||
# 添加短暂延迟,避免请求过于频繁
|
||||
time.sleep(0.5)
|
||||
|
||||
# 测试边界值
|
||||
print("\n===== 测试边界值 =====")
|
||||
|
||||
# 测试最小值年份
|
||||
min_year = 2015
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={min_year}"
|
||||
print(f"\n测试最小值年份 {min_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"✅ 最小值年份测试通过")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
# 测试最大值年份
|
||||
max_year = 2028
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={max_year}"
|
||||
print(f"\n测试最大值年份 {max_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"✅ 最大值年份测试通过")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
# 测试超出范围的年份
|
||||
invalid_year = 2030
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={invalid_year}"
|
||||
print(f"\n测试超出范围的年份 {invalid_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
if response.status_code == 422: # FastAPI的验证错误状态码
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"✅ 超出范围年份正确返回验证错误")
|
||||
else:
|
||||
print(f"❌ 期望状态码422,实际: {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试原有接口
|
||||
# test_school_chart_interface()
|
||||
|
||||
# 测试新添加的教育数据接口
|
||||
test_education_data_by_year()
|
124
Test/test_population_data_interface.py
Normal file
124
Test/test_population_data_interface.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
# API基础URL
|
||||
EDUCATION_DATA_BASE_URL = "http://localhost:8100/EducationData"
|
||||
|
||||
# 测试年份
|
||||
test_years = [2023, 2022, 2024]
|
||||
|
||||
|
||||
def test_population_data_by_year():
|
||||
"""测试获取指定年份人口数据接口"""
|
||||
print("\n===== 测试 /EducationData/populationByYear 接口 =====")
|
||||
|
||||
# 测试不同年份的数据
|
||||
for year in test_years:
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/populationByYear?year={year}"
|
||||
print(f"\n测试 {year} 年人口数据:")
|
||||
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status() # 如果状态码不是200,抛出异常
|
||||
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 验证返回数据的基本结构
|
||||
assert "code" in data, "返回数据缺少code字段"
|
||||
assert "message" in data, "返回数据缺少message字段"
|
||||
assert "data" in data, "返回数据缺少data字段"
|
||||
assert data["code"] == 200, f"状态码不匹配,期望: 200,实际: {data['code']}"
|
||||
|
||||
# 验证数据内容
|
||||
if data["data"]:
|
||||
# 检查数据项的结构
|
||||
population_data = data["data"]
|
||||
assert "year" in population_data, "数据缺少year字段"
|
||||
assert "total_population" in population_data, "数据缺少total_population字段"
|
||||
assert "birth_population" in population_data, "数据缺少birth_population字段"
|
||||
assert "urban_population" in population_data, "数据缺少urban_population字段"
|
||||
assert "rural_population" in population_data, "数据缺少rural_population字段"
|
||||
assert "urbanization_rate" in population_data, "数据缺少urbanization_rate字段"
|
||||
|
||||
# 检查数值类型
|
||||
assert isinstance(population_data["year"], int), "year应为整数类型"
|
||||
assert isinstance(population_data["total_population"], (int, float)), "total_population应为数值类型"
|
||||
assert isinstance(population_data["birth_population"], (int, float)), "birth_population应为数值类型"
|
||||
assert isinstance(population_data["urban_population"], (int, float)), "urban_population应为数值类型"
|
||||
assert isinstance(population_data["rural_population"], (int, float)), "rural_population应为数值类型"
|
||||
assert isinstance(population_data["urbanization_rate"], (int, float)), "urbanization_rate应为数值类型"
|
||||
|
||||
# 检查年份是否匹配
|
||||
assert population_data["year"] == year, f"年份不匹配,期望: {year},实际: {population_data['year']}"
|
||||
|
||||
print(f"✅ {year} 年人口数据验证通过")
|
||||
else:
|
||||
print(f"⚠️ {year} 年未返回人口数据")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
except AssertionError as e:
|
||||
print(f"❌ 数据验证失败: {e}")
|
||||
|
||||
# 添加短暂延迟,避免请求过于频繁
|
||||
time.sleep(0.5)
|
||||
|
||||
# 测试边界值
|
||||
print("\n===== 测试边界值 =====")
|
||||
|
||||
# 测试最小值年份
|
||||
min_year = 2015
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/populationByYear?year={min_year}"
|
||||
print(f"\n测试最小值年份 {min_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
if data["code"] == 200 or data["code"] == 404:
|
||||
print(f"✅ 最小值年份测试通过")
|
||||
else:
|
||||
print(f"❌ 状态码异常: {data['code']}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
# 测试最大值年份
|
||||
max_year = 2028
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/populationByYear?year={max_year}"
|
||||
print(f"\n测试最大值年份 {max_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
if data["code"] == 200 or data["code"] == 404:
|
||||
print(f"✅ 最大值年份测试通过")
|
||||
else:
|
||||
print(f"❌ 状态码异常: {data['code']}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
# 测试超出范围的年份
|
||||
invalid_year = 2030
|
||||
url = f"{EDUCATION_DATA_BASE_URL}/populationByYear?year={invalid_year}"
|
||||
print(f"\n测试超出范围的年份 {invalid_year}:")
|
||||
try:
|
||||
response = requests.get(url)
|
||||
if response.status_code == 422: # FastAPI的验证错误状态码
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"✅ 超出范围年份正确返回验证错误")
|
||||
else:
|
||||
data = response.json()
|
||||
print(f"响应状态码: {response.status_code}")
|
||||
print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
print(f"❌ 期望状态码422,实际: {response.status_code}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ 请求失败: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 测试新添加的人口数据接口
|
||||
test_population_data_by_year()
|
@@ -74,7 +74,7 @@ def main():
|
||||
},
|
||||
|
||||
# 初中教育
|
||||
'junior_high_schools': {
|
||||
'junior_schools': {
|
||||
'years': [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024],
|
||||
'columns': [
|
||||
{'year': 2015, 'urban': 'CF', 'town': 'CG', 'rural': 'CH'},
|
||||
@@ -92,7 +92,7 @@ def main():
|
||||
},
|
||||
|
||||
# 普通高中教育
|
||||
'senior_high_schools': {
|
||||
'senior_schools': {
|
||||
'years': [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024],
|
||||
'columns': [
|
||||
{'year': 2015, 'urban': 'DT', 'town': 'DU', 'rural': 'DV'},
|
||||
|
@@ -53,7 +53,7 @@ EDUCATION_STAGES = {
|
||||
{'year': 2024, 'total_staff': 'EZ', 'urban_staff': 'FA', 'town_staff': 'FB', 'rural_staff': 'FC', 'total_teacher': 'FD', 'urban_teacher': 'FE', 'town_teacher': 'FF', 'rural_teacher': 'FG'}
|
||||
]
|
||||
},
|
||||
'junior_high_teachers': {
|
||||
'junior_teachers': {
|
||||
'years': [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024],
|
||||
'columns': [
|
||||
{'year': 2015, 'total_staff': 'FH', 'urban_staff': 'FI', 'town_staff': 'FJ', 'rural_staff': 'FK', 'total_teacher': 'FL', 'urban_teacher': 'FM', 'town_teacher': 'FN', 'rural_teacher': 'FO'},
|
||||
@@ -68,7 +68,7 @@ EDUCATION_STAGES = {
|
||||
{'year': 2024, 'total_staff': 'IB', 'urban_staff': 'IC', 'town_staff': 'ID', 'rural_staff': 'IE', 'total_teacher': 'IF', 'urban_teacher': 'IG', 'town_teacher': 'IH', 'rural_teacher': 'II'}
|
||||
]
|
||||
},
|
||||
'senior_high_teachers': {
|
||||
'senior_teachers': {
|
||||
'years': [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024],
|
||||
'columns': [
|
||||
{'year': 2015, 'total_staff': 'IJ', 'urban_staff': 'IK', 'town_staff': 'IL', 'rural_staff': 'IM', 'total_teacher': 'IN', 'urban_teacher': 'IO', 'town_teacher': 'IP', 'rural_teacher': 'IQ'},
|
||||
|
@@ -1,135 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>云南省学前教育数据</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<style>
|
||||
.chart-controls {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-group {
|
||||
display: inline-flex;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
background: #f0f0f0;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.btn.active {
|
||||
background: #409eff;
|
||||
color: white;
|
||||
}
|
||||
.btn:hover:not(.active) {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>学前教育发展规模预测</h1>
|
||||
|
||||
<div class="chart-controls">
|
||||
<div class="btn-group">
|
||||
<button class="btn active" data-type="enroll">入园数总量</button>
|
||||
<button class="btn" data-type="inschool">在园数总量</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="preschoolChart" style="width: 100%; height: 500px;"></div>
|
||||
<div id="message" class="message"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 初始化图表
|
||||
var preschoolChart = echarts.init(document.getElementById('preschoolChart'));
|
||||
var chartData = null;
|
||||
var currentType = 'enroll';
|
||||
|
||||
// 显示加载状态
|
||||
function showLoading() {
|
||||
preschoolChart.showLoading();
|
||||
}
|
||||
|
||||
// 隐藏加载状态
|
||||
function hideLoading() {
|
||||
preschoolChart.hideLoading();
|
||||
}
|
||||
|
||||
// 显示错误信息
|
||||
function showError(message) {
|
||||
$('#message').text('错误: ' + message);
|
||||
console.error(message);
|
||||
}
|
||||
|
||||
// 渲染图表
|
||||
function renderChart() {
|
||||
if (!chartData) return;
|
||||
|
||||
var option = JSON.parse(JSON.stringify(chartData));
|
||||
|
||||
// 根据用户要求,现在显示所有系列数据,不需要过滤
|
||||
preschoolChart.setOption(option);
|
||||
}
|
||||
|
||||
// 加载学前教育数据
|
||||
function loadPreschoolData() {
|
||||
showLoading();
|
||||
|
||||
// 根据当前类型加载不同数据
|
||||
var url = currentType === 'enroll' ?
|
||||
'/RuYuanZaiYuan/school/preschool/chart' :
|
||||
'/RuYuanZaiYuan/school/preschool/inschool/chart';
|
||||
|
||||
$.getJSON(url)
|
||||
.done(function(data) {
|
||||
chartData = data;
|
||||
renderChart();
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
showError(errorThrown || '获取数据失败,请检查接口是否正常');
|
||||
})
|
||||
.always(function() {
|
||||
hideLoading();
|
||||
});
|
||||
}
|
||||
|
||||
// 按钮点击事件
|
||||
$(document).ready(function() {
|
||||
loadPreschoolData();
|
||||
|
||||
$('.btn').click(function() {
|
||||
$('.btn').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
currentType = $(this).data('type');
|
||||
loadPreschoolData(); // 点击按钮后重新加载数据,而不是只渲染
|
||||
});
|
||||
|
||||
// 窗口大小变化时调整图表
|
||||
$(window).resize(function() {
|
||||
preschoolChart.resize();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -166,8 +166,8 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script type="text/javascript" src="js/jquery.js"></script>
|
||||
<script type="text/javascript" src="https://gcore.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery-3.7.1.min.js"></script>
|
||||
<script type="text/javascript" src="js/echarts.min.js"></script>
|
||||
<script language="JavaScript" src="js/index.js"></script>
|
||||
<script language="JavaScript" src="js/data/index.js"></script>
|
||||
</body>
|
||||
|
@@ -36,43 +36,108 @@ option_1_1 = {
|
||||
name: "城区",
|
||||
type: "bar",
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "镇区",
|
||||
type: "bar",
|
||||
data: [ ],
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "乡村",
|
||||
type: "bar",
|
||||
data: [ ],
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "总入园数",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
data: [
|
||||
],
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
},
|
||||
{
|
||||
name: "2022年基数",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
data: [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
105.6714,
|
||||
105.6714,
|
||||
105.6714,
|
||||
],
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => typeof v === "number" ? v + " 万人" : v },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
option_1_2 = {
|
||||
grid: { left: 0, right: 0, top: 40, bottom: 10, containLabel: true },
|
||||
textStyle: { color: "#fff" },
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: { type: "cross", crossStyle: { color: "#999" } },
|
||||
textStyle: { color: "#fff" },
|
||||
backgroundColor: "rgba(96,98,102,0.8)",
|
||||
borderColor: "rgba(255,255,255,0.3)",
|
||||
borderWidth: 1,
|
||||
},
|
||||
legend: {
|
||||
data: ["城区", "镇区", "乡村", "总在园数", "2022年基数"],
|
||||
top: 0,
|
||||
textStyle: { color: "#fff" },
|
||||
icon: "roundRect",
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: [],
|
||||
axisPointer: { type: "shadow" },
|
||||
axisLine: { lineStyle: { color: "#fff" } },
|
||||
axisLabel: { color: "#fff" },
|
||||
nameTextStyle: { color: "#fff" },
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{ type: "value", axisLabel: { formatter: "{value}", color: "#fff" } },
|
||||
{ type: "value", axisLabel: { formatter: "{value}", color: "#fff" } },
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "城区",
|
||||
type: "bar",
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "镇区",
|
||||
type: "bar",
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "乡村",
|
||||
type: "bar",
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
itemStyle: { borderRadius: [6, 6, 0, 0] },
|
||||
},
|
||||
{
|
||||
name: "总在园数",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => v + " 万人" },
|
||||
},
|
||||
{
|
||||
name: "2022年基数",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
data: [],
|
||||
tooltip: { valueFormatter: (v) => typeof v === "number" ? v + " 万人" : v },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
45
static/js/echarts.min.js
vendored
Normal file
45
static/js/echarts.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -16,11 +16,11 @@ $(window).load(function () {
|
||||
});
|
||||
|
||||
$(function () {
|
||||
echarts_1();
|
||||
echarts_1_1();
|
||||
echarts_2();
|
||||
// echarts_3();
|
||||
|
||||
function echarts_1() {
|
||||
function echarts_1_1() {
|
||||
var myChart = echarts.init(document.getElementById("echarts01"));
|
||||
|
||||
$.ajax({
|
||||
@@ -28,15 +28,13 @@ $(function () {
|
||||
async: false,
|
||||
dataType: "json",
|
||||
url: "/RuYuanZaiYuan/school/preschool/chart",
|
||||
success: function (res) {
|
||||
option_1_1.series.forEach((seriesItem, index) => {
|
||||
seriesItem.tooltip = { valueFormatter: (v) => v + " 万人" };
|
||||
});
|
||||
success: function (res) {
|
||||
option_1_1.xAxis[0].data = res.xAxis_data;
|
||||
option_1_1.series[0].data = res.series_data_1;
|
||||
option_1_1.series[1].data = res.series_data_2;
|
||||
option_1_1.series[2].data = res.series_data_3;
|
||||
option_1_1.series[3].data = res.series_data_4;
|
||||
option_1_1.series[0].data = res.series_data_0;
|
||||
option_1_1.series[1].data = res.series_data_1;
|
||||
option_1_1.series[2].data = res.series_data_2;
|
||||
option_1_1.series[3].data = res.series_data_3;
|
||||
option_1_1.series[4].data = res.series_data_4;
|
||||
myChart.setOption(option_1_1);
|
||||
window.addEventListener("resize", function () {
|
||||
myChart.resize();
|
||||
@@ -282,18 +280,12 @@ $(function () {
|
||||
$(this).siblings().removeClass("active");
|
||||
// 添加active类到当前点击的元素
|
||||
$(this).addClass("active");
|
||||
|
||||
// 获取当前选中的标签数据
|
||||
var selectedTab = $(this).data("tab");
|
||||
|
||||
// 这里可以添加根据标签切换内容的逻辑
|
||||
console.log("切换到: " + selectedTab);
|
||||
|
||||
// 示例:根据标签切换图表数据
|
||||
var selectedTab = $(this).data("tab");
|
||||
switch (selectedTab) {
|
||||
case "入园数":
|
||||
// 加载入园数数据
|
||||
echarts_1();
|
||||
echarts_1_1();
|
||||
break;
|
||||
case "在园数":
|
||||
echarts_3();
|
||||
|
5
static/js/jquery.js
vendored
5
static/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user