项目交接文档

FAAP/RTD 测试数据传输系统


一、系统整体架构

整个系统负责将无线基站生产测试数据从被测设备(DUT)实时采集并可靠传输到 RTD 云端中央数据库。

DUT(被测设备)         FaapProxy(中间代理)       PC客户端              MBS(消息缓冲服务)       RTD云端
运行FAAP测试软件         协议转换+转发             FaapProxyClient        本地缓冲+可靠投递        中央数据库
     │                      │                       │                      │                    │
     │  gRPC 一元调用        │  gRPC Server Stream    │  gRPC 一元调用        │  gRPC over HTTPS    │
     ├─────────────────────►├──────────────────────►├─────────────────────►├───────────────────►│
     │                      │                       │                      │                    │
     │  AddTestPoint        │  FaapProxyReturnMsg    │  AddTestPointData    │  AddTestPointData   │
     │  AddAuxiliaryData    │  (oneof 消息流)        │  InitiateTestSession │  120秒超时          │
     │  FinalizeSequence    │                       │  FinalizeTestSession │  失败则缓存重发      │

关键特点

  • DUT 边测边发,整条链路是实时流式的
  • FaapProxyClient → MBS 和 MBS → RTD 云端使用完全相同的 Proto 接口(MBS 是透明代理)
  • MBS 提供断网保护:本地 SQLite 缓存 + 自动重发

二、代码仓库说明

按数据流顺序排列:DUT → FaapProxy → PC 客户端 → MBS → RTD 云端

2.1 Raptor2.MS.FaapProxy(FaapProxy 服务端)

位置powerMeter/Raptor2.MS.FaapProxy/Source/
中间代理服务,接收 DUT 数据并通过 gRPC Server Streaming 推送给 PC 客户端。

Source/
├── Program.cs                          ← 入口
├── Startup.cs                          ← 服务启动配置
├── appsettings.json                    ← 配置
├── Services/
│   ├── FaapProxy.cs                    ← ★ 核心:队列 → gRPC 流推送给 PC(InitializeTestAsync)
│   ├── DutTestDataMessageProxy.cs      ← V0:接收 DUT 测试数据(AddTestPointMessage 等)
│   ├── DutTestDataServiceV1.cs         ← V1:接收 DUT 测试数据(AddTestPoint + 校验 + 版本兼容)
│   ├── ControlService.cs / V1          ← 测试流程控制
│   ├── SampleBasedTestServiceV1.cs     ← SBT 采样测试
│   ├── DownloadFileServiceV1.cs        ← DUT 文件下载
│   ├── DutCtrlServiceProxyV1.cs        ← DUT 控制代理
│   ├── PsuServiceV1.cs                 ← 电源控制
│   ├── RxPwrServiceV1.cs              ← 接收功率测量
│   └── ... (40+ 其他服务代理)
├── Clients/                            ← gRPC 客户端(连接 DUT)
├── SupportComponents/
│   └── FaapProxyCache.cs               ← DUT IP → 缓存项(SessionId、FilterAttributes等)
├── Interface/                          ← 接口定义
└── Extensions/                         ← 扩展方法

2.2 FaapProxyClient(PC 客户端)

位置FaapProxyClient/Source/
WinForms 应用,接收 FaapProxy 推送的测试数据,转发到 MBS。

Source/
├── Program.cs                          ← 入口,DI 注册,gRPC 客户端配置
├── FaapProxyReturnMessageHandler.cs    ← 核心:接收消息流 + 分发处理 + RTD转发
├── DataConversion.cs                   ← 数据解析(DataPoint → 可读字符串)
├── MainForm.cs                         ← WinForms UI
├── Handlers/
│   ├── ServiceHandler.cs               ← 服务发现(查 MBS 地址)
│   └── PsuHandler.cs                   ← PSU 电源处理
├── Services/
│   └── SampleBaseTestService.cs        ← SBT 采样测试服务
├── SupportComponents/
│   ├── SettingsForm.cs                 ← 设置界面
│   └── FactoryCodeHelper.cs            ← 工厂代码帮助类
├── Models/                             ← 数据模型
└── appsettings.json                    ← 客户端配置

2.3 Raptor2.RTDMessageBufferService(MBS)

位置Raptor2.RTDMessageBufferService/Source/
消息缓冲服务,负责数据从 PC 客户端到 RTD 云端的可靠传输。

