Files
suixinkan_uikit/suixinkan/Features/WildPhotographerReport/举报摄影师接口.md

8.2 KiB
Raw Blame History

举报摄影师接口文档

本文档记录 iOS WildPhotographerReport 模块当前使用的后端接口,以及仍处于 Mock 阶段的业务点。

基础约定

  • 业务域:举报摄影师
  • API 封装:suixinkan/Features/WildPhotographerReport/API/WildPhotographerReportAPI.swift
  • 网络入口:NetworkServices.shared.wildPhotographerReportAPI
  • 后端成功码:100000
  • 响应包裹:工程统一 APIEnvelope<T>
  • 当前状态:“举报类型”、“提交举报”和“我的举报列表”已接接口;详情、补充证据、风险地图仍使用 Mock 数据闭环。

1. 获取举报类型

用途

提交举报页面进入时拉取可选举报类型。举报类型由后台动态维护,客户端不能用枚举写死,也不展示图标。

请求

GET /api/yf-handset-app/photog/report/types

请求参数

无。

响应示例

{
  "code": 100000,
  "msg": "success",
  "data": {
    "list": [
      {
        "value": 1,
        "label": "私下收款"
      },
      {
        "value": 2,
        "label": "疑似打野"
      },
      {
        "value": 3,
        "label": "未戴工牌"
      },
      {
        "value": 4,
        "label": "其他"
      }
    ]
  },
  "time": "2026-07-08 14:21:21"
}

iOS 模型

struct WildReportType: Decodable, Hashable {
    let value: Int
    let label: String
}

struct WildReportTypeListResponse: Decodable, Hashable {
    let list: [WildReportType]
}

UI 行为

  • 页面加载时调用 WildPhotographerReportSubmitViewModel.loadReportTypes(api:)
  • 按接口返回顺序渲染举报类型。
  • 每行最多展示 3 个类型,超过 3 个自动换行。
  • label 展示文字,不展示图标。
  • 默认选中 value == 2 的类型;如果接口返回中不存在该类型,则选中列表第一项。
  • 接口失败时回退本地兜底列表,并提示“举报类型获取失败,已使用默认类型”。

当前调用位置

  • WildPhotographerReportSubmitViewController.viewDidLoad()
  • WildPhotographerReportSubmitViewModel.loadReportTypes(api:)
  • WildPhotographerReportAPI.reportTypes()

2. 提交举报

用途

提交页点击“提交举报”时调用。客户端会先把现场证据和支付截图上传到 OSS全部上传成功后再提交表单数据。

请求

POST /api/yf-handset-app/photog/report/submit

请求参数

{
  "scenic_id": 1,
  "report_type": 2,
  "desc": "疑似人员在观景台附近主动揽客,并引导游客线下转账。",
  "contact_phone": "13800138000",
  "location_name": "黄山风景区",
  "location_address": "光明顶景区",
  "lat": 30.12345,
  "lng": 120.12345,
  "evidences": [
    {
      "file_url": "https://example.com/photog_report/20260708/1/report_image.jpg",
      "file_type": 1,
      "file_name": "report_image.jpg"
    },
    {
      "file_url": "https://example.com/photog_report/20260708/1/report_video.mp4",
      "file_type": 2,
      "file_name": "report_video.mp4"
    }
  ],
  "payment_screenshots": [
    {
      "file_url": "https://example.com/photog_report/20260708/1/payment.jpg",
      "file_type": 1,
      "file_name": "payment.jpg"
    }
  ]
}

字段说明

  • scenic_id:当前景区 ID来自 AppStore.shared.currentScenicId,必须大于 0。
  • report_type:举报类型接口返回的 value
  • desc:举报说明,必填,最多 500 字。
  • store_user_id:被举报摄影师 ID当前页面无来源本轮暂不传。
  • contact_phone:当前联系方式输入值,非空才传。
  • location_name / location_address:从当前定位展示文案拆分;无法拆分时使用景区名和完整地址兜底。
  • lat / lng:当前定位快照坐标;定位失败时使用 Mock 地址对应的兜底坐标。
  • evidences:现场证据,必填,至少 1 项、最多 9 项。
  • payment_screenshots:线下微信、支付宝截图,选填,最多 3 张。
  • file_type:举报提交接口约定为 1 = 图片2 = 视频

iOS 模型

