HarmonyOS 鸿蒙Next中实名过程如何利用camera实现身份证拍摄能力?

HarmonyOS 鸿蒙Next中实名过程如何利用camera实现身份证拍摄能力? 实名过程需要上传身份证照片,我们期望利用当前的camera实现身份证拍摄能力。

3 回复

您可以参考以下demo修改调整:

import { camera } from '@kit.CameraKit'
import { BusinessError } from '@kit.BasicServicesKit'
import { image } from '@kit.ImageKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { abilityAccessCtrl, PermissionRequestResult, Permissions } from '@kit.AbilityKit'
import { display, promptAction } from '@kit.ArkUI'
import { fileIo } from '@kit.CoreFileKit'
import fs from '@ohos.file.fs'

const TAG = '[CustomCameraDemo]'

@Entry
@Component
export struct CustomCameraDemo {
  context: Context = getContext(this) as Context;
  @State pixelMap: image.PixelMap | undefined = undefined;
  @State finalPixelMap: image.PixelMap | undefined = undefined;
  @State buffer: ArrayBuffer | undefined = undefined;
  @State surfaceId: string = '';
  @State hasPicture: boolean = false;
  @State fileNames: string[] = [];
  @State imageSize: image.Size = { width: 1920, height: 1080 };
  @State saveButtonOptions: SaveButtonOptions = {
    icon: SaveIconStyle.FULL_FILLED,
    text: SaveDescription.SAVE_IMAGE,
    buttonType: ButtonType.Capsule
  };

  private mXComponentController: XComponentController = new XComponentController();
  private cameraManager: camera.CameraManager | undefined = undefined;
  private cameraSession: camera.PhotoSession | undefined = undefined;
  private photoOutput: camera.PhotoOutput | undefined = undefined;
  private cameraInput: camera.CameraInput | undefined = undefined;
  private previewOutput: camera.PreviewOutput | undefined = undefined;
  private previewOutput2: camera.PreviewOutput | undefined = undefined;
  private imageReceiver: image.ImageReceiver | undefined = undefined;
  @State ca: number = 0;
  @State screenWidth: number = 0;
  @State screenHeight: number = 0;