Source/
├── Program.cs                          ← 入口,配置 DI、gRPC 服务注册
├── Startup.cs                          ← 服务启动配置
├── appsettings.json                    ← 端点配置(地址、开关、缓存策略)
├── Services/
│   ├── TestResultMessageServiceImplV1.cs    ← 接收 PC gRPC 调用(入口)
│   ├── RTDMessageHandlingService.cs         ← 并发转发到云端(步骤 2)
│   ├── CacheMessageHandlingService.cs       ← 缓存消息重发(断网恢复后)
│   ├── CacheMessagePersistenceService.cs    ← 失败消息持久化到 SQLite
│   ├── CleaningService.cs                   ← 过期数据自动清理(8小时)
│   ├── HeaderMessageHandlingService.cs      ← V0 Header 处理
│   ├── FooterMessageHandlingService.cs      ← V0 Footer 处理
│   ├── TestPointMessageHandlingService.cs   ← V0 TestPoint 处理
│   ├── AuxiliaryDataMessageHandlingService.cs ← V0 Auxiliary 处理
│   ├── V1/
│   │   ├── TestPointMessageHandlingServiceV1.cs   ← V1 TestPoint(数据增强+持久化)
│   │   ├── AuxiliaryDataMessageHandlingServiceV1.cs ← V1 Auxiliary
│   │   └── FooterMessageHandlingServiceV1.cs      ← V1 Footer
│   ├── Configuration/                       ← 动态配置相关
│   ├── CalibrationData/                     ← 校准数据服务
│   ├── TestEquipmentLog/                    ← 测试设备日志
│   └── Opentelemetry/                       ← 可观测性(指标/链路追踪/日志)
├── Helper/
│   ├── GRpcClientCall.cs                    ← gRPC 调用封装(路由+实际调用)
│   ├── EndPointOptions.cs                   ← 端点配置模型
│   ├── Configuration/                       ← MBSConfigurationHistory 动态配置
│   ├── DBContextHelper.cs                   ← SQLite 重试帮助类
│   ├── MessageIndicator.cs                  ← 消息计数/seqid 管理
│   ├── RTDMessageConverter.cs               ← V0/V1 消息转换
│   ├── ProductFamilyHelper.cs               ← 产品族推断
│   └── TptagDuplicationHandler.cs           ← 重复测试点处理
├── MessageChannel/                          ← Channel 管道接口和实现
├── DBModels/                                ← SQLite 数据模型(EF Core)
└── RTD2MI/                                  ← RTD 到 MI 的兼容层

2.4 Proto 接口定义(共享契约)

位置production/(独立 git 仓库)
所有组件共享的 Proto 接口契约,不可随意修改。

production/
├── protos/                              ← V0 版本(扁平结构)
│   ├── service_db_result.proto          ← V0 测试结果服务
│   ├── service_db_logging.proto         ← 日志服务
│   ├── calibration_data.proto           ← 校准数据
│   └── ...
├── src/proto/production/                ← V1 版本(分层结构)
│   ├── db/result/v1/
│   │   └── service_db_result.proto      ← ★ V1 测试结果服务(MBS→云端核心)
│   ├── db/result_query/v1/              ← 结果查询
│   ├── db/calibration_data/v1/          ← 校准数据
│   ├── db/test_equipment_log/v1/        ← 测试设备日志
│   ├── dut/result/v1/
│   │   └── result_service.proto         ← ★ DUT → FaapProxy 接口
│   ├── test/data/v1/
│   │   └── data.proto                   ← ★ 数据消息定义(TestPointDataMessage等)
│   └── util/                            ← 通用类型(SessionId、Data等)
└── third_party/                         ← 第三方 proto(google/rpc 等)

2.5 tcpe_proto(Proto NuGet 包源码)

位置powerMeter/tcpe_proto/Source/
C# 项目引用的 Proto 接口包的源码,包含 FaapProxy 的 proto 定义和 RTD 接口抽象。

tcpe_proto/Source/
├── Protos/
│   └── MeasurementServices/
│       ├── Services/
│       │   └── service_ms_faap_proxy.proto  ← FaapProxy gRPC 服务定义
│       └── Messages/
│           └── faap_proxy.proto             ← FaapProxyReturnMessage、InitializeTestRequest 等
├── TestData/
│   └── Interfaces/
│       ├── ITestDataResultV1.cs             ← V1 RTD 接口(PC 调用 MBS 的抽象)
│       └── ITestDataResult.cs               ← V0 RTD 接口
└── ...