struct WildReportSubmitRequest: Encodable, Equatable {
    let scenicId: Int
    let reportType: Int
    let desc: String
    let storeUserId: Int?
    let contactPhone: String?
    let locationName: String?
    let locationAddress: String?
    let lat: Double
    let lng: Double
    let evidences: [WildReportEvidenceRequest]
    let paymentScreenshots: [WildReportEvidenceRequest]
}

struct WildReportEvidenceRequest: Encodable, Equatable {
    let fileURL: String
    let fileType: Int
    let fileName: String?
}

UI 与上传行为

  • 图片、视频和支付截图使用系统相册选择器。
  • 图片/视频选择后先保存到本地临时目录,点击附件 tile 可预览本地文件。
  • 提交时顺序上传附件到 OSS按钮展示上传进度并禁用重复提交。
  • 任一 OSS 上传失败时不调用提交接口,并保留用户已填写内容。
  • 支付截图通过 payment_screenshots 独立提交,不替代现场证据必填校验。

当前调用位置

  • WildPhotographerReportSubmitViewController.submitTapped()
  • WildPhotographerReportSubmitViewModel.submitReport(api:uploader:scenicId:scenicName:)
  • OSSUploadService.uploadWildReportAttachment(...)
  • WildPhotographerReportAPI.submitReport(_:)

3. 我的举报列表

用途

“我的举报”页面进入、切换状态筛选、滚动加载更多时调用。

请求

GET /api/yf-handset-app/photog/report/list

请求参数

参数 类型 说明
scenic_id integer 可选,当前景区 ID大于 0 时传
handle_status integer 可选,状态筛选;“全部”不传该参数,其他筛选 iOS 固定使用该参数
status integer 可选,与 handle_status 等价iOS 不传
page integer 可选,默认 1
page_size integer 可选,默认 10最大 50

状态码

  • 全部:不传 handle_status
  • 0:待处理
  • 1:处理中
  • 2:已处理

响应示例

{
  "code": 100000,
  "msg": "success",
  "data": {
    "list": [
      {
        "id": 32,
        "complaint_no": "JB20260708917",
        "title": "私下收款举报",
        "report_type": 1,
        "report_type_text": "私下收款",
        "desc": "我在",
        "scenic_id": 128,
        "scenic_name": "伊犁那拉提景区-5A",
        "location_name": "伊犁那拉提景区-5A",
        "latitude": "32.4299428",
        "longitude": "119.4403263",
        "handle_status": 0,
        "handle_status_text": "待处理",
        "created_at": "2026-07-08 16:06:59"
      }
    ],
    "total": 1,
    "page": 1,
    "page_size": 10
  },
  "time": "2026-07-08 16:07:30"
}

iOS 模型

struct WildReportListRequest: Equatable {
    let scenicId: Int?
    let handleStatus: Int?
    let page: Int
    let pageSize: Int
}

struct WildReportListResponse: Decodable, Equatable {
    let list: [WildReportListItem]
    let total: Int
    let page: Int
    let pageSize: Int
}

UI 行为

  • 页面首次进入请求 page=1&page_size=10,不传 handle_status
  • 切换筛选时重置为第一页,待处理传 handle_status=0,处理中传 handle_status=1,已处理传 handle_status=2
  • 滚动到底部时,如果仍有更多数据,则请求下一页并追加。
  • 首屏失败显示 toast 和空态;加载更多失败只 toast并保留已有列表。
  • 列表接口暂不返回媒体数量,WildReportRecord.imageCount/videoCount 暂按 0 处理,后续详情接口补齐。

当前调用位置

  • WildPhotographerReportListViewController.viewDidLoad()
  • WildPhotographerReportListViewModel.loadInitial(api:scenicId:)
  • WildPhotographerReportListViewModel.loadMoreIfNeeded(api:scenicId:)
  • WildPhotographerReportAPI.reportList(_:)

Mock 阶段业务

以下业务当前仍由 WildPhotographerReportMockStore 和 ViewModel 本地逻辑完成,暂未接真实接口:

  • 举报详情
  • 补充证据
  • 附近风险地图
  • 分享、媒体预览、地图导航演示提示

后续接入真实接口时,应优先在 WildPhotographerReportServing 中补充语义化方法,并保持 ViewModel 不依赖 UIKit 视图类型。