鸿蒙智能跳绳计数器开发指南 原创

进修的泡芙
发布于 2025-6-23 13:03
浏览
0收藏

鸿蒙智能跳绳计数器开发指南

一、系统架构设计

基于HarmonyOS的分布式能力和传感器框架,我们设计了一套智能跳绳计数器系统,主要功能包括:
IMU数据处理:高效处理加速度计和陀螺仪数据

动态屏幕刷新:根据运动状态调整显示频率

运动模式识别:识别不同跳绳模式(单摇、双摇等)

跨设备同步:多终端实时显示跳绳数据

运动数据分析:统计跳绳次数、频率和消耗卡路里

!https://example.com/harmony-jump-rope-arch.png

二、核心代码实现
IMU数据处理服务

// IMUService.ets
import sensor from ‘@ohos.sensor’;
import power from ‘@ohos.power’;

class IMUService {
private static instance: IMUService;
private accelData: sensor.AccelerometerResponse | null = null;
private gyroData: sensor.GyroscopeResponse | null = null;
private samplingRate: number = 50; // 默认50Hz采样率
private jumpCount: number = 0;
private lastJumpTime: number = 0;
private powerMode: power.Mode = power.Mode.NORMAL;

private constructor() {
this.initSensors();
this.initPowerListener();
private initSensors(): void {

try {
  // 初始化加速度计
  sensor.on(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, (data) => {
    this.handleAccelData(data);
  }, { interval: 1000 / this.samplingRate });
  
  // 初始化陀螺仪
  sensor.on(sensor.SensorType.SENSOR_TYPE_ID_GYROSCOPE, (data) => {
    this.handleGyroData(data);
  }, { interval: 1000 / this.samplingRate });

catch (error) {

  console.error('IMU sensor initialization failed:', error);

}

private initPowerListener(): void {
power.on(‘powerModeChange’, (mode) => {
this.powerMode = mode;
this.adjustSamplingRate();
});
private adjustSamplingRate(): void {

let newRate: number;

switch (this.powerMode) {
  case power.Mode.POWER_SAVE:
    newRate = 20; // 省电模式20Hz
    break;
  case power.Mode.PERFORMANCE:
    newRate = 100; // 高性能模式100Hz
    break;
  default:
    newRate = 50; // 普通模式50Hz

if (newRate !== this.samplingRate) {

  this.samplingRate = newRate;
  this.restartSensors();

}

private restartSensors(): void {
sensor.off(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER);
sensor.off(sensor.SensorType.SENSOR_TYPE_ID_GYROSCOPE);

this.initSensors();

private handleAccelData(data: sensor.AccelerometerResponse): void {

this.accelData = data;
this.detectJump();

private handleGyroData(data: sensor.GyroscopeResponse): void {

this.gyroData = data;

private detectJump(): void {

if (!this.accelData) return;

// 计算加速度矢量幅度
const magnitude = Math.sqrt(
  Math.pow(this.accelData.x, 2) +
  Math.pow(this.accelData.y, 2) +
  Math.pow(this.accelData.z, 2)
);

// 简单的阈值检测跳跃
if (magnitude > 15 && Date.now() - this.lastJumpTime > 200) {
  this.jumpCount++;
  this.lastJumpTime = Date.now();
  
  // 触发事件
  EventBus.emit('jumpDetected', {
    count: this.jumpCount,
    timestamp: this.lastJumpTime
  });

}

public static getInstance(): IMUService {
if (!IMUService.instance) {
IMUService.instance = new IMUService();
return IMUService.instance;

public getJumpCount(): number {

return this.jumpCount;

public resetCounter(): void {

this.jumpCount = 0;
this.lastJumpTime = 0;

public getCurrentRate(): number {

if (this.jumpCount < 2 || !this.lastJumpTime) return 0;

const now = Date.now();
const jumpsPerMinute = (this.jumpCount / (now - this.lastJumpTime)) * 60000;
return jumpsPerMinute;

public getIMUData(): { accel: sensor.AccelerometerResponse null, gyro: sensor.GyroscopeResponse
null } {

return {
  accel: this.accelData,
  gyro: this.gyroData
};

}

export const imuService = IMUService.getInstance();

动态屏幕刷新服务

// DisplayService.ets
import display from ‘@ohos.display’;
import power from ‘@ohos.power’;

class DisplayService {
private static instance: DisplayService;
private currentRefreshRate: number = 60; // 默认60Hz
private isActive: boolean = false;
private powerMode: power.Mode = power.Mode.NORMAL;
private lastUpdateTime: number = 0;

private constructor() {
this.initPowerListener();
private initPowerListener(): void {

power.on('powerModeChange', (mode) => {
  this.powerMode = mode;
  this.adjustRefreshRate();
});

public static getInstance(): DisplayService {

if (!DisplayService.instance) {
  DisplayService.instance = new DisplayService();

return DisplayService.instance;

public start(): void {

this.isActive = true;
this.adjustRefreshRate();

public stop(): void {

this.isActive = false;
this.setRefreshRate(60); // 恢复默认刷新率

public updateActivity(): void {

this.lastUpdateTime = Date.now();
this.adjustRefreshRate();

private adjustRefreshRate(): void {

if (!this.isActive) return;

let targetRate: number;

// 根据电源模式和活动状态决定刷新率
switch (this.powerMode) {
  case power.Mode.POWER_SAVE:
    targetRate = 30; // 省电模式30Hz
    break;
  case power.Mode.PERFORMANCE:
    targetRate = 90; // 高性能模式90Hz
    break;
  default:
    // 普通模式下根据活动调整
    const timeSinceLastUpdate = Date.now() - this.lastUpdateTime;
    targetRate = timeSinceLastUpdate < 1000 ? 60 : 45;

if (targetRate !== this.currentRefreshRate) {

  this.setRefreshRate(targetRate);

}

private setRefreshRate(rate: number): void {
try {
display.setDefaultDisplayRefreshRate(rate);
this.currentRefreshRate = rate;
catch (error) {

  console.error('Failed to set refresh rate:', error);

}

public getCurrentRefreshRate(): number {
return this.currentRefreshRate;
}

export const displayService = DisplayService.getInstance();

运动模式识别服务

// MotionRecognitionService.ets
import neuralNetwork from ‘@ohos.ai.neuralNetwork’;
import { imuService } from ‘./IMUService’;

class MotionRecognitionService {
private static instance: MotionRecognitionService;
private model: neuralNetwork.Model | null = null;
private currentMode: JumpMode = ‘single’;
private lastDetectionTime: number = 0;

private constructor() {
this.initModel();
this.initEventListeners();
private initModel(): void {

try {
  // 加载轻量级跳绳模式识别模型
  this.model = await neuralNetwork.loadModel({
    modelPath: 'models/jump_rope_pattern.nn',
    quantization: true
  });

catch (error) {

  console.error('Failed to load motion recognition model:', error);

}

private initEventListeners(): void {
EventBus.on(‘jumpDetected’, () => {
this.detectJumpPattern();
});
public static getInstance(): MotionRecognitionService {

if (!MotionRecognitionService.instance) {
  MotionRecognitionService.instance = new MotionRecognitionService();

return MotionRecognitionService.instance;

private async detectJumpPattern(): Promise<void> {

if (!this.model || Date.now() - this.lastDetectionTime < 1000) return;

try {
  const imuData = imuService.getIMUData();
  if (!imuData.accel || !imuData.gyro) return;
  
  // 准备输入数据
  const input: neuralNetwork.Tensor = {
    data: this.prepareInputData(imuData),
    shape: [1, 6, 10] // [批次, 特征数, 时间步]
  };
  
  // 运行模型
  const output = await this.model.run(input);
  
  // 解析输出
  this.currentMode = this.parseOutput(output);
  this.lastDetectionTime = Date.now();
  
  // 触发事件
  EventBus.emit('jumpModeChanged', this.currentMode);

catch (error) {

  console.error('Motion recognition failed:', error);

}

private prepareInputData(imuData: { accel: sensor.AccelerometerResponse, gyro: sensor.GyroscopeResponse }): number[] {
// 标准化传感器数据
return [
imuData.accel.x / 10, imuData.accel.y / 10, imuData.accel.z / 10,
imuData.gyro.x / 10, imuData.gyro.y / 10, imuData.gyro.z / 10
];
private parseOutput(output: neuralNetwork.Tensor): JumpMode {

const data = output.data as number[];
const modes: JumpMode[] = ['single', 'double', 'crisscross', 'sideSwing'];
const maxIndex = data.indexOf(Math.max(...data));
return modes[maxIndex] || 'single';

public getCurrentMode(): JumpMode {

return this.currentMode;

public getCaloriesBurned(): number {

// 简单计算卡路里消耗
const jumpCount = imuService.getJumpCount();
const modeFactor = this.getModeFactor();
return jumpCount  0.1  modeFactor;

private getModeFactor(): number {

switch (this.currentMode) {
  case 'single': return 1.0;
  case 'double': return 1.5;
  case 'crisscross': return 1.8;
  case 'sideSwing': return 1.3;
  default: return 1.0;

}

export const motionRecognition = MotionRecognitionService.getInstance();

跨设备同步服务

// SyncService.ets
import distributedData from ‘@ohos.data.distributedData’;
import deviceManager from ‘@ohos.distributedHardware.deviceManager’;

class SyncService {
private static instance: SyncService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;
private connectedDevices: string[] = [];

private constructor() {
this.initKVStore();
this.initDeviceListener();
private async initKVStore(): Promise<void> {

const config = {
  bundleName: 'com.example.jumprope',
  userInfo: { userId: 'default' }
};

this.kvManager = distributedData.createKVManager(config);
this.kvStore = await this.kvManager.getKVStore('jump_rope_sync', {
  createIfMissing: true,
  backup: false,
  autoSync: true,
  kvStoreType: distributedData.KVStoreType.SINGLE_VERSION
});

this.kvStore.on('dataChange', (data) => {
  this.handleRemoteData(data);
});

private initDeviceListener(): void {

deviceManager.on('deviceStateChange', (data) => {
  this.handleDeviceStateChange(data);
});

this.updateConnectedDevices();

private async updateConnectedDevices(): Promise<void> {

const devices = await deviceManager.getTrustedDeviceList();
this.connectedDevices = devices.map(d => d.deviceId);

private handleDeviceStateChange(data: deviceManager.DeviceStateChangeData): void {

if (data.deviceState === deviceManager.DeviceState.ONLINE) {
  if (!this.connectedDevices.includes(data.deviceId)) {
    this.connectedDevices.push(data.deviceId);

} else if (data.deviceState === deviceManager.DeviceState.OFFLINE) {

  this.connectedDevices = this.connectedDevices.filter(id => id !== data.deviceId);

}

public static getInstance(): SyncService {
if (!SyncService.instance) {
SyncService.instance = new SyncService();
return SyncService.instance;

public async syncJumpData(data: JumpData): Promise<void> {

const syncData: SyncJumpData = {
  ...data,
  deviceId: deviceManager.getLocalDevice().id,
  timestamp: Date.now()
};

await this.kvStore.put(jump_${Date.now()}, JSON.stringify(syncData));

public async syncJumpMode(mode: JumpMode): Promise<void> {

const syncData: SyncJumpMode = {
  mode,
  deviceId: deviceManager.getLocalDevice().id,
  timestamp: Date.now()
};

await this.kvStore.put(mode_${Date.now()}, JSON.stringify(syncData));

private handleRemoteData(data: distributedData.ChangeInfo): void {

if (data.deviceId === deviceManager.getLocalDevice().id) return;

try {
  const parsed = JSON.parse(data.value);
  
  if (data.key.startsWith('jump_')) {
    EventBus.emit('remoteJumpData', parsed);

else if (data.key.startsWith(‘mode_’)) {

    EventBus.emit('remoteJumpMode', parsed);

} catch (error) {

  console.error('Failed to parse sync data:', error);

}

public async getConnectedDevices(): Promise<string[]> {
await this.updateConnectedDevices();
return […this.connectedDevices];
public async broadcastCommand(command: JumpCommand): Promise<void> {

const syncCommand: SyncCommand = {
  type: 'command',
  command,
  timestamp: Date.now(),
  deviceId: deviceManager.getLocalDevice().id
};

await this.kvStore.put(command_${Date.now()}, JSON.stringify(syncCommand));

}

export const syncService = SyncService.getInstance();

三、主界面实现
跳绳计数主界面

// JumpRopeView.ets
@Component
struct JumpRopeView {
@State jumpCount: number = 0;
@State jumpRate: number = 0;
@State calories: number = 0;
@State jumpMode: JumpMode = ‘single’;
@State connectedDevices: number = 0;

aboutToAppear() {
this.initEventListeners();
this.loadInitialState();
build() {

Column() {
  // 计数显示
  Text(this.jumpCount.toString())
    .fontSize(48)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 32, bottom: 8 })
  
  // 跳绳模式
  Text(this.getModeText())
    .fontSize(18)
    .fontColor('#4A90E2')
    .margin({ bottom: 16 })
  
  // 统计信息
  Row() {
    Column() {
      Text(${this.jumpRate.toFixed(1)})
        .fontSize(24)
      Text('次/分钟')
        .fontSize(14)

.margin({ right: 32 })

    Column() {
      Text(${this.calories.toFixed(0)})
        .fontSize(24)
      Text('卡路里')
        .fontSize(14)

}

  .margin({ bottom: 32 })
  
  // 控制按钮
  Row() {
    Button('开始')
      .onClick(() => this.startJumping())
      .width(120)
    
    Button('重置')
      .onClick(() => this.resetCounter())
      .width(120)
      .margin({ left: 16 })

.margin({ bottom: 24 })

  // 设备连接状态
  if (this.connectedDevices > 0) {
    Text(${this.connectedDevices}设备连接中)
      .fontSize(14)
      .fontColor('#666666')

}

.width('100%')
.height('100%')

private initEventListeners(): void {

EventBus.on('jumpDetected', (data) => {
  this.jumpCount = data.count;
  this.jumpRate = imuService.getCurrentRate();
  this.calories = motionRecognition.getCaloriesBurned();
});

EventBus.on('jumpModeChanged', (mode) => {
  this.jumpMode = mode;
});

EventBus.on('remoteJumpData', (data) => {
  this.jumpCount = data.count;
  this.jumpRate = data.rate;
  this.calories = data.calories;
});

EventBus.on('remoteJumpMode', (data) => {
  this.jumpMode = data.mode;
});

private loadInitialState(): void {

this.connectedDevices = syncService.getConnectedDevices().length;

private getModeText(): string {

switch (this.jumpMode) {
  case 'single': return '单摇模式';
  case 'double': return '双摇模式';
  case 'crisscross': return '交叉跳';
  case 'sideSwing': return '侧摆跳';
  default: return '标准模式';

}

private startJumping(): void {
imuService.resetCounter();
displayService.start();
private resetCounter(): void {

imuService.resetCounter();
this.jumpCount = 0;
this.jumpRate = 0;
this.calories = 0;
displayService.stop();

}

运动数据分析界面

// StatsView.ets
@Component
struct StatsView {
@State history: JumpSession[] = [];
@State selectedSession: JumpSession | null = null;

aboutToAppear() {
this.loadHistory();
build() {

Column() {
  // 历史记录列表
  HistoryList({
    history: this.history,
    onSelect: (session) => this.selectSession(session)
  })
  .layoutWeight(1)
  
  // 选中会话详情
  if (this.selectedSession) {
    SessionDetail({ session: this.selectedSession })
      .margin({ top: 16 })

}

.padding(16)

private loadHistory(): void {

this.history = storageService.getJumpHistory();
if (this.history.length > 0) {
  this.selectedSession = this.history[0];

}

private selectSession(session: JumpSession): void {
this.selectedSession = session;
}

@Component
struct HistoryList {
private history: JumpSession[];
private onSelect: (session: JumpSession) => void;

build() {
List() {
ForEach(this.history, (session) => {
ListItem() {
HistoryItem({
session,
onClick: () => this.onSelect(session)
})
})

}

@Component

struct HistoryItem {
private session: JumpSession;
private onClick: () => void;

build() {
Row() {
Column() {
Text(this.formatDate(this.session.startTime))
.fontSize(16)
.fontWeight(FontWeight.Bold)

    Text({this.session.mode} • {this.session.count}次)
      .fontSize(14)
      .fontColor('#666666')

.layoutWeight(1)

  Text(${this.session.calories.toFixed(0)}卡)
    .fontSize(16)

.padding(12)

.backgroundColor('#FFFFFF')
.borderRadius(8)
.onClick(() => this.onClick())

private formatDate(timestamp: number): string {

const date = new Date(timestamp);
return {date.getMonth() + 1}月{date.getDate()}日 {date.getHours()}:{date.getMinutes().toString().padStart(2, '0')};

}

@Component
struct SessionDetail {
private session: JumpSession;

build() {
Column() {
// 会话概览
Row() {
Column() {
Text(‘总次数’)
.fontSize(14)
Text(this.session.count.toString())
.fontSize(24)
.margin({ right: 32 })

    Column() {
      Text('持续时间')
        .fontSize(14)
      Text(this.formatDuration(this.session.duration))
        .fontSize(24)

}

  .margin({ bottom: 16 })
  
  // 详细统计
  StatsChart({ session: this.session })
    .height(200)
    .margin({ bottom: 16 })
  
  // 模式分布
  Text('跳绳模式分布')
    .fontSize(16)
    .fontWeight(FontWeight.Bold)
    .margin({ bottom: 8 })
  
  ModeDistribution({ modes: this.session.modeChanges })

.padding(16)

.backgroundColor('#FFFFFF')
.borderRadius(8)

private formatDuration(ms: number): string {

const minutes = Math.floor(ms / 60000);
const seconds = Math.floor((ms % 60000) / 1000);
return {minutes}分{seconds.toString().padStart(2, '0')}秒;

}

四、高级功能实现
运动会话管理

// SessionService.ets
import { imuService } from ‘./IMUService’;
import { motionRecognition } from ‘./MotionRecognitionService’;

class SessionService {
private static instance: SessionService;
private currentSession: JumpSession | null = null;
private sessionHistory: JumpSession[] = [];

private constructor() {
this.loadHistory();
this.initEventListeners();
private loadHistory(): void {

this.sessionHistory = storageService.get('jumpSessions') || [];

private initEventListeners(): void {

EventBus.on('jumpDetected', () => {
  this.updateCurrentSession();
});

EventBus.on('jumpModeChanged', () => {
  this.recordModeChange();
});

public static getInstance(): SessionService {

if (!SessionService.instance) {
  SessionService.instance = new SessionService();

return SessionService.instance;

public startNewSession(): void {

this.currentSession = {
  id: generateId(),
  startTime: Date.now(),
  endTime: 0,
  count: 0,
  calories: 0,
  duration: 0,
  mode: 'single',
  modeChanges: [],
  peakRate: 0
};

imuService.resetCounter();

public endCurrentSession(): void {

if (!this.currentSession) return;

this.currentSession.endTime = Date.now();
this.currentSession.duration = this.currentSession.endTime - this.currentSession.startTime;

// 保存会话
this.sessionHistory.unshift(this.currentSession);
storageService.set('jumpSessions', this.sessionHistory);

this.currentSession = null;

private updateCurrentSession(): void {

if (!this.currentSession) return;

this.currentSession.count = imuService.getJumpCount();
this.currentSession.calories = motionRecognition.getCaloriesBurned();

const currentRate = imuService.getCurrentRate();
if (currentRate > this.currentSession.peakRate) {
  this.currentSession.peakRate = currentRate;

}

private recordModeChange(): void {
if (!this.currentSession) return;

const newMode = motionRecognition.getCurrentMode();
if (newMode !== this.currentSession.mode) {
  this.currentSession.modeChanges.push({
    mode: newMode,
    timestamp: Date.now() - this.currentSession.startTime
  });
  this.currentSession.mode = newMode;

}

public getCurrentSession(): JumpSession | null {
return this.currentSession;
public getSessionHistory(): JumpSession[] {

return [...this.sessionHistory];

public clearHistory(): void {

this.sessionHistory = [];
storageService.set('jumpSessions', []);

}

export const sessionService = SessionService.getInstance();

实时数据同步

// RealtimeSyncService.ets
import { syncService } from ‘./SyncService’;
import { imuService } from ‘./IMUService’;
import { motionRecognition } from ‘./MotionRecognitionService’;

class RealtimeSyncService {
private static instance: RealtimeSyncService;
private syncTimer: number | null = null;
private syncInterval: number = 1000; // 默认1秒同步一次

private constructor() {
this.initEventListeners();
private initEventListeners(): void {

EventBus.on('sessionStarted', () => {
  this.startSyncing();
});

EventBus.on('sessionEnded', () => {
  this.stopSyncing();
});

public static getInstance(): RealtimeSyncService {

if (!RealtimeSyncService.instance) {
  RealtimeSyncService.instance = new RealtimeSyncService();

return RealtimeSyncService.instance;

public startSyncing(): void {

if (this.syncTimer) return;

this.syncTimer = setInterval(() => {
  this.syncData();
}, this.syncInterval);

public stopSyncing(): void {

if (this.syncTimer) {
  clearInterval(this.syncTimer);
  this.syncTimer = null;

}

private syncData(): void {
const jumpData: JumpData = {
count: imuService.getJumpCount(),
rate: imuService.getCurrentRate(),
calories: motionRecognition.getCaloriesBurned(),
mode: motionRecognition.getCurrentMode(),
timestamp: Date.now()
};

syncService.syncJumpData(jumpData);
syncService.syncJumpMode(jumpData.mode);

public setSyncInterval(interval: number): void {

this.syncInterval = interval;

if (this.syncTimer) {
  this.stopSyncing();
  this.startSyncing();

}

export const realtimeSync = RealtimeSyncService.getInstance();

电源管理服务

// PowerManagementService.ets
import power from ‘@ohos.power’;
import { imuService } from ‘./IMUService’;
import { displayService } from ‘./DisplayService’;
import { motionRecognition } from ‘./MotionRecognitionService’;

class PowerManagementService {
private static instance: PowerManagementService;
private powerMode: power.Mode = power.Mode.NORMAL;
private isActive: boolean = false;

private constructor() {
this.initPowerListener();
private initPowerListener(): void {

power.on('powerModeChange', (mode) => {
  this.handlePowerModeChange(mode);
});

public static getInstance(): PowerManagementService {

if (!PowerManagementService.instance) {
  PowerManagementService.instance = new PowerManagementService();

return PowerManagementService.instance;

public setPowerMode(mode: string): void {

let powerMode: power.Mode;
switch (mode) {
  case 'power_save': powerMode = power.Mode.POWER_SAVE; break;
  case 'performance': powerMode = power.Mode.PERFORMANCE; break;
  default: powerMode = power.Mode.NORMAL;

power.setMode(powerMode);

private handlePowerModeChange(mode: power.Mode): void {

this.powerMode = mode;
this.adjustComponents();

public startActivity(): void {

this.isActive = true;
this.adjustComponents();

public endActivity(): void {

this.isActive = false;
this.adjustComponents();

private adjustComponents(): void {

if (!this.isActive) {
  // 非活动状态下最低功耗
  imuService.setSamplingRate(10);
  displayService.setRefreshRate(30);
  motionRecognition.setEnabled(false);
  return;

switch (this.powerMode) {

  case power.Mode.POWER_SAVE:
    imuService.setSamplingRate(20);
    displayService.setRefreshRate(45);
    motionRecognition.setEnabled(true);
    break;
  case power.Mode.PERFORMANCE:
    imuService.setSamplingRate(100);
    displayService.setRefreshRate(90);
    motionRecognition.setEnabled(true);
    break;
  default:
    imuService.setSamplingRate(50);
    displayService.setRefreshRate(60);
    motionRecognition.setEnabled(true);

}

public getCurrentMode(): power.Mode {
return this.powerMode;
public isDeviceActive(): boolean {

return this.isActive;

}

export const powerManagement = PowerManagementService.getInstance();

五、总结

本智能跳绳计数器系统实现了以下核心价值:
精确计数:IMU数据处理算法准确识别每次跳跃

智能识别:机器学习模型区分不同跳绳模式

动态优化:根据运动状态调整屏幕刷新率节省电量

多设备协同:实时同步数据到手机、平板等设备

数据分析:记录运动历史并提供详细统计

扩展方向:
增加心率监测集成

开发跳绳训练计划和目标设定

添加社交分享功能

支持更多跳绳花样模式识别

集成到健康管理生态系统

注意事项:
使用前需进行IMU校准

不同跳绳模式需要一定学习周期

省电模式可能影响计数精度

多设备同步需登录相同账号

首次使用建议进行教程学习

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