2.6 Python gRPC 模拟环境

位置python_grpc/strict_pipeline/
用 Python 模拟整条链路,方便独立测试(不需要实际 DUT 和硬件):

strict_pipeline/
├── dut_client.py           ← 模拟 DUT 发送测试数据
├── faap_proxy_server.py    ← 模拟 FaapProxy 代理
├── pc_client.py            ← 模拟 PC 客户端
└── rtd_mbs_server.py       ← 模拟 MBS 接收

三、第一段链路:DUT → FaapProxy(中间代理)

3.1 通信方式

DUT(被测设备)通过 gRPC 一元调用(Unary RPC)逐条发送测试数据到 FaapProxy。
Proto 定义production/src/proto/production/dut/result/v1/result_service.proto

RPC 方法 作用
AddTestPoint 发送一个测试点数据(测量值 + Pass/Fail + 限值)
AddAuxiliaryData 发送辅助数据(温度/电压/电流等)
AddDataPointGroup 发送数据点分组
GetSeqIds 批量预取序列号(V1 新增)

3.2 FaapProxy 收到数据后做什么

  1. 通过 DUT IP 查缓存 — 从 context.Peer 获取 DUT 的 IP 地址,查找对应的缓存项(SessionId、FilterAttributes、DutPosition 等)
  2. 补充 FilterAttributes — 工厂代码、产品族等信息从缓存获取,附加到消息上
  3. V1 校验 SessionId — V1 版本增加了 SessionId 非空校验,为空返回 InvalidArgument
  4. 版本兼容处理 — 根据 PC 客户端声明的 SupportedMessages,决定发 V1 格式还是降级为 V0
  5. 写入消息队列 — 按 DutPosition 隔离的 Channel 队列(生产者-消费者模式)

3.3 关键设计

  • DUT 边测边发,不是测完才传,整条链路实时流式
  • FaapProxy 本质是透传代理,不做业务层面的数据校验
  • 按 DutPosition 隔离队列,支持多 DUT 并行测试
  • 用 DUT IP 作为缓存 key,缓存会话信息供后续 RPC 使用

四、第二段链路:FaapProxy → PC 客户端(FaapProxyClient)

4.1 通信方式

PC 客户端通过 gRPC Server Streaming(服务端流式)持续接收 FaapProxy 推送的数据。
Proto 定义powerMeter/tcpe_proto/Source/Protos/MeasurementServices/Services/service_ms_faap_proxy.proto

RPC 方法 类型 作用
InitializeTestAsync Server Streaming PC 发起调用,FaapProxy 持续推送消息流
ReleaseResources Unary 释放锁定的资源
GetSampleTestResults Unary 获取 SBT 采样测试结果汇总

4.2 建立连接流程

PC 客户端调用 InitializeTestAsync 时发送 InitializeTestRequest,包含:

  • SessionId(序列号 + UTC 时间戳)
  • DUT IP、产品号、R-State
  • FilterAttributes(工厂代码 + 产品族)
  • FilesToDownload(最多 4 个数据库文件的字节内容)
  • SupportedMessages(声明客户端能处理哪些消息类型)
  • TestCategory、PowerCoupling、ExecutionMode 等
    FaapProxy 收到后:
  1. 缓存 DUT 信息(IP、SessionId、支持的消息类型等)
  2. 发送 FaapProxyServerStarted 通知
  3. 进入持续推送循环 — 从队列读取消息,通过 gRPC 流写给 PC

4.3 推送的消息类型(FaapProxyReturnMessage,oneof)

字段 消息类型 说明
test_point TestPointDataMessage (V0) 旧版测试点数据
test_point_v1 TestPointDataMessage (V1) 新版测试点数据
auxiliary AuxiliaryDataMessage (V0) 旧版辅助数据
auxiliary_v1 AuxiliaryDataMessage (V1) 新版辅助数据
data_point_group DataPointGroupMessage (V0) 旧版数据点组
data_point_group_v1 DataPointGroupMessage (V1) 新版数据点组
sequence_finalized TerminateTest 测试序列完成
runtime_error ClientRuntimeError 运行时错误
faap_still_alive FaapStillAlive 心跳/看门狗
faap_proxy_server_started FaapProxyServerStarted 服务端就绪通知

