package iot import ( "bytes" "context" "io" "time" v1 "git.5iot.com/iotlcm-public/iotlcm-admin-svr/api/iot/v1" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/exportcenter" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/iot/simcardquery" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/iot_excelize" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) // simCardQueryService 两个查询功能共用同一份实现,避免重复注册。 var simCardQueryService = simcardquery.New() // SimCardBaseQueryTemplate 下载卡基础信息查询模板 func (c *ControllerV1) SimCardBaseQueryTemplate(ctx context.Context, req *v1.SimCardBaseQueryTemplateReq) (res *v1.SimCardBaseQueryTemplateRes, err error) { file, name, err := simCardQueryService.BaseTemplate(ctx) if err != nil { return nil, err } defer file.Close() return &v1.SimCardBaseQueryTemplateRes{}, iot_excelize.WriteHTTP(ctx, file, name) } // SimCardBaseQueryColumns 卡基础信息查询可选导出列 func (c *ControllerV1) SimCardBaseQueryColumns(ctx context.Context, req *v1.SimCardBaseQueryColumnsReq) (res *v1.SimCardBaseQueryColumnsRes, err error) { return &v1.SimCardBaseQueryColumnsRes{Items: simCardQueryService.BaseColumnOptions()}, nil } // SimCardBaseQueryExport 提交卡基础信息查询导出 func (c *ControllerV1) SimCardBaseQueryExport(ctx context.Context, req *v1.SimCardBaseQueryExportReq) (res *v1.SimCardBaseQueryExportRes, err error) { input, err := excelInput(ctx, req.Mode) if err != nil { return nil, err } submit, err := simCardQueryService.ExportBase(ctx, &req.SimCardQueryExportParam, input) if err != nil { return nil, err } return &v1.SimCardBaseQueryExportRes{SimCardQuerySubmitRes: toSubmitRes(submit)}, nil } // SimCardUsageHistoryTemplate 下载月历史用量查询模板 func (c *ControllerV1) SimCardUsageHistoryTemplate(ctx context.Context, req *v1.SimCardUsageHistoryTemplateReq) (res *v1.SimCardUsageHistoryTemplateRes, err error) { file, name, err := simCardQueryService.UsageHistoryTemplate(ctx) if err != nil { return nil, err } defer file.Close() return &v1.SimCardUsageHistoryTemplateRes{}, iot_excelize.WriteHTTP(ctx, file, name) } // SimCardUsageHistoryColumns 月历史用量查询固定列与近12个月月份清单 func (c *ControllerV1) SimCardUsageHistoryColumns(ctx context.Context, req *v1.SimCardUsageHistoryColumnsReq) (res *v1.SimCardUsageHistoryColumnsRes, err error) { return &v1.SimCardUsageHistoryColumnsRes{ Items: simCardQueryService.UsageHistoryColumnOptions(), Months: simCardQueryService.UsageHistoryMonths(time.Now()), }, nil } // SimCardUsageHistoryDeptOptions 月历史用量查询可选公司 func (c *ControllerV1) SimCardUsageHistoryDeptOptions(ctx context.Context, req *v1.SimCardUsageHistoryDeptOptionsReq) (res *v1.SimCardUsageHistoryDeptOptionsRes, err error) { items, err := simCardQueryService.DeptOptions(ctx) if err != nil { return nil, err } return &v1.SimCardUsageHistoryDeptOptionsRes{ Items: items, CurrentDeptId: contexts.GetDeptId(ctx), }, nil } // SimCardUsageHistoryExport 提交月历史用量查询导出 func (c *ControllerV1) SimCardUsageHistoryExport(ctx context.Context, req *v1.SimCardUsageHistoryExportReq) (res *v1.SimCardUsageHistoryExportRes, err error) { input, err := excelInput(ctx, req.Mode) if err != nil { return nil, err } submit, err := simCardQueryService.ExportUsageHistory(ctx, &req.SimCardUsageHistoryExportParam, input) if err != nil { return nil, err } return &v1.SimCardUsageHistoryExportRes{SimCardQuerySubmitRes: toSubmitRes(submit)}, nil } // excelInput 只在 Excel 模式下读取上传文件。 // 一次性读进内存再交给后台解析:提交接口必须立即返回, // 而 HTTP 请求结束后临时上传文件可能被清理,不能在后台协程里再读。 func excelInput(ctx context.Context, mode string) (simcardquery.ExcelInput, error) { if mode != model.SimCardQueryModeExcel { return nil, nil } request := g.RequestFromCtx(ctx) if request == nil { return nil, gerror.New("当前上下文不是HTTP请求") } file := request.GetUploadFile("file") if file == nil { return nil, gerror.New("请先上传 Excel 文件") } content, err := readUploadContent(file) if err != nil { return nil, err } if len(content) == 0 { return nil, gerror.New("上传的 Excel 文件为空") } return func() (io.Reader, error) { return bytes.NewReader(content), nil }, nil } func toSubmitRes(submit *exportcenter.SubmitResult) *model.SimCardQuerySubmitRes { if submit == nil { return nil } return &model.SimCardQuerySubmitRes{ TaskId: submit.TaskId, TaskNo: submit.TaskNo, Total: submit.Total, } } // maxUploadBytes Excel 上传大小上限(MB 换算后的字节数)。 // 20MB 足够容纳 20000 行三列号码,再大基本是用户传错文件。 const maxUploadBytes = 20 << 20 // readUploadContent 一次性读出上传文件内容。 func readUploadContent(file *ghttp.UploadFile) ([]byte, error) { reader, err := file.Open() if err != nil { return nil, gerror.Wrap(err, "读取上传文件失败") } defer reader.Close() if file.Size > maxUploadBytes { return nil, gerror.Newf("上传文件超过 %dMB 上限", maxUploadBytes>>20) } content, err := io.ReadAll(reader) if err != nil { return nil, gerror.Wrap(err, "读取上传文件失败") } return content, nil }