v3.1 + 批次0: 智能回复重构基线 - ApprovalMatcher + 关键词降级 + 文档速修 + v4.0任务书面化

This commit is contained in:
Simon
2026-07-17 23:08:59 +08:00
parent 5a77a89ab1
commit 3ed86d5fb3
181 changed files with 19738 additions and 2655 deletions
+129 -3
View File
@@ -53,14 +53,22 @@ class ITHealthService:
Returns:
Dict: 包含 current_device / other_devices / data_source / health_score
"""
# 尝试从联软获取真实设备信息
# 尝试从联软获取真实设备信息(总部员工优先)
device_info = await self._get_device_from_lianruan(employee_id)
# 联软不可用 → 尝试从火绒获取设备信息(分公司员工兜底)
if device_info is None:
# 联软不可用 → 返回 Mock 数据
device_info = await self._get_device_from_huorong(employee_id)
# 火绒不可用 → 尝试从设备清单数据库查询
if device_info is None:
device_info = await self._get_device_from_inventory(employee_id)
if device_info is None:
# 联软/火绒/设备清单都不可用 → 返回 Mock 数据
return self._get_mock_data(employee_id)
# 联软数据可用,尝试从火绒获取安全状态
# 已有设备信息,尝试从火绒获取安全状态
security_info = await self._get_security_from_huorong(
device_info.get("device_name", "")
)
@@ -170,6 +178,124 @@ class ITHealthService:
logger.warning(f"联软获取设备信息失败: {e}")
return None
async def _get_device_from_inventory(self, employee_id: str) -> Optional[Dict[str, Any]]:
"""从设备清单数据库查询设备信息(联软/火绒不可用时的兜底方案)。
匹配逻辑:
1. employee_account = employee_id(员工企微账号)
2. employee_name = employee_id(员工姓名)
3. computer_name 包含 employee_id
Args:
employee_id: 员工企微 UserID 或姓名
Returns:
Dict: 设备信息字典,未匹配时返回 None
"""
try:
# 直接用 SQL 查询
result = await self.db.fetch("""
SELECT computer_name, ip_address, mac_address,
employee_account, employee_name, asset_tag, department, source
FROM device_inventory
WHERE employee_account = $1
OR employee_name LIKE $2
OR computer_name ILIKE $3
LIMIT 1
""", employee_id, f"%{employee_id}%", f"%{employee_id}%")
if not result:
logger.info(f"设备清单中未找到员工 {employee_id} 的设备")
return None
row = result[0]
logger.info(f"从设备清单找到员工 {employee_id} 的设备: {row['computer_name']}")
return {
"device_name": row["computer_name"],
"ip_address": row["ip_address"],
"mac_address": row["mac_address"],
"employee_account": row["employee_account"],
"employee_name": row["employee_name"],
"asset_tag": row["asset_tag"],
"department": row["department"],
"source": row["source"],
}
except Exception as e:
logger.warning(f"从设备清单查询失败: {e}")
return None
async def _get_device_from_huorong(self, employee_id: str) -> Optional[Dict[str, Any]]:
"""从火绒查终端设备信息(联软不可用时的兜底方案)。
通过以下方式匹配员工设备:
1. 计算机名匹配:员工账号作为 strusername 查询
2. IP 匹配:查询所有终端,匹配员工当前 IP
Args:
employee_id: 员工账号
Returns:
Dict: 设备信息字典,火绒不可用时返回 None
"""
try:
from app.integrations.huorong.config import get_huorong_client
client = await get_huorong_client(self.db)
if not client:
logger.warning("火绒客户端未配置")
return None
# 方式1:尝试用员工账号匹配计算机名
# 火绒终端的 computer_name 通常是 hostname
result = await client.list_terminals(per_page=200)
terminals = result.get("items", [])
matched_terminal = None
# 优先尝试精确匹配:计算机名包含员工账号
for t in terminals:
if t.computer_name and employee_id.lower() in t.computer_name.lower():
matched_terminal = t
logger.info(f"火绒精确匹配: {t.computer_name} (employee={employee_id})")
break
# 如果没有精确匹配,返回第一个在线终端(兜底策略)
if not matched_terminal:
for t in terminals:
if t.is_online:
matched_terminal = t
logger.info(f"火绒兜底匹配: {t.computer_name} (employee={employee_id}, 在线终端)")
break
if not matched_terminal:
logger.info(f"火绒未找到任何终端")
return None
# 获取终端详细信息
detail = await client.get_terminal_detail(matched_terminal.client_id)
# 构建设备信息字典
device = {
"device_name": matched_terminal.computer_name or "",
"is_online": matched_terminal.is_online,
"ip_address": matched_terminal.local_ip or "",
"mac": getattr(matched_terminal, "mac", "") or "",
"os": detail.os_name or "",
"location": "",
"department": "",
"uptime": "",
"last_online_time": "",
}
logger.info(f"火绒获取设备成功: {matched_terminal.computer_name} (employee={employee_id})")
return device
except Exception as e:
logger.warning(f"火绒获取设备信息失败: {e}")
return None
async def _get_other_devices(
self, employee_id: str, exclude_device: str
) -> List[Dict[str, Any]]: