package dto import "time" // ListPhoneAssetAssociationRequest 后台查询手机号—资产关联列表请求。 // 仅超级管理员与平台用户可调用,范围外资产不进入结果集,越权与不存在不形成可枚举差异。 type ListPhoneAssetAssociationRequest struct { Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码,默认 1"` PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量,默认 20,最大 100"` AssetIdentifier string `json:"asset_identifier" query:"asset_identifier" validate:"omitempty,max=100" maxLength:"100" description:"资产标识(ICCID、虚拟号、IMEI、SN 或接入号,精确匹配)"` Phone string `json:"phone" query:"phone" validate:"omitempty,max=20" maxLength:"20" description:"手机号(完整值精确匹配)"` Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"关联状态 (0:已失效, 1:有效)"` CreatedAtStart *time.Time `json:"created_at_start" query:"created_at_start" description:"关联创建时间起(含)"` CreatedAtEnd *time.Time `json:"created_at_end" query:"created_at_end" description:"关联创建时间止(含)"` } // PhoneAssetAssociationResponse 手机号—资产关联列表项。 // 手机号为读取范围内的完整值(读侧不脱敏);审计与日志仍只写脱敏值。 type PhoneAssetAssociationResponse struct { ID uint `json:"id" description:"关联关系ID"` Phone string `json:"phone" description:"关联手机号(完整值)"` AssetType string `json:"asset_type" description:"资产类型 (iot_card:物联网卡, device:设备)"` AssetID uint `json:"asset_id" description:"资产ID"` AssetIdentifier string `json:"asset_identifier" description:"资产当前标识(卡为 ICCID,设备为虚拟号)"` Status int `json:"status" description:"关联状态 (0:已失效, 1:有效)"` StatusName string `json:"status_name" description:"关联状态中文名称"` Source string `json:"source" description:"建立来源,固定为 h5_sms_verification"` EstablishedAt string `json:"established_at" description:"建立时间(短信验证通过时间)"` ValidAssociationCount int64 `json:"valid_association_count" description:"该手机号当前有效关联数量(只统计有效关系,卡与设备各计一项,与「最多关联十项」上限判定同一计数口径)"` InvalidatedAt string `json:"invalidated_at" description:"失效时间;有效关系为空"` InvalidationMethod string `json:"invalidation_method" description:"失效方式 (backend_single:后台单项, backend_batch:后台批量, csv_import:CSV导入);有效关系为空"` InvalidationMethodName string `json:"invalidation_method_name" description:"失效方式中文名称;有效关系为空"` InvalidationReason string `json:"invalidation_reason" description:"失效原因;有效关系为空"` InvalidatorID uint `json:"invalidator_id" description:"最近解绑人账号ID(后台账号标识);有效关系为空,值为 0"` InvalidatorName string `json:"invalidator_name" description:"最近解绑人后台账号名称快照;有效关系为空。不以创建人或最后更新人填充"` } // PhoneAssetAssociationPageResult 手机号—资产关联列表分页响应。 type PhoneAssetAssociationPageResult struct { Items []*PhoneAssetAssociationResponse `json:"items" description:"关联列表"` Total int64 `json:"total" description:"总记录数"` Page int `json:"page" description:"当前页码"` Size int `json:"size" description:"每页数量"` } // UnbindPhoneAssetAssociationRequest 单项解除手机号—资产关联请求。 // 路径主键即指定一条关系;解除必须二次确认并填写原因,缺一即拒绝。 type UnbindPhoneAssetAssociationRequest struct { ID uint `json:"-" path:"id" description:"关联关系ID" required:"true" minimum:"1"` Reason string `json:"reason" validate:"required,min=1,max=500" required:"true" minLength:"1" maxLength:"500" description:"解除原因(1~500 字符)"` Confirmed bool `json:"confirmed" validate:"required,eq=true" required:"true" description:"二次确认,必须为 true"` } // UnbindPhoneAssetAssociationResponse 单项解除结果。 type UnbindPhoneAssetAssociationResponse struct { ID uint `json:"id" description:"关联关系ID"` AssetType string `json:"asset_type" description:"资产类型 (iot_card:物联网卡, device:设备)"` AssetID uint `json:"asset_id" description:"资产ID"` UnboundCount int `json:"unbound_count" description:"本次解除的有效关系数,成功时为 1"` InvalidatedAt string `json:"invalidated_at" description:"失效时间"` } // BatchUnbindAssetItem 批量解除中的单项资产。 type BatchUnbindAssetItem struct { AssetType string `json:"asset_type" validate:"required,oneof=iot_card device" required:"true" description:"资产类型 (iot_card:物联网卡, device:设备)"` AssetID uint `json:"asset_id" validate:"required,min=1" required:"true" minimum:"1" description:"资产ID"` } // BatchUnbindPhoneAssetAssociationRequest 按资产批量解除手机号关联请求。 // 每项资产解除其全部当前有效关系,逐资产独立执行,部分成功不回滚成功项。 type BatchUnbindPhoneAssetAssociationRequest struct { Assets []BatchUnbindAssetItem `json:"assets" validate:"required,min=1,max=200,dive" required:"true" description:"待解除的资产集合,按 (资产类型, 资产ID) 去重后执行"` Reason string `json:"reason" validate:"required,min=1,max=500" required:"true" minLength:"1" maxLength:"500" description:"解除原因(1~500 字符)"` Confirmed bool `json:"confirmed" validate:"required,eq=true" required:"true" description:"二次确认,必须为 true"` } // BatchUnbindAssetResult 批量解除的逐项结果。 type BatchUnbindAssetResult struct { AssetType string `json:"asset_type" description:"资产类型 (iot_card:物联网卡, device:设备)"` AssetID uint `json:"asset_id" description:"资产ID"` Success bool `json:"success" description:"该项是否解除成功"` UnboundCount int `json:"unbound_count" description:"该项解除的有效关系数"` Reason string `json:"reason,omitempty" description:"该项失败原因,成功时为空"` } // CreatePhoneAssetUnbindImportRequest 创建手机号—资产关联 CSV 解绑导入任务请求。 type CreatePhoneAssetUnbindImportRequest struct { FileKey string `json:"file_key" validate:"required,min=1,max=500" required:"true" minLength:"1" maxLength:"500" description:"CSV 对象存储 Key,必须以 phone-unbind-imports/ 开头且扩展名为 .csv(通过 POST /api/admin/storage/upload-url 获取)"` Reason string `json:"reason" validate:"required,min=1,max=500" required:"true" minLength:"1" maxLength:"500" description:"任务级解绑原因(1~500 字符),写入每次解除的失效原因"` Confirmed bool `json:"confirmed" validate:"required,eq=true" required:"true" description:"二次确认,必须为 true"` } // ListPhoneAssetUnbindImportRequest 查询解绑导入任务列表请求。 type ListPhoneAssetUnbindImportRequest struct { Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码,默认 1"` PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量,默认 20,最大 100"` Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败)"` } // GetPhoneAssetUnbindImportRequest 解绑导入任务详情路径参数。 type GetPhoneAssetUnbindImportRequest struct { ID uint `path:"id" required:"true" description:"导入任务ID"` } // PhoneAssetUnbindImportTaskResponse 解绑导入任务响应。 type PhoneAssetUnbindImportTaskResponse struct { ID uint `json:"id" description:"导入任务ID"` TaskNo string `json:"task_no" description:"导入任务编号"` FileName string `json:"file_name" description:"上传的源 CSV 文件名"` UnbindReason string `json:"unbind_reason" description:"任务级解绑原因"` Status int `json:"status" description:"任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败)"` StatusName string `json:"status_name" description:"任务状态中文名称"` TotalCount int `json:"total_count" description:"数据行总数;任务级失败时为 0"` SuccessCount int `json:"success_count" description:"成功行数"` FailCount int `json:"fail_count" description:"失败行数"` ErrorMessage string `json:"error_message" description:"任务级失败原因;与行级失败原因分开记录"` CreatorName string `json:"creator_name" description:"任务创建人名称快照"` CreatedAt string `json:"created_at" description:"创建时间"` StartedAt string `json:"started_at" description:"开始处理时间"` CompletedAt string `json:"completed_at" description:"完成时间"` } // PhoneAssetUnbindImportTaskPageResult 解绑导入任务分页响应。 type PhoneAssetUnbindImportTaskPageResult struct { Items []*PhoneAssetUnbindImportTaskResponse `json:"items" description:"导入任务列表"` Total int64 `json:"total" description:"总记录数"` Page int `json:"page" description:"当前页码"` Size int `json:"size" description:"每页数量"` } // PhoneAssetUnbindImportItemResponse 解绑导入逐行结果。 // AssociatedPhones 是解绑当时的完整手机号快照:关系已失效,只有快照能事后展示被解绑的手机号。 type PhoneAssetUnbindImportItemResponse struct { Line int `json:"line" description:"行号,自数据首行起计(表头不计入)"` AssetType string `json:"asset_type" description:"资产类型 (iot_card:物联网卡, device:设备);未定位到资产时为空"` AssetIdentifier string `json:"asset_identifier" description:"导入文件中的资产标识原文"` AssetID uint `json:"asset_id" description:"资产ID;未定位到资产时为 0"` UnboundCount int `json:"unbound_count" description:"该行解除的有效关系数"` AssociatedPhones []string `json:"associated_phones" description:"解绑当时的完整关联手机号快照;失败行为空数组"` Status int `json:"status" description:"行状态 (3:成功, 4:失败)"` StatusName string `json:"status_name" description:"行状态中文名称"` Reason string `json:"reason" description:"失败原因;成功行为空"` } // PhoneAssetUnbindImportTaskDetailResponse 解绑导入任务详情响应。 type PhoneAssetUnbindImportTaskDetailResponse struct { PhoneAssetUnbindImportTaskResponse Items []PhoneAssetUnbindImportItemResponse `json:"items" description:"逐行结果明细;任务级失败时为空数组"` } type BatchUnbindPhoneAssetAssociationResponse struct { SuccessCount int `json:"success_count" description:"解除成功的资产项数"` FailCount int `json:"fail_count" description:"解除失败的资产项数"` Items []BatchUnbindAssetResult `json:"items" description:"逐项结果,顺序与请求去重后的资产集合一致"` }