4.4 PC 客户端收到消息后做什么

收到消息 → 按 MsgCase 分发:
  ├── TestPoint/TestPointV1 → 解析数据 → 控制台输出(Pass绿/Fail红)→ 写本地文件 → 可选转发到 MBS
  ├── Auxiliary/AuxiliaryV1 → 解析数据 → 控制台输出 → 可选转发到 MBS
  ├── DataPointGroup/V1    → 日志记录 → 可选转发到 MBS
  ├── SequenceFinalized    → 计数器 → 可选自动结束会话
  ├── RuntimeError         → 仅日志
  └── FaapStillAlive/ServerStarted → 仅日志

4.5 关键设计

  • 底层基于 HTTP/2 长连接,服务端有数据就推,PC 端实时收到,无轮询
  • PC 客户端用异步队列System.Threading.Channels)解耦数据接收和 RTD 转发
  • 主线程收消息放队列(不阻塞),后台 Task 从队列消费并转发到 MBS
  • 会话遵循 Header → Data Stream → Footer 三段式协议

五、第三段链路:PC 客户端 → MBS(本地 gRPC 调用)

5.1 通信方式

PC 客户端通过 gRPC 一元调用发送到本地 MBS(localhost:58766),使用的接口和 MBS → 云端完全相同。
Proto 定义production/src/proto/production/db/result/v1/service_db_result.proto(同一套)

5.2 调用时序

测试开始 → InitiateTestSession(发送 HeaderMessage)
测试进行 → AddTestPointData / AddAuxiliaryData / AddDataPointGroup(从队列逐条消费)
测试结束 → FinalizeTestSession(发送 FooterMessage,先等队列排空最多 10 秒)

5.3 服务发现

PC 客户端不硬编码 MBS 端口,而是通过 ServiceManager 动态查询 "TestResultMessageService" 的实际运行地址。

5.4 重试策略

  • 最多重试 5 次
  • 指数退避:1s → 1.5s → 2.25s → 3.375s → 5s(最大)
  • 仅对 StatusCode.Unavailable 重试

六、第四段链路:MBS 内部处理 + 转发到 RTD 云端(三步)

6.1 MBS 接收入口

TestResultMessageServiceImplV1 接收 PC 客户端的 gRPC 调用,将消息写入对应的 Channel:

PC 调用的 RPC MBS 写入的 Channel
InitiateTestSession _initiateTestSessionChannel
AddTestPointData _testPointDataChannel
AddAuxiliaryData _auxiliaryDataChannel
AddDataPointGroup _dataPointGroupChannel
FinalizeTestSession _footerChannel

6.2 三步转发流程

步骤 1: TestPointMessageHandlingServiceV1(数据增强 + 持久化)
        - 从输入 Channel 读取
        - 补充 seqid、Duration、FilterAttributes、Repetition、Property、Tcnr
        - 持久化到本地 SQLite(断网保护)
        - 包装为 Request 写入输出 Channel
                        ↓
步骤 2: RTDMessageHandlingService(并发转发)
        - 从输出 Channel 读取,最多 20 并发发送
        - 为每个请求创建 DI Scope(资源隔离)
        - 调用 GRpcClientCall.PerformGRpcCall
        - 失败 → 序列化为 byte[] → 写入缓存 Channel
                        ↓
步骤 3: GRpcClientCall(实际 gRPC 调用)
        - 根据消息类型查字典找到对应处理函数
        - GetTransportConfigurationPerSession 获取端点配置 + headers
        - 遍历所有启用的端点
        - 用 GrpcClientFactory 创建 gRPC Stub
        - 调用云端 RPC(带 120 秒超时 + 自定义 headers)
        - 返回状态码:0=成功,非0=失败
                        ↓
