Files
auto_control/web/common.py
T
butubb 3422b4f265 feat: 监控页按名称排序 + 按钮改「看屏 / 打开设备端 Agent」;设备名匹配补 USB 设备
用户反馈的三件事:

1) **监控页设备排序**改成按**名称**(A01/A02/…),没名字的排最后按地址。
   之前是 adb 返回的顺序,看着像按 IP 排,同型号多台时对不上号。
   排序放在 `/api/status`(后端),大屏页一并受益。

2) **操作按钮改名 + 换实现**:
   - 「截图」→「**看屏**」(行为不变,就是查看设备实时画面)
   - 「定位」→「**打开设备端 Agent**」:改成让设备上的 Agent 弹身份大字页
     (名称/IP/平台地址),替代原来"推 HTML 让设备浏览器打开定位页"那套
     (那套要设备装浏览器、页面还依赖设备能访问平台,backlog A1/A2 一直没修)
     * 新接口 `POST /api/agent/show-info {serial, close?}`;没装 Agent 时明确报出来
     * **先点亮屏幕 + 解除锁屏再拉起** —— 设备息屏时 am start 会把大字页开在锁屏后面,
       人看到的还是一片黑(实测踩过)
     * 平台地址取操作者当前访问地址;若是 localhost 则换成本机局域网地址
       (设备上显示 127.0.0.1 毫无意义)

3) **安装应用的选择设备界面仍显示裸序列号**:USB 设备在 adb 里的 serial 就是
   `ro.serialno`,等于池里那条网络记录的**指纹** —— 之前只按 serial 匹配,插着 USB
   时会冒出一个没名字的 `s8o7nrt8pbzhfadq`。现在按 serial 或指纹任一命中都取名称,
   三处(剪贴板注入 / 安装弹窗 / 安装进度表)统一。

顺带修掉几个自己踩出来的坑:
- `device_pool.list_configured()` 返回的是 **serial 字符串列表**,我当成字典用了
  (`.get("serial")` 抛异常被 except 吞掉 → 名字全空)→ 改用 `list_devices()`
- `web/device_agent_api.py` 用了 `PERM_DEVICES` 但没导入 → 服务直接起不来(502)
- Agent 自检里的版本号是写死的常量(升到 1.4 还显示 1.0)→ 改成读包信息
- `doc/API.md` 章节编号(插了一节没把后面整体下移,出现两个 §16)

验证:安装弹窗里 USB 那台现在显示「A07」(指纹匹配);监控页按钮为
「看屏 / 打开设备端 Agent」;对装/未装 Agent 的设备分别得到大字页 / 明确报错;
大字页实测显示 A07 + 192.168.20.250:18050 + Agent v1.4。
2026-09-13 17:18:30 +08:00

66 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""跨模块共享工具(web 层)。"""
from core import device_pool
from core.adb_helper import _adb
from core.logger import get_logger
_log = get_logger("web")
def _merged_device_list():
"""本地 adb(含 USB)+ 设备池的合并列表([{serial, name, state}])。
供维护终端/剪贴板注入/应用版本管理等设备选择场景共用。
状态:device/offline=本机 adb 实际状态;pool=设备池已配置但本机未连接。
name 来自设备池(平台给设备起的名字,如 A08)—— 界面上统一按「名称 · 地址」
显示,同型号多台时才分得清是哪一台;池里没有的设备 name 为空,界面回退显示地址。
"""
states = {}
out = _adb("devices")
for line in (out or "").splitlines()[1:]:
parts = line.split()
if len(parts) >= 2 and parts[0] and not parts[0].startswith("*"):
states[parts[0]] = parts[1]
# 注意用的是 list_devices()(**字典**,含 name/fingerprint);
# list_configured() 只返回 serial 字符串列表,别拿它当字典用(实测踩过:.get 抛异常
# 被 except 吞掉 → 名字全空)
names, fp_names = {}, {}
try:
for d in device_pool.list_devices():
if d.get("serial"):
names[d["serial"]] = d.get("name") or ""
# USB 设备在 adb 里的 serial 就是 ro.serialno,等于池里那条网络记录的
# **指纹** —— 插着 USB 时会以另一个 serial 出现,靠指纹才认得出是同一台,
# 否则界面上会冒出一个没名字的裸序列号(实测踩过)
if d.get("fingerprint"):
fp_names[d["fingerprint"]] = d.get("name") or ""
except Exception as e:
import logging
logging.getLogger("web").warning(f"读取设备名失败: {e}")
try:
for serial in device_pool.list_configured():
if serial not in states:
states[serial] = "pool"
except Exception:
pass
return [{"serial": s, "name": names.get(s) or fp_names.get(s) or "", "state": st}
for s, st in sorted(states.items())]
def _device_screen_state(serial):
"""设备屏幕状态:on/off/unknown(dumpsys power 只读查询)。
用 mWakefulness 判断(Asleep=熄屏):MIUI 的 dumpsys display 没有
mScreenState 字段,power 字段全机型存在。USB 设备查询失败返回 unknown。
"""
try:
if ":" not in serial:
return "unknown"
out = _adb("-s", serial, "shell", "dumpsys", "power") or ""
import re
m = re.search(r"mWakefulness=(\w+)", out)
if m:
return "off" if m.group(1).lower() == "asleep" else "on"
except Exception:
pass
return "unknown"