  aboutToAppear(): void {
    let permissions: Array<Permissions> = [
      'ohos.permission.CAMERA',
      'ohos.permission.WRITE_MEDIA',
      'ohos.permission.READ_MEDIA',
      'ohos.permission.MEDIA_LOCATION',
    ];
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    atManager.requestPermissionsFromUser(this.context, permissions).then((data: PermissionRequestResult) => {
      let grantStatus: Array<number> = data.authResults;
      let length: number = grantStatus.length;
      for (let i = 0; i < length; i++) {
        if (grantStatus[i] != 0) {
          return;
        }
      }
      console.info(`${TAG} Success to request permissions from user. authResults is ${grantStatus}.`);
    }).catch((err: BusinessError) => {
      console.error(`${TAG} Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
    });

    let displaydef = display.getDefaultDisplaySync();
    this.screenWidth = displaydef.width;
    this.screenHeight = displaydef.height;
  }

  createCameraManager() {
    let cameraManager: camera.CameraManager = camera.getCameraManager(this.context);
    if (!cameraManager) {
      console.error('CameraDemo camera.getCameraManager error');
      return;
    }
    this.cameraManager = cameraManager;

    this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
      console.info(`CameraDemo camera: ${cameraStatusInfo.camera.cameraId}, status: ${cameraStatusInfo.status}`);
    });
  }

  async onPageShow() {
    await this.prepareCamera(this.ca);
  }

  build() {
    Column() {
      Column({ space: 10 }) {
        if (this.hasPicture) {
          Image(this.finalPixelMap)
            .objectFit(ImageFit.Fill)
            .width('100%')
            .height(600);
          SaveButton(this.saveButtonOptions)
            .onClick(async (event, result: SaveButtonOnClickResult) => {
              if (result == SaveButtonOnClickResult.SUCCESS) {
                if (this.finalPixelMap) {
                  try {
                    let phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
                    let options: photoAccessHelper.CreateOptions = {
                      title: Date.now().toString()
                    };
                    let photoUri: string = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png', options);
                    console.info('CameraDemo createAsset successfully, photoUri: ' + photoUri);
                    let file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.WRITE_ONLY);
                    fileIo.writeSync(file.fd, this.buffer);
                    fileIo.closeSync(file);
                    promptAction.showToast({ message: `保存成功` });
                  } catch (error) {
                    let err = error as BusinessError;
                    console.error(`CameraDemo savePicture error: ${JSON.stringify(err)}`);
                    promptAction.showToast({ message: `保存失败` });
                  }
                }
              } else {
                console.error('CameraDemo SaveButtonOnClickResult createAsset failed.');
                promptAction.showToast({ message: `保存失败` });
              }
              setTimeout(() => {
                this.hasPicture = false;
                this.finalPixelMap = undefined;
              }, 1000);
            });
        } else {
          Row() {
            XComponent({
              id: '',
              type: 'surface',
              libraryname: '',
              controller: this.mXComponentController
            })
              .onLoad(() => {
                this.mXComponentController.setXComponentSurfaceRect({ offsetX: 0, offsetY: 0, surfaceWidth: this.screenHeight * 0.49, surfaceHeight: this.screenWidth * 0.49 * 1920 / 1080.0 });
                this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
                setTimeout(async () => {
                  await this.prepareCamera(this.ca);
                }, 500);
              })
              .width(px2vp(this.screenWidth * 0.49))
              .height(px2vp(this.screenWidth * 0.49 * 1920 / 1080.0));

            Image(this.pixelMap)
              .margin({ left: 5 })
              .width(px2vp(this.screenWidth * 0.49))
              .height(px2vp(this.screenWidth * 0.49 * 1920 / 1080.0));
          }

          Row() {
            Button('拍照').width(60).height(60).margin({ right: 10 }).borderRadius(30)
              .onClick(async () => {
                let photoCaptureSetting: camera.PhotoCaptureSetting = {
                  quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
                  rotation: camera.ImageRotation.ROTATION_0
                };
                await this.photoOutput?.capture(photoCaptureSetting).catch((error: BusinessError) => {
                  console.error(`CameraDemo Failed to capture the photo ${error.message}`);
                });
                this.hasPicture = true;
              });
          }

          Row() {
            Button('前置摄像头')
              .size({ width: 100, height: 30 }).margin({ right: 10 })
              .onClick(async () => {
                this.ca = 1;
                console.debug('打开前置摄像头');
                await this.prepareCamera(this.ca);
              });

            Button('后置摄像头')
              .size({ width: 100, height: 30 }).margin({ left: 10 })
              .onClick(async () => {
                this.ca = 0;
                console.debug('打开后置摄像头');
                await this.prepareCamera(this.ca);
              });
          }
        }
      }
      .width('100%')
      .height('100%')
      .padding(15)
      .borderRadius(8);
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF');
  }

  async prepareCamera(ca: Number) {
    this.releaseCamera();
    this.createCameraManager();
    if (!this.cameraManager) {
      console.error('CameraDemo cameraManager is undefined.');
      return;
    }

    let cameraDevices: Array<camera.CameraDevice> = [];
    let CameraDevice: camera.CameraDevice;
    try {
      cameraDevices = this.cameraManager.getSupportedCameras();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo The getSupportedCameras call failed. error: ${JSON.stringify(err)}`);
    }

    cameraDevices.forEach((cameraDevice: camera.CameraDevice) => {
      console.info(`CameraDemo cameraId: ${cameraDevice.cameraId}, cameraPosition: ${cameraDevice.cameraPosition.toString()}, cameraType: ${cameraDevice.cameraType.toString()}, connectionType: ${cameraDevice.connectionType.toString()}`);
    });

    try {
      CameraDevice = (ca == 0) ? cameraDevices[0] : cameraDevices[1];
      this.cameraInput = this.cameraManager.createCameraInput(CameraDevice);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`);
      return;
    }

    this.cameraInput.on('error', CameraDevice, (error: BusinessError) => {
      console.error(`CameraDemo Camera input error: ${JSON.stringify(error)}`);
    });

    try {
      await this.cameraInput.open();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo cameraInput open error. error: ${JSON.stringify(err)}`);
    }

    let cameraSceneModes: Array<camera.SceneMode> = [];
    try {
      cameraSceneModes = this.cameraManager.getSupportedSceneModes(CameraDevice);
      cameraSceneModes.forEach((cameraSceneMode: camera.SceneMode) => {
        console.info(`CameraDemo cameraSceneMode: ${cameraSceneMode.toString()}`);
      });
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo The getSupportedSceneModes call failed. error: ${JSON.stringify(err)}`);
    }

    let cameraOutputCapability: camera.CameraOutputCapability = this.cameraManager.getSupportedOutputCapability(CameraDevice, camera.SceneMode.NORMAL_PHOTO);
    if (!cameraOutputCapability) {
      console.error('CameraDemo cameraManager.getSupportedOutputCapability error');
      return;
    }

    this.printCameraOutputCapability(cameraOutputCapability);
    let previewProfile = cameraOutputCapability.previewProfiles[0];
    cameraOutputCapability.previewProfiles.forEach(profile => {
      if (profile.size.width == this.imageSize.width && profile.size.height == this.imageSize.height) {
        previewProfile = profile;
        return;
      }
    });
    this.imageSize = previewProfile.size;

    try {
      this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.surfaceId);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`);
      return;
    }

    this.previewOutput.on('error', (error: BusinessError) => {
      console.error(`CameraDemo previewOutput error: ${JSON.stringify(error)}`);
    });

    try {
      this.imageReceiver = image.createImageReceiver(this.imageSize, image.ImageFormat.JPEG, 8);
      let imageReceiverSurfaceId: string = await this.imageReceiver.getReceivingSurfaceId();
      this.previewOutput2 = this.cameraManager.createPreviewOutput(previewProfile, imageReceiverSurfaceId);
      this.onImageArrival(this.imageReceiver);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo createImageReceiver error ${JSON.stringify(err)}`);
      return;
    }

    try {
      let photoProfile = cameraOutputCapability.photoProfiles[0];
      cameraOutputCapability.photoProfiles.forEach(profile => {
        if (profile.size.width == this.imageSize.width && profile.size.height == this.imageSize.height) {
          photoProfile = profile;
          return;
        }
      });
      this.photoOutput = this.cameraManager.createPhotoOutput(photoProfile);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo createPhotoOutput error ${JSON.stringify(err)}`);
    }

    if (this.photoOutput === undefined) {
      console.error('CameraDemo photoOutput is undefined.');
      return;
    }

    this.setPhotoOutputCb(this.photoOutput);

    try {
      this.cameraSession = this.cameraManager.createSession<camera.PhotoSession>(camera.SceneMode.NORMAL_PHOTO);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`);
      return;
    }

    this.cameraSession.on('error', (error: BusinessError) => {
      console.error(`CameraDemo Capture session error: ${JSON.stringify(error)}`);
    });

    try {
      this.cameraSession.beginConfig();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo beginConfig error. error: ${JSON.stringify(err)}`);
    }

    try {
      this.cameraSession.addInput(this.cameraInput);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo addInput error. error: ${JSON.stringify(err)}`);
    }

    try {
      this.cameraSession.addOutput(this.previewOutput);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo add previewOutput error. error: ${JSON.stringify(err)}`);
    }

    try {
      this.cameraSession.addOutput(this.previewOutput2);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo add previewOutput2 error. error: ${JSON.stringify(err)}`);
    }

    try {
      this.cameraSession.addOutput(this.photoOutput);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo add photoOutput error. error: ${JSON.stringify(err)}`);
    }

    try {
      await this.cameraSession.commitConfig();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo captureSession commitConfig error: ${JSON.stringify(err)}`);
    }

    try {
      await this.cameraSession.start();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo captureSession start error: ${JSON.stringify(err)}`);
    }

    this.configuringSession(this.cameraSession);
  }

  configuringSession(photoSession: camera.PhotoSession): void {
    let flashStatus: boolean = false;
    try {
      flashStatus = photoSession.hasFlash();
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo Failed to hasFlash. error: ${JSON.stringify(err)}`);
    }
    console.info(`CameraDemo Returned with the flash light support status: ${flashStatus}`);

    if (flashStatus) {
      let flashModeStatus: boolean = false;
      try {
        let status: boolean = photoSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO);
        flashModeStatus = status;
      } catch (error) {
        let err = error as BusinessError;
        console.error(`CameraDemo Failed to check whether the flash mode is supported. error: ${JSON.stringify(err)}`);
      }
      if (flashModeStatus) {
        try {
          photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
        } catch (error) {
          let err = error as BusinessError;
          console.error(`CameraDemo Failed to set the flash mode. error: ${JSON.stringify(err)}`);
        }
      }
    }

    let focusModeStatus: boolean = false;
    try {
      let status: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
      focusModeStatus = status;
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo Failed to check whether the focus mode is supported. error: ${JSON.stringify(err)}`);
    }
    if (focusModeStatus) {
      try {
        photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
      } catch (error) {
        let err = error as BusinessError;
        console.error(`CameraDemo Failed to set the focus mode. error: ${JSON.stringify(err)}`);
      }
    }

    let zoomRatioRange: Array<number> = [];
    try {
      zoomRatioRange = photoSession.getZoomRatioRange();
      zoomRatioRange.forEach(index => {
        console.info(`zoomRatioRange 支持的焦距: [${index}]`);
      });
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo Failed to get the zoom ratio range. error: ${JSON.stringify(err)}`);
    }
    if (zoomRatioRange.length <= 0) {
      return;
    }

    try {
      photoSession.setZoomRatio(1);
    } catch (error) {
      let err = error as BusinessError;
      console.error(`CameraDemo Failed to set the zoom ratio value. error: ${JSON.stringify(err)}`);
    }
  }

  async onImageArrival(receiver: image.ImageReceiver): Promise<void> {
    receiver.on('imageArrival', () => {
      receiver.readNextImage(async (err, nextImage: image.Image) => {
        if (err || nextImage === undefined) {
          console.error(`CameraDemo imageArrival error, error is ${JSON.stringify(err)} or nextImage is undefined`);
          return;
        }
        nextImage.getComponent(image.ComponentType.JPEG, async (err, imgComponent: image.Component) => {
          if (err || imgComponent === undefined) {
            console.error(`CameraDemo getComponent error, error is ${JSON.stringify(err)} or imgComponent is undefined`);
            return;
          }
          if (imgComponent.byteBuffer as ArrayBuffer) {
            let sourceOptions: image.SourceOptions = {
              sourceDensity: 0,
              sourcePixelFormat: image.PixelMapFormat.NV21,
              sourceSize: this.imageSize
            };
            let imageSource: image.ImageSource = image.createImageSource(imgComponent.byteBuffer, sourceOptions);
            let opts: image.InitializationOptions = {
              editable: false,
              pixelFormat: image.PixelMapFormat.NV21,
              size: this.imageSize
            };
            let pixelMap = await imageSource.createPixelMap(opts);
            await pixelMap.rotate(270.0);
            this.pixelMap = pixelMap;
            await imageSource.release();
          } else {
            return;
          }
          nextImage.release();
        });
      });
    });
  }

  setPhotoOutputCb(photoOutput: camera.PhotoOutput) {
    photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
      console.info(`CameraDemo getPhoto start. err: ${JSON.stringify(errCode)}`);
      if (errCode || photo === undefined || photo.main === undefined) {
        console.error('CameraDemo getPhoto failed');
        return;
      }
      let imageObj = photo.main;
      imageObj.getComponent(image.ComponentType.JPEG, async (errCode: BusinessError, component: image.Component): Promise<void> => {
        console.info('CameraDemo getComponent start');
        if (errCode || component === undefined) {
          console.error('CameraDemo getComponent failed');
          return;
        }
        let buffer: ArrayBuffer;
        if (component.byteBuffer) {
          buffer = component.byteBuffer;
          this.buffer = buffer;
          let sourceOptions: image.SourceOptions = {
            sourceDensity: 0,
            sourcePixelFormat: image.PixelMapFormat.RGBA_8888,
            sourceSize: this.imageSize
          };
          let imageSource: image.ImageSource = image.createImageSource(buffer, sourceOptions);
          let opts: image.InitializationOptions = {
            editable: false,
            pixelFormat: image.PixelMapFormat.RGBA_8888,
            size: this.imageSize
          };
          let pixelMap = await imageSource.createPixelMap(opts);
          this.finalPixelMap = pixelMap;
        } else {
          console.error('CameraDemo byteBuffer is null');
          return;
        }
      });
    });
  }

  printCameraOutputCapability(cameraOutputCapability: camera.CameraOutputCapability) {
    let previewProfileArr: Array<camera.Profile> = cameraOutputCapability.previewProfiles;
    let photoProfileArr: Array<camera.Profile> = cameraOutputCapability.photoProfiles;
    let videoProfileArr: Array<camera.VideoProfile> = cameraOutputCapability.videoProfiles;
    let supportedMetadataObjectTypeArr: Array<camera.MetadataObjectType> = cameraOutputCapability.supportedMetadataObjectTypes;

    previewProfileArr.forEach((value: camera.Profile, index: number) => {
      console.info(`CameraDemo 支持的预览尺寸: [${value.size.width},${value.size.height}]`);
    });

    photoProfileArr.forEach((value: camera.Profile, index: number) => {
      console.info(`CameraDemo 支持的拍照尺寸: [${value.size.width},${value.size.height}]`);
    });

    videoProfileArr.forEach((value: camera.VideoProfile, index: number) => {
      console.info(`CameraDemo 支持的录像尺寸: [${value.size.width},${value.size.height}], 支持的帧率范围: [${value.frameRateRange.min},${value.frameRateRange.max}]`);
    });

    supportedMetadataObjectTypeArr.forEach((value: camera.MetadataObjectType, index: number) => {
      console.info(`CameraDemo 支持的metadata流类型: ${value}`);
    });
  }

  releaseCamera() {
    if (this.cameraInput) {
      this.cameraInput.close();
    }
    if (this.previewOutput) {
      this.previewOutput.release();
    }
    if (this.photoOutput) {
      this.photoOutput.release();
    }
    if (this.cameraSession) {
      this.cameraSession.release();
    }
  }

  async imageWriteAlbumExample(pixelMap?: image.PixelMap) {
    console.info('createAssetDemo');
    let context = getContext(this);
    let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE;
    let extension: string = 'jpg';
    let options: photoAccessHelper.CreateOptions = {
      title: 'testPhoto'
    };
    let uri = await phAccessHelper.createAsset(photoType, extension, options);

    try {
      if (pixelMap) {
        let file = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
        const imageBuffer = await this.packingPixelMap2Jpg(pixelMap as image.PixelMap);
        fs.writeSync(file.fd, imageBuffer);
        fs.closeSync(file.fd);
      }
      promptAction.showToast({ message: `保存成功` });
      promptAction.showToast({
        message: '已保存至相册',
        duration: 2500
      });
    } catch (err) {
      console.error("error is " + JSON.stringify(err));
      promptAction.showToast({
        message: '保存失败',
        duration: 2000
      });
    }
  }

  async packingPixelMap2Jpg(pixelMap: PixelMap): Promise<ArrayBuffer> {
    const imagePackerApi = image.createImagePacker();
    const packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 };
    let imageBuffer: ArrayBuffer = new ArrayBuffer(1);
    try {
      imageBuffer = await imagePackerApi.packing(pixelMap, packOpts);
    } catch (err) {
      console.error(`Invoke packingPixelMap2Jpg failed, err: ${JSON.stringify(err)}`);
    }
    return imageBuffer;
  }
}

更多关于HarmonyOS 鸿蒙Next中实名过程如何利用camera实现身份证拍摄能力?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,利用Camera实现身份证拍摄能力,可以通过调用系统提供的相机API来实现。

  1. 权限申请:首先需要在应用的配置文件中申请相机权限和存储权限,确保应用有权访问摄像头并保存拍摄的照片。

  2. 相机初始化:使用CameraKitCameraAbility类初始化相机实例,设置相机参数,如分辨率、对焦模式等,以适应身份证拍摄的需求。

  3. 预览界面:通过SurfaceViewTextureView创建相机预览界面,将相机捕获的图像实时显示在屏幕上,方便用户调整身份证的位置和角度。

  4. 拍摄照片:调用相机的takePicture方法,捕获当前帧的图像。可以设置回调函数,在照片拍摄完成后进行处理。

  5. 图像处理:对拍摄的照片进行裁剪、旋转、校正等处理,确保身份证图像清晰且符合要求。

  6. 保存与上传:将处理后的图像保存到本地存储或直接上传到服务器进行后续的实名认证处理。

通过以上步骤,可以在HarmonyOS鸿蒙Next中实现身份证拍摄能力,并确保图像质量符合实名认证的要求。

在HarmonyOS鸿蒙Next中,利用Camera实现身份证拍摄能力,可以通过以下步骤:

  1. 权限申请:在config.json中声明ohos.permission.CAMERA权限。

  2. 初始化相机:使用CameraKit API初始化相机,设置预览视图。

  3. 配置相机参数:调整分辨率、对焦模式等参数,确保身份证清晰拍摄。

  4. 图像捕获:调用capture方法捕获图像,并保存为文件。

  5. 图像处理:使用Image API对捕获的图像进行裁剪、旋转等处理,提取身份证区域。

  6. OCR识别:集成OCR SDK(如华为云OCR服务)识别身份证信息。

  7. 数据验证:对识别结果进行校验,确保信息准确无误。

通过这些步骤,可以在鸿蒙Next中实现身份证拍摄与识别功能。

回到顶部