RTD 云端 (https://apigw.radiounits-realtimetestdata.ericsson.net:9443)

6.3 失败重发路径

步骤 2 发送失败
  → sendtoCache = true
  → 序列化为 RTDMessage(messageType, byte[])
  → 写入 CacheRTDMessageChannel
                        ↓
CacheMessagePersistenceService(后台服务)
  → 从缓存 Channel 读取
  → 持久化到 SQLite 的 rtd_messages 表
                        ↓
SQLite(本地持久化)
                        ↓ (网络恢复后)
CacheMessageHandlingService(后台服务)
  → 定期扫描 SQLite 中未发送的消息
  → 反序列化 byte[] → protobuf 对象
  → 调用 GRpcClientCall.PerformGRpcCall(byte[] 版本)
  → 成功后从 SQLite 删除
                        ↓
RTD 云端 → 成功

6.4 GRpcClientCall 两个重载

PerformGRpcCall(string, IMessage, sp) PerformGRpcCall(string, byte[], sp)
输入 protobuf 对象(活对象) byte[] 字节(从 SQLite 读出)
谁调用 RTDMessageHandlingService(实时) CacheMessageHandlingService(重发)
反序列化 不需要,直接 as 强转 需要 Parser.ParseFrom(bytes)
端点过滤 检查 Enabled 检查 CacheEnabled

七、关键配置

7.1 MBS 端点配置(appsettings.json)

文件Raptor2.RTDMessageBufferService/Source/appsettings.json

{
  "EndPointInfos": [
    {
      "Enabled": true,              // 是否启用
      "CacheEnabled": true,         // 失败是否缓存重发
      "EndPointName": "TestDataV1Endpoint",
      "gRpcClient": "Proto.Production.Db.Result.V1.TestResultMessageService.TestResultMessageServiceClient",
      "Url": "https://apigw.radiounits-realtimetestdata.ericsson.net:9443"
    }
  ]
}

7.2 重要地址

地址 用途 状态
https://apigw.radiounits-realtimetestdata.ericsson.net:9443 RTD 生产环境 启用
https://apigw-dev.radiounits-realtimetestdata.ericsson.net:9443 RTD 开发环境 注释掉
http://rtd-u.kroto075.rnd.gic.ericsson.se:31103 沙箱环境 Enabled=false
http://kroto075.rnd.gic.ericsson.se:4317 OpenTelemetry 收集器 启用
localhost:58766 MBS 本地 gRPC 监听端口

7.3 关键参数

  • gRPC 调用超时:120 秒
  • 并发发送上限:20 路
  • 客户端重试策略:5 次,指数退避 1s→5s,仅 Unavailable 状态码
  • 过期数据清理:8 小时
  • SQLite 模式:WAL(高并发写入不阻塞)

八、云端 gRPC 接口(Proto 定义)

MBS 调用 RTD 云端的核心 RPC(定义在 service_db_result.proto V1):

RPC 方法 作用 调用时机
InitiateTestSession 开始测试会话 测试开始时发一次
AddTestPointData 发送测试点数据 每个测试点发一次
AddAuxiliaryData 发送辅助数据 有辅助数据时发
AddDataPointGroup 发送数据点组 批量数据时发
FinalizeTestSession 结束测试会话 测试结束时发一次
每个 RPC 的返回都是 google.rpc.Status:Code=0 成功,非0 失败。

九、GRpcClientCall.cs 两个重载的区别(补充)

PerformGRpcCall(string, IMessage, sp) PerformGRpcCall(string, byte[], sp)
输入 protobuf 对象(活对象) byte[] 字节数组(从数据库读出)
谁调用 RTDMessageHandlingService(实时发送) CacheMessageHandlingService(缓存重发)
反序列化 不需要 内部 Parser.ParseFrom(bytes)
端点过滤 检查 endPoint.Enabled 检查 endPoint.CacheEnabled

十、各后台服务职责速查

服务 职责
TestResultMessageServiceImplV1 接收 PC 的 gRPC 调用,写入对应 Channel
TestPointMessageHandlingServiceV1 从 Channel 读取 → 数据增强 → SQLite 持久化 → 写入输出 Channel
AuxiliaryDataMessageHandlingServiceV1 同上,处理辅助数据
FooterMessageHandlingServiceV1 同上,处理 Footer
RTDMessageHandlingService 从输出 Channel 读取 → 20 并发转发到云端 → 失败写缓存
CacheMessagePersistenceService 从缓存 Channel 读取 → 持久化到 SQLite
CacheMessageHandlingService 定期扫描 SQLite 未发送消息 → 反序列化 → 重新发送
CleaningService 定期清理超过 8 小时的过期会话数据
LocalMessagePersistenceService 本地消息存储管理

十一、FaapProxyClient 数据处理流程

11.1 会话生命周期

启动 → 服务发现(查 MBS 地址)→ 建立 gRPC 连接
  → 发送 RTD Header(InitiateTestSession)
  → 发起 Server Streaming 调用(InitializeTestAsync)
  → 持续接收消息流 → 按类型分发处理 → 可选转发到 MBS
  → 测试结束 → 发送 RTD Footer(FinalizeTestSession)

11.2 数据的三个输出去向

  1. 控制台:始终输出,Pass 绿色 / Fail 红色
  2. 本地文件:JSON 序列化 + TXT 追加
  3. RTD 云端:通过异步队列 → MBS 本地代理 → 云端

11.3 RTD 转发机制

主线程收到消息 → 写入 _rtdMessageQueue(不阻塞)→ 后台 Task 消费 → 调用 ITestDataResultV1 的对应方法 → MBS 接收

十二、常见问题排查

问题 1:数据没发到云端

排查步骤:

  1. 检查 MBS 进程是否在运行(Ericsson.Raptor2.RTDMessageBufferService
  2. 检查 appsettings.json 中对应端点的 Enabled 是否为 true
  3. 检查网络是否能访问 apigw.radiounits-realtimetestdata.ericsson.net:9443
  4. 查看 MBS 日志,搜索 "status code" 或 "exception"
  5. 检查 SQLite 缓存中是否有堆积的未发送消息

问题 2:数据发了但云端查不到

排查步骤:

  1. 确认 Header 中的 FilterAttributes 非空(产品族、工厂代码)
  2. 确认没有 "NOT_INTENDED_FOR_RTD" 标记
  3. 检查是否发了 Footer(FinalizeTestSession),云端可能要等 Footer 才可查询
  4. 确认 SessionId 格式正确(序列号 + UTC 时间戳)

问题 3:MBS 日志报 gRPC 超时

可能原因:

  • 网络不稳定或 VPN 问题
  • 云端负载高导致响应慢
  • 当前超时设置为 120 秒,如果一直超时说明网络有问题
  • 失败的消息会自动缓存,网络恢复后自动重发,不会丢

问题 4:切换到沙箱环境测试

修改 appsettings.json

  • 把生产端点的 Enabled 设为 false
  • 把沙箱端点(TestDataEndpointSandbox)的 Enabled 设为 true
  • 或直接修改 Url 字段指向沙箱地址

十三、开发环境信息

  • IDE:Visual Studio / VS Code
  • 语言:C# (.NET 6+)
  • 构建dotnet build
  • 解决方案文件
    • MBS: Raptor2.RTDMessageBufferService/Source/Ericsson.Raptor2.RTDMessageBufferService.sln
    • PC Client: FaapProxyClient/Source/FaapProxyClient.sln
  • NuGet 源:见各项目的 nuget.config
  • Proto 编译:Proto 文件由 NuGet 包提供编译后的 C# 代码,不需要本地 protoc 编译
  • 部署路径(测试站):C:\TestStation\Raptor2RTDMessageBufferService\

十四、相关文档索引

文档 内容
MBS到RTD_三步链路代码详解.md MBS 内部三步转发的详细代码分析
MBS到RTD云端_完整流程图.md 完整的架构图和流程图
FAAP_Report_数据处理流程学习汇报.md DUT → FaapProxy → PC 的完整数据流分析
FaapProxyClient到RTD数据传输详解.md PC 客户端到 RTD 的两跳传输详解
工作总结_求职简历参考.md 个人工作总结(非交接用)

十五、注意事项

  1. Proto 文件不要随意修改 — 它是多方共享的接口契约,修改需要协调 DUT 端、FaapProxy、PC 客户端、MBS、RTD 云端等多方
  2. appsettings.json 改完注意重启 MBS — 虽然有动态配置(MBSConfigurationHistory),但端点配置的变更通常需要重启
  3. SQLite 数据库文件 — 在 ./temp/testrtd.db,如果磁盘满了可以手动清理
  4. V0 和 V1 同时存在 — 系统同时支持旧版(V0)和新版(V1)协议,新开发优先用 V1
  5. Python 模拟环境python_grpc/strict_pipeline/ 可以不连实际设备,独立模拟测试整条链路
posted @ 2026-06-05 16:33  mo686  阅读(0)  评论(0)    收藏  举报