This commit is contained in:
HuangHai
2026-01-12 21:33:21 +08:00
parent 2051cb61c2
commit 4612ee2d81
18 changed files with 457 additions and 191 deletions

View File

@@ -36,6 +36,25 @@ class XinDianTuService:
def get_hash(self, s: str) -> str:
return hashlib.md5(s.encode('utf-8')).hexdigest()
def _to_float(self, value) -> float:
"""
从字符串中提取浮点数,过滤掉非数字字符
"""
if value is None:
return 0.0
if isinstance(value, (int, float)):
return float(value)
import re
try:
# 提取第一个匹配的数字部分(包含小数点)
match = re.search(r"[-+]?\d*\.?\d+", str(value))
if match:
return float(match.group())
return 0.0
except:
return 0.0
async def init_db(self):
await self.db.init_db()
@@ -129,12 +148,7 @@ class XinDianTuService:
})
price_str = station.get("price", "")
current_price = None
try:
price_match = re.search(r"\d+\.\d+", str(price_str))
if price_match:
current_price = float(price_match.group())
except: pass
current_price = self._to_float(price_str)
await self.station_status_model.save(
session=session,
@@ -193,32 +207,47 @@ class XinDianTuService:
# 2. 保存 Status (解析价格和电桩)
status_id = self.generate_id()
piles_str = station.get("piles", "0/0")
# 处理 piles 字段 (由 VL 返回的列表结构)
piles_data = station.get("piles")
total, free = 0, 0
standardized_piles = []
if "/" in piles_str:
if isinstance(piles_data, list):
for idx, p in enumerate(piles_data):
try:
t = int(p.get("total", 0))
f = int(p.get("free", 0))
total += t
free += f
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": p.get("type", "未知"),
"power": "",
"status_text": f"空闲{f}/总{t}",
"remark": "列表页VL"
})
except:
pass
elif isinstance(piles_data, str) and "/" in piles_data:
# 兼容旧格式或意外返回的字符串格式
try:
parts = piles_str.split("/")
free = int(parts[0])
total = int(parts[1])
parts = piles_data.split("/")
free = int(re.search(r"\d+", parts[0]).group())
total = int(re.search(r"\d+", parts[1]).group())
standardized_piles.append({
"pile_no": "G1",
"type": "未知",
"power": "",
"status_text": f"空闲{free}/总{total}",
"remark": "列表页VL"
"remark": "列表页VL(兼容)"
})
except:
pass
price_str = station.get("price", "")
current_price = None
try:
price_match = re.search(r"\d+\.\d+", str(price_str))
if price_match:
current_price = float(price_match.group())
except: pass
current_price = self._to_float(price_str)
await self.station_status_model.save(
session=session,
@@ -299,20 +328,10 @@ class XinDianTuService:
continue
price = station.get("price")
current_price = None
if price is not None and price != "":
try:
current_price = float(price)
except (ValueError, TypeError):
current_price = None
current_price = self._to_float(price) if price is not None and price != "" else None
pro_price_val = station.get("pro_price")
pro_price = None
if pro_price_val is not None and pro_price_val != "":
try:
pro_price = float(pro_price_val)
except (ValueError, TypeError):
pro_price = None
pro_price = self._to_float(pro_price_val) if pro_price_val is not None and pro_price_val != "" else None
await self.station_status_model.save(
session=session,
@@ -414,44 +433,64 @@ class XinDianTuService:
# 2. 保存 Status
status_id = self.generate_id()
# 解析电桩数量 (支持多组,如 "快:2/10 慢:1/5")
piles_str = station_info.get("piles", "")
# 解析电桩数量 (支持由 VL 返回的列表或字符串)
piles_data = station_info.get("piles", [])
total, free = 0, 0
standardized_piles = []
# 尝试匹配 "快:2/10" 或 "2/10" 这种格式
# 模式 1: 有类型,如 "快:2/10"
matches_with_type = re.findall(r"(\w+):(\d+)/(\d+)", piles_str)
if matches_with_type:
for idx, (p_type, f, t) in enumerate(matches_with_type):
f_int, t_int = int(f), int(t)
free += f_int
total += t_int
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": p_type,
"power": "",
"status_text": f"空闲{f_int}/总{t_int}",
"remark": "列表页VL"
})
else:
# 模式 2: 无类型,仅 "2/10"
matches_simple = re.findall(r"(\d+)/(\d+)", piles_str)
for idx, (f, t) in enumerate(matches_simple):
f_int, t_int = int(f), int(t)
free += f_int
total += t_int
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": "未知",
"power": "",
"status_text": f"空闲{f_int}/总{t_int}",
"remark": "列表页VL"
})
if isinstance(piles_data, list):
# 模式 1: VL 返回的结构化列表
for idx, p in enumerate(piles_data):
if isinstance(p, dict):
try:
t = int(p.get("total", 0))
f = int(p.get("free", 0))
total += t
free += f
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": p.get("type", "未知"),
"power": "",
"status_text": f"空闲{f}/总{t}",
"remark": "列表页VL"
})
except:
pass
elif isinstance(piles_data, str):
# 模式 2: 字符串格式 (兼容)
piles_str = piles_data
# 尝试匹配 "快:2/10" 或 "2/10" 这种格式
matches_with_type = re.findall(r"(\w+):(\d+)/(\d+)", piles_str)
if matches_with_type:
for idx, (p_type, f, t) in enumerate(matches_with_type):
f_int, t_int = int(f), int(t)
free += f_int
total += t_int
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": p_type,
"power": "",
"status_text": f"空闲{f_int}/总{t_int}",
"remark": "列表页VL(兼容)"
})
else:
# 模式 3: 无类型,仅 "2/10"
matches_simple = re.findall(r"(\d+)/(\d+)", piles_str)
for idx, (f, t) in enumerate(matches_simple):
f_int, t_int = int(f), int(t)
free += f_int
total += t_int
standardized_piles.append({
"pile_no": f"G{idx+1}",
"type": "未知",
"power": "",
"status_text": f"空闲{f_int}/总{t_int}",
"remark": "列表页VL(兼容)"
})
if not standardized_piles:
if not standardized_piles and isinstance(piles_data, str):
# 兜底匹配所有数字
nums = re.findall(r"(\d+)", piles_str)
nums = re.findall(r"(\d+)", piles_data)
if len(nums) >= 2:
free = int(nums[0])
total = int(nums[1])
@@ -463,17 +502,9 @@ class XinDianTuService:
"remark": "列表页VL兜底"
})
# 解析价格
# 解析价格
price_val = station_info.get("price")
current_price = None
if price_val:
try:
# 提取数字部分
price_match = re.search(r"(\d+(\.\d+)?)", str(price_val))
if price_match:
current_price = float(price_match.group(1))
except:
pass
current_price = self._to_float(price_val)
await self.station_status_model.save(
session=session,