AccessServer.py 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. from flask import Flask, request, jsonify
  2. import subprocess
  3. import csv
  4. import pymysql
  5. import mysql.connector
  6. import requests
  7. from datetime import datetime, timedelta
  8. import math
  9. import json
  10. import os
  11. import codecs
  12. import quopri
  13. from werkzeug.utils import secure_filename
  14. from email.header import decode_header
  15. app = Flask(__name__)
  16. SQServerHost = "http://111.4.141.191:18081"
  17. @app.after_request
  18. def add_header(response):
  19. response.headers['Access-Control-Allow-Origin'] = '*'
  20. response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
  21. return response
  22. # 定义数据模型类
  23. class SensorData:
  24. def __init__(self, sample_time, recv_time, node_name, node_value, node_type, node_unit, device_id, channel_id, project_id):
  25. self.sample_time = sample_time
  26. self.recv_time = recv_time
  27. self.node_name = node_name
  28. self.node_value = node_value
  29. self.node_type = node_type
  30. self.node_unit = node_unit
  31. self.device_id = device_id
  32. self.channel_id = channel_id
  33. self.project_id = project_id
  34. def __repr__(self): # 为了方便打印对象列表,定义一个简单的字符串表示方法
  35. return f"{self.sample_time} - {self.node_name}: {self.node_value}"
  36. def GetStartEndTime(deltaHour = 6):
  37. # 获取当前时间
  38. current_time = datetime.now()
  39. # 取整到最近的小时,即当前时间的小时数不变,分钟和秒数归零
  40. rounded_time = datetime(current_time.year, current_time.month, current_time.day, current_time.hour, 0, 0)
  41. # 往前推6个小时
  42. previous_time = rounded_time - timedelta(hours=deltaHour)
  43. # 输出两个时间
  44. return rounded_time.strftime('%Y-%m-%d %H:%M:%S'), previous_time.strftime('%Y-%m-%d %H:%M:%S')
  45. #return "2024-07-13 16:00:00", "2024-07-10 16:00:00"
  46. @app.route('/sync_from_access', methods=['POST'])
  47. def sync_from_access():
  48. sensor_data_list = []
  49. mdb_file = 'test.mdb'
  50. table_name = 'AcsData'
  51. output_file = 'output.csv'
  52. # 构建命令,确保提供可执行文件的完整路径
  53. cmd = ['mdb-export', mdb_file, table_name]
  54. # 执行命令并捕获输出
  55. try:
  56. result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, check=True)
  57. # 将结果写入输出文件
  58. with open(output_file, 'w', encoding='utf-8') as f:
  59. f.write(result.stdout)
  60. except subprocess.CalledProcessError as e:
  61. print(f"An error occurred: {e}")
  62. # 可以写入错误信息到文件或进行其他错误处理
  63. with open(output_file, 'w', encoding='utf-8') as f:
  64. f.write(e.stderr.decode('utf-8')) # 将stderr从字节解码为字符串
  65. # 建立MySQL连接
  66. conn = mysql.connector.connect(
  67. host="localhost",
  68. user="root",
  69. password="HelloWorld123",
  70. database="water"
  71. )
  72. # 设置MySQL连接的字符集
  73. conn.set_charset_collation('utf8')
  74. # 定义CSV文件和表格名称
  75. csv_file = 'output.csv'
  76. table_name = 'sensor_data'
  77. try:
  78. # 打开CSV文件进行读取
  79. with open(csv_file, mode='r', encoding='utf-8') as file:
  80. # 创建CSV阅读器
  81. reader = csv.reader(file)
  82. # 跳过第一行,因为它是标题行
  83. next(reader)
  84. # 创建游标对象
  85. cursor = conn.cursor()
  86. index = 0
  87. # 逐行插入数据
  88. for row in reader:
  89. print(index)
  90. index += 1
  91. # 将日期时间字符串转换为MySQL可接受的格式
  92. SampleTime = datetime.strptime(row[0], '%m/%d/%y %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')
  93. RecvTime = datetime.strptime(row[1], '%m/%d/%y %H:%M:%S').strftime('%Y-%m-%d %H:%M:%S')
  94. NodeName = row[2]
  95. NodeValue = float(row[3])
  96. if math.isnan(NodeValue):
  97. NodeValue = 0.0
  98. NodeType = row[4]
  99. NodeUnit = row[5]
  100. DeviceID = row[6]
  101. ChannelID = row[7]
  102. ProjectID = 0
  103. sensor_data_list.append(SensorData(SampleTime,RecvTime,NodeName,NodeValue,NodeType,NodeUnit,DeviceID,ChannelID,ProjectID))
  104. # 对列表进行排序,根据sample_time倒序排序
  105. sensor_data_list.sort(key=lambda x: x.recv_time, reverse=True)
  106. index = 0
  107. sensor_data_list_true = []
  108. for sd in sensor_data_list:
  109. index += 1
  110. sensor_data_list_true.append(sd)
  111. if index > 100:
  112. break
  113. for sd in sensor_data_list_true:
  114. # 检查数据库中是否已存在相同的记录
  115. check_sql = "SELECT COUNT(*) FROM {0} WHERE RecvTime=%s AND DeviceID=%s AND ChannelID=%s".format(table_name)
  116. cursor.execute(check_sql, (sd.recv_time, sd.device_id,sd.channel_id))
  117. exists = cursor.fetchone()[0]
  118. print(exists)
  119. # 如果数据库中不存在相同的记录,则插入数据
  120. if exists == 0:
  121. # 准备SQL语句,使用参数化查询
  122. sql = "INSERT INTO {0} (SampleTime, RecvTime, NodeName, NodeValue, NodeType, NodeUnit, DeviceID, ChannelID, ProjectID) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)".format(table_name)
  123. print(sql)
  124. # 执行插入操作,使用元组传递参数确保字符编码正确
  125. cursor.execute(sql, (sd.sample_time, sd.recv_time, sd.node_name, sd.node_value, sd.node_type, sd.node_unit, sd.device_id, sd.channel_id, sd.project_id))
  126. # 提交事务
  127. conn.commit()
  128. except mysql.connector.Error as e:
  129. return jsonify({"error": str(e)}), 500
  130. finally:
  131. if cursor:
  132. cursor.close()
  133. if conn:
  134. conn.close()
  135. return jsonify({"message": "Data synced successfully"}), 200
  136. @app.route('/get_last_data', methods=['POST'])
  137. def get_last_data():
  138. # 解析 JSON 请求数据
  139. data = request.get_json()
  140. ChannelID = data.get('ChannelID')
  141. DeviceID = data.get('DeviceID')
  142. n = data.get('N', 1) # 默认为1,如果请求中没有提供n,则取默认值
  143. if not ChannelID or not DeviceID:
  144. return jsonify({"error": "Missing ChannelID or DeviceID"}), 400
  145. # 建立MySQL连接
  146. conn = mysql.connector.connect(
  147. host="localhost",
  148. user="root",
  149. password="HelloWorld123",
  150. database="water"
  151. )
  152. # 设置MySQL连接的字符集
  153. conn.set_charset_collation('utf8')
  154. try:
  155. cursor = conn.cursor()
  156. # 编写 SQL 查询,以获取匹配 ChannelID 和 DeviceID 的最近的 n 条记录的全部数据
  157. query = """
  158. WITH Stats AS (
  159. SELECT
  160. MAX(NodeValue) AS MaxNodeValue,
  161. AVG(NodeValue) AS AvgNodeValue
  162. FROM sensor_data
  163. WHERE ChannelID=%s AND DeviceID=%s
  164. )
  165. SELECT
  166. sd.*,
  167. s.MaxNodeValue,
  168. s.AvgNodeValue
  169. FROM sensor_data sd
  170. CROSS JOIN Stats s
  171. WHERE sd.ChannelID=%s AND sd.DeviceID=%s
  172. ORDER BY sd.RecvTime DESC
  173. LIMIT %s;
  174. """
  175. cursor.execute(query, (ChannelID,DeviceID,ChannelID, DeviceID, n))
  176. results = cursor.fetchall()
  177. if results:
  178. # 将查询结果转换为列表的字典
  179. rows = [dict(zip([column[0] for column in cursor.description], row)) for row in results]
  180. jsonData = {}
  181. jsonData["datas"] = rows
  182. return jsonify(jsonData)
  183. else:
  184. return jsonify({"message": "No data found"}), 404
  185. except mysql.connector.Error as e:
  186. return jsonify({"error": str(e)}), 500
  187. finally:
  188. # 关闭游标和数据库连接
  189. if cursor:
  190. cursor.close()
  191. if conn:
  192. conn.close()
  193. @app.route('/get_data_by_avg', methods=['POST'])
  194. def get_data_by_avg():
  195. data = request.get_json()
  196. ChannelID = data.get('ChannelID')
  197. DeviceID = data.get('DeviceID')
  198. AvgType = data.get('AvgType')
  199. N = data.get('N', 6) # 默认为6小时,如果请求中没有提供hour,则取默认值
  200. if not ChannelID or not DeviceID or not AvgType:
  201. return jsonify({"error": "Missing ChannelID or DeviceID or AvgType"}), 400
  202. # 建立MySQL连接
  203. conn = mysql.connector.connect(
  204. host="localhost",
  205. user="root",
  206. password="HelloWorld123",
  207. database="water"
  208. )
  209. # 设置MySQL连接的字符集
  210. conn.set_charset_collation('utf8')
  211. try:
  212. cursor = conn.cursor()
  213. # 编写 SQL 查询,以获取匹配 ChannelID 和 DeviceID 的最近的 n 条记录的全部数据
  214. query = """
  215. SELECT * FROM sensor_data
  216. WHERE ChannelID=%s AND DeviceID=%s
  217. ORDER BY RecvTime DESC
  218. LIMIT %s
  219. """
  220. if AvgType == "hour":
  221. cursor.execute(query, (ChannelID, DeviceID, N * 3))
  222. elif AvgType == "day":
  223. cursor.execute(query, (ChannelID, DeviceID, N * 3 * 24))
  224. elif AvgType == "month":
  225. cursor.execute(query, (ChannelID, DeviceID, N * 3 * 24 * 7 * 31))
  226. else:
  227. return jsonify({"message": "AvgType type error!"}), 404
  228. results = cursor.fetchall()
  229. if not results:
  230. return jsonify({"message": "No data found"}), 404
  231. rows = [dict(zip([column[0] for column in cursor.description], row)) for row in results]
  232. # 按小时分组并计算每个小时的平均值
  233. avg_data = {}
  234. for data in rows:
  235. if AvgType == "hour":
  236. n_key = data["SampleTime"].strftime('%Y-%m-%d %H:00:00')
  237. elif AvgType == "day":
  238. n_key = data["SampleTime"].strftime('%Y-%m-%d')
  239. elif AvgType == "month":
  240. n_key = data["SampleTime"].strftime('%Y-%m')
  241. if n_key not in avg_data:
  242. avg_data[n_key] = {'total_value': 0, 'count': 0}
  243. avg_data[n_key]['total_value'] += float(data["NodeValue"])
  244. avg_data[n_key]['count'] += 1
  245. avg_data[n_key]['ChannelID'] = int(data["ChannelID"])
  246. avg_data[n_key]['DeviceID'] = int(data["DeviceID"])
  247. avg_data[n_key]['NodeName'] = str(data["NodeName"])
  248. avg_data[n_key]['NodeType'] = str(data["NodeType"])
  249. avg_data[n_key]['NodeUnit'] = str(data["NodeUnit"])
  250. avg_data[n_key]['ProjectID'] = int(data["ProjectID"])
  251. # 构建包含每个小时平均值的列表
  252. average_values = []
  253. for n_key in reversed(sorted(avg_data.keys())):
  254. average_values.append({
  255. 'SampleTime': n_key,
  256. 'RecvTime': n_key,
  257. "ProjectID" : avg_data[n_key]['ProjectID'],
  258. "NodeUnit" : avg_data[n_key]['NodeUnit'],
  259. "NodeName" : avg_data[n_key]['NodeName'],
  260. "NodeType" : avg_data[n_key]['NodeType'],
  261. "ChannelID" : avg_data[n_key]['ChannelID'],
  262. "DeviceID" : avg_data[n_key]['DeviceID'],
  263. 'NodeValue': avg_data[n_key]['total_value'] / avg_data[n_key]['count']
  264. })
  265. if len(average_values) >= N:
  266. break
  267. # 检查平均值列表长度是否等于hour,如果不足,用None填充
  268. average_values += [None] * (N - len(average_values))
  269. jsonData = {"datas": average_values}
  270. return jsonify(jsonData)
  271. except mysql.connector.Error as e:
  272. return jsonify({"error": str(e)}), 500
  273. finally:
  274. if cursor:
  275. cursor.close()
  276. if conn:
  277. conn.close()
  278. @app.route('/get_last_datas', methods=['POST'])
  279. def get_last_datas():
  280. # 解析 JSON 请求数据
  281. data = request.get_json()
  282. ids_list = data.get('idsList')
  283. if not ids_list or not isinstance(ids_list, list):
  284. return jsonify({"error": "Missing or invalid idsList parameter"}), 400
  285. # 存储结果的列表
  286. results = []
  287. # 建立MySQL连接
  288. conn = mysql.connector.connect(
  289. host="localhost",
  290. user="root",
  291. password="HelloWorld123",
  292. database="water"
  293. )
  294. if isinstance(conn, str):
  295. return jsonify({"error": conn}), 500
  296. try:
  297. cursor = conn.cursor()
  298. # 创建一个临时表来存储每个 (ChannelID, DeviceID) 的最大 id
  299. ids_temp_table_query = """
  300. CREATE TEMPORARY TABLE ids_temp AS
  301. SELECT MAX(id) as max_id
  302. FROM sensor_data
  303. WHERE (ChannelID, DeviceID) IN (%s)
  304. GROUP BY ChannelID, DeviceID
  305. """
  306. # 构建 (ChannelID, DeviceID) 的值
  307. channel_device_pairs = [(item['ChannelID'], item['DeviceID']) for item in ids_list if 'ChannelID' in item and 'DeviceID' in item]
  308. channel_device_pairs_str = ', '.join([f"({channel_id}, {device_id})" for channel_id, device_id in channel_device_pairs])
  309. # 执行创建临时表的查询
  310. cursor.execute(ids_temp_table_query % channel_device_pairs_str)
  311. # 使用临时表中的最大 id 来获取对应的完整记录
  312. final_query = """
  313. SELECT sd.*
  314. FROM sensor_data sd
  315. JOIN ids_temp it ON sd.id = it.max_id
  316. """
  317. # 执行最终的查询
  318. cursor.execute(final_query)
  319. results = cursor.fetchall()
  320. # 将查询结果转换为字典列表
  321. result_dicts = [dict(zip([column[0] for column in cursor.description], result)) for result in results]
  322. return jsonify(result_dicts)
  323. except mysql.connector.Error as e:
  324. return jsonify({"error": str(e)}), 500
  325. finally:
  326. # 关闭游标和数据库连接
  327. if cursor:
  328. cursor.close()
  329. if conn:
  330. conn.close()
  331. ######################################一张图接口#######################################
  332. @app.route('/get-water-management-projects', methods=['GET'])
  333. def get_water_management_projects():
  334. # 建立MySQL连接
  335. conn = mysql.connector.connect(
  336. host="localhost",
  337. user="root",
  338. password="HelloWorld123",
  339. database="water"
  340. )
  341. # 设置MySQL连接的字符集
  342. conn.set_charset_collation('utf8')
  343. try:
  344. cursor = conn.cursor()
  345. # 查询WaterManagementProjects表中的所有数据
  346. query = """
  347. SELECT * FROM WaterManagementProjects
  348. """
  349. cursor.execute(query)
  350. projects = cursor.fetchall()
  351. # 将查询结果转换为字典列表
  352. projects_json = []
  353. for project in projects:
  354. project_json = {
  355. 'id': project[0], # 项目ID
  356. 'special': bool(project[1]), # 将tinyint转换为布尔值
  357. 'type': project[2], # 项目类型
  358. 'longitude': project[3], # 经度
  359. 'latitude': project[4], # 纬度
  360. 'name': project[5], # 项目名称
  361. 'name_pri': project[6], # 项目主要名称
  362. 'text1': project[7], # 文本1
  363. 'text2': project[8] # 文本2
  364. }
  365. projects_json.append(project_json)
  366. # 返回JSON响应,包含msg, code和data
  367. response = {
  368. "msg": None,
  369. "code": 200,
  370. "data": projects_json
  371. }
  372. return jsonify(response), 200
  373. except mysql.connector.Error as e:
  374. # 捕获MySQL错误并返回错误信息和状态码 500
  375. response = {
  376. "msg": str(e),
  377. "code": 500,
  378. "data": []
  379. }
  380. return jsonify(response), 500
  381. finally:
  382. # 关闭数据库连接
  383. conn.close()
  384. @app.route('/get-project-milestones', methods=['GET'])
  385. def get_project_milestones():
  386. # 建立MySQL连接
  387. conn = mysql.connector.connect(
  388. host="localhost",
  389. user="root",
  390. password="HelloWorld123",
  391. database="water"
  392. )
  393. # 设置MySQL连接的字符集
  394. conn.set_charset_collation('utf8')
  395. try:
  396. cursor = conn.cursor()
  397. # 查询Project_milestones表中的所有数据
  398. query = """
  399. SELECT * FROM Project_milestones
  400. """
  401. cursor.execute(query)
  402. projects = cursor.fetchall()
  403. # 将查询结果转换为字典列表
  404. projects_json = []
  405. for project in projects:
  406. project_json = {
  407. 'id': project[0], # 项目ID
  408. 'year': project[1], # 年份
  409. 'date': project[2], # 日期
  410. 'title': project[3], # 标题
  411. 'pos': project[4], # 位置
  412. 'content': project[5], # 内容
  413. }
  414. projects_json.append(project_json)
  415. # 返回JSON响应,包含msg, code和data
  416. response = {
  417. "msg": None,
  418. "code": 200,
  419. "data": projects_json
  420. }
  421. return jsonify(response), 200
  422. except mysql.connector.Error as e:
  423. # 捕获MySQL错误并返回错误信息和状态码 500
  424. response = {
  425. "msg": str(e),
  426. "code": 500,
  427. "data": []
  428. }
  429. return jsonify(response), 500
  430. finally:
  431. # 关闭数据库连接
  432. conn.close()
  433. @app.route('/get-move-plans', methods=['GET'])
  434. def get_move_plans():
  435. # 建立MySQL连接
  436. conn = mysql.connector.connect(
  437. host="localhost",
  438. user="root",
  439. password="HelloWorld123",
  440. database="water"
  441. )
  442. # 设置MySQL连接的字符集
  443. conn.set_charset_collation('utf8')
  444. try:
  445. cursor = conn.cursor()
  446. # 查询Move_Plans表中的所有数据
  447. query = """
  448. SELECT * FROM Move_Plans
  449. """
  450. cursor.execute(query)
  451. plans = cursor.fetchall()
  452. # 将查询结果转换为字典列表
  453. plans_json = []
  454. for plan in plans:
  455. plan_json = {
  456. 'id': plan[0], # 自增主键ID
  457. 'isAfter': bool(plan[1]), # 将tinyint转换为布尔值
  458. 'isOut': bool(plan[2]), # 将tinyint转换为布尔值
  459. 'desc': plan[3],
  460. 'from': plan[4],
  461. 'to': plan[5],
  462. 'manNum': plan[6],
  463. 'homeNum': plan[7],
  464. 'completeNum': plan[8],
  465. 'dateTime': str(plan[9]),
  466. 'villageCount': plan[10],
  467. 'materialPrize': str(plan[11])
  468. }
  469. plans_json.append(plan_json)
  470. # 返回JSON响应,包含msg, code和data
  471. response = {
  472. "msg": None,
  473. "code": 200,
  474. "data": plans_json
  475. }
  476. return jsonify(response), 200
  477. except mysql.connector.Error as e:
  478. # 捕获MySQL错误并返回错误信息和状态码 500
  479. response = {
  480. "msg": str(e),
  481. "code": 500,
  482. "data": []
  483. }
  484. return jsonify(response), 500
  485. finally:
  486. # 关闭数据库连接
  487. conn.close()
  488. @app.route('/get-rkzy-base-data', methods=['GET'])
  489. def get_rkzy_base_data():
  490. # 建立MySQL连接
  491. conn = mysql.connector.connect(
  492. host="localhost",
  493. user="root",
  494. password="HelloWorld123",
  495. database="water"
  496. )
  497. # 设置MySQL连接的字符集
  498. conn.set_charset_collation('utf8')
  499. try:
  500. cursor = conn.cursor()
  501. # 查询Move_Plans表中的所有数据
  502. query = """
  503. SELECT * FROM SafetyZone
  504. """
  505. cursor.execute(query)
  506. plans = cursor.fetchall()
  507. # 将查询结果转换为字典列表
  508. plans_json = {}
  509. for plan in plans:
  510. plan_json = {
  511. 'population': plan[1],
  512. 'area': plan[2],
  513. 'capacity': plan[3]
  514. }
  515. plans_json = plan_json
  516. break
  517. # 返回JSON响应,包含msg, code和data
  518. response = {
  519. "msg": None,
  520. "code": 200,
  521. "data": plans_json
  522. }
  523. return jsonify(response), 200
  524. except mysql.connector.Error as e:
  525. # 捕获MySQL错误并返回错误信息和状态码 500
  526. response = {
  527. "msg": str(e),
  528. "code": 500,
  529. "data": []
  530. }
  531. return jsonify(response), 500
  532. finally:
  533. # 关闭数据库连接
  534. conn.close()
  535. @app.route('/get-swyj-base-data', methods=['GET'])
  536. def get_swyj_base_data():
  537. # 建立MySQL连接
  538. conn = mysql.connector.connect(
  539. host="localhost",
  540. user="root",
  541. password="HelloWorld123",
  542. database="water"
  543. )
  544. # 设置MySQL连接的字符集
  545. conn.set_charset_collation('utf8')
  546. try:
  547. cursor = conn.cursor()
  548. # 查询Move_Plans表中的所有数据
  549. query = """
  550. SELECT * FROM YangtzeRiverWaterLevels
  551. """
  552. cursor.execute(query)
  553. waterLevels = cursor.fetchall()
  554. # 将查询结果转换为字典列表
  555. waterLevel_jsons = []
  556. for level in waterLevels:
  557. waterLevel_json = {
  558. 'location': level[0],
  559. 'flood_protection_level': level[1],
  560. 'warning_level': level[2],
  561. 'guarantee_level':level[3]
  562. }
  563. waterLevel_jsons.append(waterLevel_json)
  564. # 返回JSON响应,包含msg, code和data
  565. response = {
  566. "msg": None,
  567. "code": 200,
  568. "data": waterLevel_jsons
  569. }
  570. return jsonify(response), 200
  571. except mysql.connector.Error as e:
  572. # 捕获MySQL错误并返回错误信息和状态码 500
  573. response = {
  574. "msg": str(e),
  575. "code": 500,
  576. "data": []
  577. }
  578. return jsonify(response), 500
  579. finally:
  580. # 关闭数据库连接
  581. conn.close()
  582. ######################天气相关接口###################################
  583. # 假设 qxData 是一个全局变量,在这里初始化它
  584. qxData = []
  585. #获取6小时内降雨数据
  586. @app.route('/get-six-hour-qx-data', methods=['GET'])
  587. def get_six_hour_qx_data():
  588. global qxData
  589. # 准备第一个 API 请求的数据和头部信息
  590. requestData = {
  591. "eqaddvcd": "421083",
  592. "pageSize": "80"
  593. }
  594. requestHead = {
  595. "token": "6C60F37D40B48DECF9A3F2CC1A5A50142C4BE52F26D15B171153F20DB63960696A439E435DDCA9AF925F13338470FFBDDC98CEE65AFBC92C2EB4E44C0A757DB5"
  596. }
  597. # 连接数据库
  598. conn = pymysql.connect(host='localhost', user='root', password='HelloWorld123', db='water', charset='utf8mb4')
  599. try:
  600. # 发送第一个请求以获取基本数据
  601. response = requests.post("{0}/shareddata/api/v1/baseinfo/stbprp/qx".format(SQServerHost), data=requestData, headers=requestHead)
  602. response.raise_for_status()
  603. jsonData = response.json()
  604. qxData = []
  605. # 初始化一个字典以将 STCD 映射到其在 qxData 中的索引
  606. qxDataDic = {}
  607. index = 0
  608. # 连接数据库并开始操作
  609. with conn.cursor() as cursor:
  610. for jsData in jsonData["data"]["list"]:
  611. if (114.115926000756 > jsData["LGTD"] and jsData["LGTD"] > 113.410714576698 and 30.2676753765206 > jsData["LTTD"] and jsData["LTTD"] > 29.8114499954776):
  612. qxData.append(jsData)
  613. qxDataDic[jsData["STCD"]] = index
  614. index += 1
  615. # 检查数据库中是否已有该记录
  616. cursor.execute("SELECT id FROM WaterHotPoints WHERE longitude=%s AND latitude=%s",
  617. (jsData["LGTD"], jsData["LTTD"]))
  618. result = cursor.fetchone()
  619. if result:
  620. pass
  621. else:
  622. # 如果记录不存在,执行插入操作
  623. cursor.execute("INSERT INTO WaterHotPoints (type, longitude, latitude, name, name_pri) VALUES (%s, %s, %s, %s, %s)",
  624. (1, jsData['LGTD'], jsData['LTTD'], jsData['STNM'], ""))
  625. conn.commit()
  626. # 准备第二个 API 请求的数据
  627. requestData = {}
  628. sts = ','.join([qx["STCD"] for qx in qxData])
  629. # 假设 GetStartEndTime 函数返回一个元组 (etm, stm)
  630. etm, stm = GetStartEndTime(6)
  631. requestData["sts"] = sts
  632. requestData["etm"] = etm
  633. requestData["stm"] = stm
  634. # 发送第二个请求以获取降雨数据
  635. response = requests.post("{0}/shareddata/api/v1/monitdata/pptn/qx".format(SQServerHost), data=requestData, headers=requestHead)
  636. response.raise_for_status()
  637. jsonData = response.json()
  638. # 初始化一个字典以存储六小时的降雨数据
  639. dropDic = {}
  640. for jd in jsonData['data']:
  641. if jd["STCD"] not in dropDic:
  642. dropDic[jd["STCD"]] = jd["DRP"]
  643. else:
  644. dropDic[jd["STCD"]] += jd["DRP"]
  645. # 更新 qxData 以包含降雨数据
  646. for key, value in dropDic.items():
  647. if key in qxDataDic:
  648. qxData[qxDataDic[key]]["dropSum6"] = value
  649. # 返回最终的 qxData 作为 JSON 响应
  650. response = {
  651. "msg": None,
  652. "code": 200,
  653. "data": qxData
  654. }
  655. return jsonify(response), 200
  656. except requests.RequestException as e:
  657. # 处理任何 HTTP 错误
  658. response = {
  659. "msg": str(e),
  660. "code": 500,
  661. "data": []
  662. }
  663. return jsonify(response), 500
  664. # 假设 swData 是一个全局变量,在这里初始化它
  665. swData = []
  666. @app.route('/get-six-hour-sw-data', methods=['GET'])
  667. def get_six_hour_sw_data():
  668. global swData
  669. swData = []
  670. # 准备第一个 API 请求的数据和头部信息
  671. requestData = {
  672. "eqaddvcd": "421083",
  673. "pageSize": "80"
  674. }
  675. requestHead = {
  676. "token": "6C60F37D40B48DECF9A3F2CC1A5A50142C4BE52F26D15B171153F20DB63960696A439E435DDCA9AF925F13338470FFBDDC98CEE65AFBC92C2EB4E44C0A757DB5"
  677. }
  678. # 连接数据库
  679. conn = pymysql.connect(host='localhost', user='root', password='HelloWorld123', db='water', charset='utf8mb4')
  680. try:
  681. # 发送第一个请求以获取基本数据
  682. response = requests.post("{0}/shareddata/api/v1/baseinfo/stbprp/sw".format(SQServerHost), data=requestData, headers=requestHead)
  683. response.raise_for_status()
  684. jsonData = response.json()
  685. # 初始化一个字典以将 STCD 映射到其在 swData 中的索引
  686. swDataDic = {}
  687. index = 0
  688. # 连接数据库并开始操作
  689. with conn.cursor() as cursor:
  690. for jsData in jsonData["data"]["list"]:
  691. if (114.115926000756 > jsData["LGTD"] and jsData["LGTD"] > 113.410714576698 and 30.2676753765206 > jsData["LTTD"] and jsData["LTTD"] > 29.8114499954776):
  692. swData.append(jsData)
  693. swDataDic[jsData["STCD"]] = index
  694. index += 1
  695. # 检查数据库中是否已有该记录
  696. cursor.execute("SELECT id FROM WaterHotPoints WHERE longitude=%s AND latitude=%s",
  697. (jsData["LGTD"], jsData["LTTD"]))
  698. result = cursor.fetchone()
  699. if result:
  700. pass
  701. else:
  702. # 如果记录不存在,执行插入操作
  703. cursor.execute("INSERT INTO WaterHotPoints (type, longitude, latitude, name, name_pri) VALUES (%s, %s, %s, %s, %s)",
  704. (2, jsData['LGTD'], jsData['LTTD'], jsData['STNM'], ""))
  705. conn.commit()
  706. # 准备第二个 API 请求的数据
  707. requestData = {}
  708. sts = ','.join([sw["STCD"] for sw in swData])
  709. # 假设 GetStartEndTime 函数返回一个元组 (etm, stm)
  710. etm, stm = GetStartEndTime(6)
  711. requestData["sts"] = sts
  712. requestData["etm"] = etm
  713. requestData["stm"] = stm
  714. # 发送第二个请求以获取降雨数据
  715. response = requests.post("{0}/shareddata/api/v1/monitdata/pptn/sw".format(SQServerHost), data=requestData, headers=requestHead)
  716. response.raise_for_status()
  717. jsonData = response.json()
  718. # 初始化字典以存储六小时的降雨数据和天气数据
  719. dropDic = {}
  720. wthDic = {}
  721. for jd in jsonData['data']:
  722. if jd["STCD"] not in dropDic:
  723. dropDic[jd["STCD"]] = jd["DRP"]
  724. else:
  725. dropDic[jd["STCD"]] += jd["DRP"]
  726. wthDic[jd["STCD"]] = jd["WTH"]
  727. # 更新 swData 以包含降雨和天气数据
  728. for key in dropDic.keys():
  729. if key in swDataDic:
  730. swData[swDataDic[key]]["dropSum6"] = dropDic[key]
  731. swData[swDataDic[key]]["wth"] = wthDic[key]
  732. # 使用列表推导过滤出包含 'dropSum6' 字段的字典
  733. filtered_swData = [item for item in swData if 'dropSum6' in item]
  734. # 更新全局变量 swData
  735. swData = filtered_swData
  736. # 返回最终的 swData 作为 JSON 响应
  737. response = {
  738. "msg": None,
  739. "code": 200,
  740. "data": swData
  741. }
  742. return jsonify(response), 200
  743. except requests.RequestException as e:
  744. # 处理任何 HTTP 错误
  745. response = {
  746. "msg": str(e),
  747. "code": 500,
  748. "data": []
  749. }
  750. return jsonify(response), 500
  751. swHeightData = []
  752. @app.route('/get-sw-height-data', methods=['GET'])
  753. def get_sw_height_data():
  754. global swHeightData
  755. swDataDic = {}
  756. swHeightData = []
  757. # 准备头部信息
  758. requestHead = {
  759. "token": "6C60F37D40B48DECF9A3F2CC1A5A50142C4BE52F26D15B171153F20DB63960696A439E435DDCA9AF925F13338470FFBDDC98CEE65AFBC92C2EB4E44C0A757DB5"
  760. }
  761. # 如果本地文件不存在,则从API获取数据并保存到本地文件
  762. if not os.path.exists("importZa.json"):
  763. requestData = {
  764. "pageSize": "10000"
  765. }
  766. response = requests.post("{0}/shareddata/api/v1/baseinfo/stbprp/sw".format(SQServerHost), data=requestData, headers=requestHead)
  767. response.raise_for_status()
  768. importZ = ["福田寺", "黄丝南", "下新河", "子贝渊", "沙螺"]
  769. jsonData = response.json()
  770. index = 0
  771. for jsData in jsonData["data"]["list"]:
  772. esixt = False
  773. for im in importZ:
  774. if im in jsData["STNM"]:
  775. esixt = True
  776. if esixt:
  777. swHeightData.append(jsData)
  778. swDataDic[jsData["STCD"]] = index
  779. index += 1
  780. # 保存到本地文件
  781. newJ = json.dumps(swHeightData, ensure_ascii=False)
  782. with codecs.open("importZa.json", "w+", encoding="utf-8") as nj:
  783. nj.write(newJ)
  784. else:
  785. # 如果本地文件存在,则从文件加载数据
  786. index = 0
  787. with codecs.open("importZa.json", "r", encoding="utf-8") as iz:
  788. izContent = json.loads(iz.read())
  789. for izc in izContent:
  790. swHeightData.append(izc)
  791. swDataDic[izc["STCD"]] = index
  792. index += 1
  793. # 准备第二个 API 请求的数据
  794. etm, stm = GetStartEndTime(0)
  795. requestData = {
  796. "pageSize": 300,
  797. "etm": etm,
  798. "stm": stm
  799. }
  800. # 发送第二个请求以获取水位数据
  801. response = requests.post("{0}/shareddata/api/v1/monitdata/rw/st_was_r".format(SQServerHost), data=requestData, headers=requestHead)
  802. response.raise_for_status()
  803. jsonData = response.json()
  804. # 初始化字典以存储水位数据
  805. dwzDic = {}
  806. upzDic = {}
  807. tgtqDic = {}
  808. for jd in jsonData['data']["list"]:
  809. dwzDic[jd["STCD"]] = -1 if jd["DWZ"] == None else jd["DWZ"]
  810. upzDic[jd["STCD"]] = -1 if jd["UPZ"] == None else jd["UPZ"]
  811. tgtqDic[jd["STCD"]] = -1 if jd["TGTQ"] == None else jd["TGTQ"]
  812. # 更新 swHeightData 以包含水位数据
  813. for key in dwzDic.keys():
  814. if key in swDataDic:
  815. swHeightData[swDataDic[key]]["dwz"] = dwzDic[key]
  816. swHeightData[swDataDic[key]]["upz"] = upzDic[key]
  817. swHeightData[swDataDic[key]]["tgtq"] = tgtqDic[key]
  818. # 使用列表推导过滤出包含 'dwz' 字段的字典
  819. filtered_swData = [item for item in swHeightData if 'dwz' in item]
  820. # 处理没有 'dwz' 数据的项
  821. sub_swData = [item for item in swHeightData if 'dwz' not in item]
  822. for ssw in sub_swData:
  823. ssw["dwz"] = -1
  824. ssw["upz"] = -1
  825. ssw["tgtq"] = -1
  826. filtered_swData.append(ssw)
  827. # 更新全局变量 swHeightData
  828. swHeightData = filtered_swData
  829. # 返回最终的 swHeightData 作为 JSON 响应
  830. response = {
  831. "msg": None,
  832. "code": 200,
  833. "data": swHeightData
  834. }
  835. return jsonify(response), 200
  836. # 配置文件上传的目录
  837. UPLOAD_FOLDER = 'uploads/images/'
  838. ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
  839. app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
  840. def allowed_file(filename):
  841. return '.' in filename and \
  842. filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
  843. def decode_mime(encoded_str):
  844. """解码MIME编码的字符串"""
  845. try:
  846. # 只处理以 `=?utf-8?Q?` 开头并以 `?=` 结尾的字符串
  847. if encoded_str.startswith("=?utf-8?Q?") and encoded_str.endswith("?="):
  848. encoded_str = encoded_str[10:-2]
  849. decoded_bytes = quopri.decodestring(encoded_str)
  850. decoded_str = decoded_bytes.decode('utf-8')
  851. return decoded_str
  852. else:
  853. return encoded_str
  854. except Exception as e:
  855. print(f"Error decoding MIME: {e}")
  856. return encoded_str
  857. @app.route('/upload', methods=['POST'])
  858. def upload_file():
  859. global UPLOAD_FOLDER
  860. # 创建上传目录
  861. if not os.path.exists(UPLOAD_FOLDER):
  862. os.makedirs(UPLOAD_FOLDER)
  863. # 检查是否有文件在请求中
  864. if 'file' not in request.files:
  865. return jsonify({'error': '没有文件部分'})
  866. file = request.files['file']
  867. # 如果用户没有选择文件,浏览器也会提交一个没有文件名的空部分
  868. if file.filename == '':
  869. return jsonify({'error': '没有选择文件'})
  870. # 解码文件名
  871. decoded_filename = decode_mime(file.filename)
  872. print(decoded_filename)
  873. if file and allowed_file(decoded_filename):
  874. filename = decoded_filename
  875. file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
  876. return jsonify({'message': '文件上传成功', 'filename': filename})
  877. return jsonify({'error': '不支持的文件类型'})
  878. if __name__ == '__main__':
  879. app.run(host='192.168.0.7',debug=True,port=15000)