package models import ( "errors" "fmt" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" orm "go-admin/common/global" "go-admin/logger" "go-admin/tools" "go-admin/tools/config" "gorm.io/gorm" "math/rand" "time" ) const ( ErpRepairOrderUnAudit = 1 // 待审核 ErpRepairOrderWaitRepair = 2 // 待送修 ErpRepairOrderBingRepaired = 3 // 维修中 ErpRepairOrderFinished = 4 // 已完成 ) type RepairRecord struct { Model SerialNumber string `json:"serial_number"` // 订单编号 Uid uint32 `json:"uid"` // 用户ID Tel string `json:"tel"` // 手机号 MemberLevel uint32 `json:"member_level"` // 会员等级:1-普通用户,6-尊享会员 StoreId uint32 `json:"store_id"` // 门店ID StoreName string `json:"store_name" gorm:"-"` // 门店名称 HandlerId uint32 `json:"handler_id"` // 经手人ID HandlerName string `json:"handler_name"` // 经手人名称 State uint8 `json:"state"` // 状态(1-待审核,2-待送修,3-维修中,4-已完成) MakerId uint32 `json:"maker_id"` // 制单人ID MakerName string `json:"maker_name"` // 制单人名称 MakerTime *time.Time `json:"maker_time"` // 制单时间 AuditorId uint32 `json:"auditor_id"` // 审核人ID AuditorName string `json:"auditor_name"` // 审核人名称 AuditTime *time.Time `json:"audit_time"` // 审核时间 SendTime *time.Time `json:"send_time"` // 送修时间 SendRemark string `json:"send_remark"` // 送修备注 ExpressType uint8 `json:"express_type"` // 邮寄方:1-个人;2-门店 ExpressNo string `json:"express_no"` // 快递单号 ExpressFee float64 `json:"express_fee"` // 快递费用 RepairUnitId uint32 `json:"repair_unit_id"` // 维修单位ID(供应商) RepairUnitName string `json:"repair_unit_name" gorm:"-"` // 维修单位名称(供应商) RepairFee float64 `json:"repair_fee"` // 维修费用 CompletedTime *time.Time `json:"completed_time"` // 完成时间 CompleteRemark string `json:"complete_remark"` // 完成备注 Commodities []RepairRecordCommodity `json:"commodities" gorm:"-"` // 维修商品信息 } type RepairRecordCommodity struct { Model RepairRecordId uint32 `json:"repair_record_id"` // 维修记录ID CommodityId uint32 `json:"commodity_id"` // 商品ID CommodityName string `json:"commodity_name"` // 商品名称 OldIMEI string `json:"old_imei"` // 旧机器编码 NewIMEI string `json:"new_imei"` // 新机器编码 Count uint32 `json:"count"` // 数量 FaultImage string `json:"fault_image"` // 故障图片 FaultDesc string `json:"fault_desc"` // 故障描述 } type RepairCreateReq struct { Uid uint32 `json:"uid"` Tel string `json:"tel"` StoreId uint32 `json:"store_id" binding:"required"` HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id HandlerName string `json:"handler_name"` // 经手人名称 Commodities []RepairRecordCommodity `json:"commodities"` } type RepairEditReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 订单编号 Uid uint32 `json:"uid"` // 用户ID Tel string `json:"tel"` // 手机号 MemberLevel uint32 `json:"member_level"` // 会员等级:普通用户、尊享会员 StoreId uint32 `json:"store_id" binding:"required"` // 门店ID HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人ID HandlerName string `json:"handler_name"` // 经手人名称 State uint8 `json:"state"` // 状态(1-待审核,2-已审核,3-维修中,4-已完成) MakerId uint32 `json:"maker_id" binding:"required"` // 制单人ID MakerName string `json:"maker_name"` // 制单人名称 MakerTime *time.Time `json:"maker_time"` // 制单时间 AuditorId uint32 `json:"auditor_id"` // 审核人ID AuditorName string `json:"auditor_name"` // 审核人名称 AuditTime *time.Time `json:"audit_time"` // 审核时间 SendTime *time.Time `json:"send_time"` // 送修时间 SendRemark string `json:"send_remark"` // 送修备注 ExpressNo string `json:"express_no"` // 快递单号 RepairUnitId uint32 `json:"repair_unit_id"` // 维修单位ID RepairFee float64 `json:"repair_fee"` // 维修费用 CompletedTime *time.Time `json:"completed_time"` // 完成时间 CompleteRemark string `json:"complete_remark"` // 完成备注 Commodities []RepairRecordCommodity `json:"commodities"` } // ErpRepairDeleteReq 删除维修订单入参 type ErpRepairDeleteReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 } // ErpRepairOrderListReq 查询维修订单列表入参 type ErpRepairOrderListReq struct { SerialNumber string `json:"serial_number"` // 单据编号 Uid uint32 `json:"uid"` // 用户ID Tel string `json:"tel"` // 手机号 MemberLevel uint32 `json:"member_level"` // 会员等级:普通用户、尊享会员 StoreId []uint32 `json:"store_id"` // 门店id HandlerId uint32 `json:"handler_id"` // 经手人id State []uint32 `json:"state"` // 状态:1-待审核,2-已审核,3-维修中,4-已完成 RepairUnitId uint32 `json:"repair_unit_id"` // 维修单位ID(供应商) MakeTimeStart string `json:"make_time_start"` // 制单开始时间 MakeTimeEnd string `json:"make_time_end"` // 制单结束时间 AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 SendTimeStart string `json:"send_time_start"` // 送修开始时间 SendTimeEnd string `json:"send_time_end"` // 送修结束时间 CompleteTimeStart string `json:"complete_time_start"` // 维修完成开始时间 CompleteTimeEnd string `json:"complete_time_end"` // 维修完成结束时间 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // ErpRepairOrderListResp 查询维修订单列表出参 type ErpRepairOrderListResp struct { List []RepairRecord `json:"list"` Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 } // ErpRepairDetailReq 查询维修订单详情入参 type ErpRepairDetailReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 } // ErpRepairAuditReq 审核维修订单入参 type ErpRepairAuditReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核 } // ErpRepairSendReq 维修订单送修入参 type ErpRepairSendReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 RepairUnitId uint32 `json:"repair_unit_id" binding:"required"` // 维修单位ID(供应商) ExpressType uint8 `json:"express_type" binding:"required"` // 邮寄方:1-个人;2-门店 ExpressNo string `json:"express_no"` // 快递单号 ExpressFee float64 `json:"express_fee"` // 快递费用 SendRemark string `json:"send_remark"` // 送修备注 } // ErpRepairCompleteReq 维修订单完成入参 type ErpRepairCompleteReq struct { SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 RepairFee float64 `json:"repair_fee"` // 维修费用 CompleteRemark string `json:"complete_remark"` // 完成备注 } // NewRepairBillSn 生成维修订单号 func NewRepairBillSn() string { nowTime := time.Now() rand.Seed(nowTime.UnixNano()) max := 1 for { if max > 5 { logger.Error("create sn err") return "" } random := rand.Int31n(9999) + 1000 sn := fmt.Sprintf("wx%s%d", nowTime.Format("060102"), random) exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM repair_record WHERE serial_number='%s'", sn)) if err != nil { logger.Error("exist sn err") } if !exist { return sn } max++ } } // CreateRepairOrder 创建维修订单 func CreateRepairOrder(req *RepairCreateReq, sysUser *SysUser) (*RepairRecord, error) { // 开始事务 tx := orm.Eloquent.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() return } }() userMemberLevel := 1 // 判断是否为尊享会员 if IsValidPrivilegeMember(req.Uid) { userMemberLevel = 6 } nowTime := time.Now() // 写入主表 repair := RepairRecord{ SerialNumber: NewRepairBillSn(), Uid: req.Uid, Tel: req.Tel, MemberLevel: uint32(userMemberLevel), StoreId: req.StoreId, HandlerId: req.HandlerId, HandlerName: req.HandlerName, MakerId: uint32(sysUser.UserId), MakerName: sysUser.NickName, MakerTime: &nowTime, State: ErpRepairOrderUnAudit, // 初始状态:待审核 } if err := tx.Create(&repair).Error; err != nil { tx.Rollback() logger.Error("Create RepairRecord err:", logger.Field("err", err)) return nil, err } // 写入子表 for _, com := range req.Commodities { item := RepairRecordCommodity{ RepairRecordId: repair.ID, CommodityId: com.CommodityId, CommodityName: com.CommodityName, OldIMEI: com.OldIMEI, NewIMEI: com.NewIMEI, Count: com.Count, FaultImage: com.FaultImage, FaultDesc: com.FaultDesc, } if err := tx.Create(&item).Error; err != nil { tx.Rollback() logger.Error("Create RepairCommodity err:", logger.Field("err", err)) return nil, err } } if err := tx.Commit().Error; err != nil { tx.Rollback() logger.Error("commit err:", logger.Field("err", err)) return nil, err } repair.Commodities = req.Commodities return &repair, nil } // EditRepairOrder 编辑维修订单 func EditRepairOrder(req *RepairEditReq, sysUser *SysUser) (*RepairRecord, error) { // 查询订单信息 var repairOrder RepairRecord err := orm.Eloquent.Table("repair_record").Where("serial_number=?", req.SerialNumber).Find(&repairOrder).Error if err != nil { logger.Error("repair order err:", logger.Field("err", err)) return nil, err } if repairOrder.State != ErpRepairOrderUnAudit { // 只有待审核的订单才能编辑 return nil, errors.New("订单不是待审核状态") } begin := orm.Eloquent.Begin() // 1-更新维修订单信息 repairOrder.Uid = req.Uid repairOrder.Tel = req.Tel repairOrder.MemberLevel = req.MemberLevel repairOrder.StoreId = req.StoreId repairOrder.HandlerId = req.HandlerId repairOrder.HandlerName = req.HandlerName repairOrder.MakerId = uint32(sysUser.UserId) repairOrder.MakerName = sysUser.NickName err = begin.Model(&RepairRecord{}).Where("serial_number=?", req.SerialNumber). Omit("created_at").Save(repairOrder).Error if err != nil { begin.Rollback() logger.Error("update erp_order err:", logger.Field("err", err)) return nil, err } // 2-更新维修订单商品表 err = updateRepairCommodityData(begin, repairOrder.ID, req) if err != nil { begin.Rollback() logger.Error("update erp_purchase_commodity err:", logger.Field("err", err)) return nil, err } err = begin.Commit().Error if err != nil { begin.Rollback() logger.Error("commit err:", logger.Field("err", err)) return nil, err } return &repairOrder, nil } // updateRepairCommodityData 更新维修订单商品信息 func updateRepairCommodityData(gdb *gorm.DB, orderId uint32, req *RepairEditReq) error { // 查询现有的零售订单信息 var commodities []RepairRecordCommodity err := orm.Eloquent.Table("repair_record_commodity").Where("repair_record_id = ?", orderId).Find(&commodities).Error if err != nil { logger.Error("query repair_record_commodity err:", logger.Field("err", err)) return err } // 1-删除所有的商品信息 if len(commodities) != 0 { err = gdb.Delete(&commodities).Error if err != nil { logger.Error("更新商品订单信息-删除 error") return errors.New("操作失败:" + err.Error()) } } for i, _ := range req.Commodities { req.Commodities[i].ID = 0 if req.Commodities[i].RepairRecordId == 0 { //发现前端有时会没传,后端打补丁 req.Commodities[i].RepairRecordId = orderId } } // 2-更新商品订单信息-新增 if len(req.Commodities) != 0 { err = gdb.Create(&req.Commodities).Error if err != nil { logger.Error("更新商品订单信息-新增 error") return errors.New("操作失败:" + err.Error()) } } return nil } // List 查询维修订单列表 func (m *ErpRepairOrderListReq) List(c *gin.Context) (*ErpRepairOrderListResp, error) { resp := &ErpRepairOrderListResp{ PageIndex: m.PageIndex, PageSize: m.PageSize, } page := m.PageIndex - 1 if page < 0 { page = 0 } if m.PageSize == 0 { m.PageSize = 10 } qs := orm.Eloquent.Table("repair_record") if m.SerialNumber != "" { qs = qs.Where("serial_number = ?", m.SerialNumber) } else if m.Uid != 0 { qs = qs.Where("uid = ?", m.Uid) } else if m.Tel != "" { qs = qs.Where("tel = ?", m.Tel) } else { if m.RepairUnitId != 0 { qs = qs.Where("repair_unit_id = ?", m.RepairUnitId) } if len(m.StoreId) != 0 { qs = qs.Where("store_id in ?", m.StoreId) } // 非管理员才判断所属门店 if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { sysUser, err := GetSysUserByCtx(c) if err != nil { return nil, errors.New("操作失败:" + err.Error()) } // 返回sysUser未过期的门店id列表 storeList := GetValidStoreIDs(sysUser.StoreData) if len(storeList) > 0 { if len(storeList) == 1 { qs = qs.Where("store_id = ?", storeList[0]) } else { qs = qs.Where("store_id IN (?)", storeList) } } else { return nil, errors.New("用户未绑定门店") } } if m.MemberLevel != 0 { qs = qs.Where("member_level = ?", m.MemberLevel) } if len(m.State) > 0 { qs = qs.Where("state IN (?)", m.State) } if m.HandlerId != 0 { qs = qs.Where("handler_id=?", m.HandlerId) } if m.AuditTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) if err != nil { logger.Errorf("erpRepairOrderList err:", err) return nil, err } qs = qs.Where("audit_time > ?", parse) } if m.AuditTimeEnd != "" { parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd) if err != nil { logger.Errorf("erpRepairOrderList err:", err) return nil, err } //parse = parse.AddDate(0, 0, 1) qs = qs.Where("audit_time < ?", parse) } if m.MakeTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.MakeTimeStart) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("maker_time > ?", parse) } if m.MakeTimeEnd != "" { parse, err := time.Parse(QueryTimeFormat, m.MakeTimeEnd) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("maker_time < ?", parse) } if m.SendTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.SendTimeStart) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("send_time > ?", parse) } if m.SendTimeEnd != "" { parse, err := time.Parse(QueryTimeFormat, m.SendTimeEnd) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("send_time < ?", parse) } if m.CompleteTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.CompleteTimeStart) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("complete_time > ?", parse) } if m.CompleteTimeEnd != "" { parse, err := time.Parse(QueryTimeFormat, m.CompleteTimeEnd) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("complete_time < ?", parse) } } var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("count err:", logger.Field("err", err)) return resp, err } resp.Total = int(count) var orders []RepairRecord err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("erp commodity list err:", logger.Field("err", err)) return resp, err } // 校验时间,如果为01-01-01 08:05,则赋值为空 for i, v := range orders { if v.MakerTime != nil && v.MakerTime.IsZero() { orders[i].MakerTime = nil } if v.AuditTime != nil && v.AuditTime.IsZero() { orders[i].AuditTime = nil } if v.SendTime != nil && v.SendTime.IsZero() { orders[i].SendTime = nil } if v.CompletedTime != nil && v.CompletedTime.IsZero() { orders[i].CompletedTime = nil } // 添加维修单位名称 supplier, _ := GetSupplierById(v.RepairUnitId) orders[i].RepairUnitName = supplier.Name } resp.List = orders return resp, nil } // SendToRepair 维修订单送修 func SendToRepair(req *ErpRepairSendReq, c *gin.Context) error { // 查询订单信息 var repairRecord RepairRecord err := orm.Eloquent.Table("repair_record").Where("serial_number = ?", req.SerialNumber). Find(&repairRecord).Error if err != nil { logger.Error("order err:", logger.Field("err", err)) return err } sysUser, err := GetSysUserByCtx(c) if err != nil { logger.Error("sys user err:", logger.Field("err", err)) return err } // 校验入参门店是否包含在用户所有门店中,是否过期 if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { if !CheckUserStore(repairRecord.StoreId, sysUser) { return errors.New("操作失败:您没有该门店权限") } } if repairRecord.ID == 0 { return errors.New("未查询到订单信息") } if repairRecord.State != ErpRepairOrderWaitRepair { return errors.New("订单不是待送修状态") } nowTime := time.Now() repairRecord.RepairUnitId = req.RepairUnitId repairRecord.ExpressType = req.ExpressType repairRecord.ExpressNo = req.ExpressNo repairRecord.ExpressFee = req.ExpressFee repairRecord.SendRemark = req.SendRemark repairRecord.State = ErpRepairOrderBingRepaired repairRecord.SendTime = &nowTime err = orm.Eloquent.Model(&RepairRecord{}).Where("id = ?", repairRecord.ID). Updates(repairRecord).Error if err != nil { return err } return nil } // CompleteRepairOrder 维修订单完成 func CompleteRepairOrder(req *ErpRepairCompleteReq, c *gin.Context) error { // 查询订单信息 var repairRecord RepairRecord err := orm.Eloquent.Table("repair_record").Where("serial_number = ?", req.SerialNumber). Find(&repairRecord).Error if err != nil { logger.Error("order err:", logger.Field("err", err)) return err } sysUser, err := GetSysUserByCtx(c) if err != nil { logger.Error("sys user err:", logger.Field("err", err)) return err } // 校验入参门店是否包含在用户所有门店中,是否过期 if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { if !CheckUserStore(repairRecord.StoreId, sysUser) { return errors.New("操作失败:您没有该门店权限") } } if repairRecord.ID == 0 { return errors.New("未查询到订单信息") } if repairRecord.State != ErpRepairOrderBingRepaired { return errors.New("订单不是待送修状态") } nowTime := time.Now() repairRecord.RepairFee = req.RepairFee repairRecord.CompleteRemark = req.CompleteRemark repairRecord.State = ErpRepairOrderFinished repairRecord.CompletedTime = &nowTime err = orm.Eloquent.Model(&RepairRecord{}).Where("id = ?", repairRecord.ID). Updates(repairRecord).Error if err != nil { return err } return nil } // ErpRepairDetailReportReq 维修明细汇总入参 type ErpRepairDetailReportReq struct { SerialNumber string `json:"serial_number"` // 单据编号 Uid uint32 `json:"uid"` // 用户ID Tel string `json:"tel"` // 手机号 MemberLevel uint32 `json:"member_level"` // 会员等级:普通用户、尊享会员 StoreId []uint32 `json:"store_id"` // 门店id HandlerId uint32 `json:"handler_id"` // 经手人id RepairUnitId uint32 `json:"repair_unit_id"` // 维修单位ID(供应商) MakeTimeStart string `json:"make_time_start"` // 制单开始时间 MakeTimeEnd string `json:"make_time_end"` // 制单结束时间 AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 SendTimeStart string `json:"send_time_start"` // 送修开始时间 SendTimeEnd string `json:"send_time_end"` // 送修结束时间 CompleteTimeStart string `json:"complete_time_start"` // 维修完成开始时间 CompleteTimeEnd string `json:"complete_time_end"` // 维修完成结束时间 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 IsExport uint32 `json:"is_export"` // 1-导出 //State []uint32 `json:"state"` // 状态:1-待审核,2-已审核,3-维修中,4-已完成 } // ErpRepairDetailReportResp 维修明细汇总出参 type ErpRepairDetailReportResp struct { Total int `json:"total"` // 总条数(总订单数) PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 ExportUrl string `json:"export_url"` // 导出excel地址 List []RepairRecord `json:"list"` // 零售明细 SumData RepairDetailTotalData `json:"sumData"` // 汇总数据 } // RepairDetailTotalData 维修明细相关金额汇总 type RepairDetailTotalData struct { Count int32 `json:"count"` // 维修数量 TotalExpressFee float64 `json:"total_express_fee"` // 快递费用 TotalRepairFee float64 `json:"total_repair_fee"` // 维修费用 } // RepairDetailReport 维修明细 func RepairDetailReport(req *ErpRepairDetailReportReq, c *gin.Context) (*ErpRepairDetailReportResp, error) { page := req.PageIndex - 1 if page < 0 { page = 0 } if req.PageSize == 0 { req.PageSize = 10 } db := orm.Eloquent.Table("repair_record AS rr"). Select("rr.*, s.name AS store_name, ru.name AS repair_unit_name"). Joins("LEFT JOIN store s ON rr.store_id = s.id"). Joins("LEFT JOIN erp_supplier ru ON rr.repair_unit_id = ru.id"). Where("state in (3,4)") // 条件过滤 db = buildRepairDetailQuery(db, req) sumQuery := orm.Eloquent.Table("repair_record AS rr"). Select("COUNT(*) AS count, COALESCE(SUM(rr.express_fee), 0) AS total_express_fee, COALESCE(SUM(rr.repair_fee), 0) AS total_repair_fee"). Where("state in (3,4)") sumQuery = buildRepairDetailQuery(sumQuery, req) // 非管理员才判断所属门店 if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { sysUser, err := GetSysUserByCtx(c) if err != nil { return nil, errors.New("操作失败:" + err.Error()) } // 返回sysUser未过期的门店id列表 storeList := GetValidStoreIDs(sysUser.StoreData) if len(storeList) > 0 { if len(storeList) == 1 { db = db.Where("store_id = ?", storeList[0]) sumQuery = sumQuery.Where("store_id = ?", storeList[0]) } else { db = db.Where("store_id IN (?)", storeList) sumQuery = sumQuery.Where("store_id IN (?)", storeList) } } else { return nil, errors.New("用户未绑定门店") } } var total int64 if err := db.Count(&total).Error; err != nil { return nil, err } var records []RepairRecord query := db.Order("rr.id DESC") if req.IsExport != 1 { query = query.Offset(page * req.PageSize).Limit(req.PageSize) } if err := query.Find(&records).Error; err != nil { return nil, err } // 查询商品明细 for i := range records { var commodities []RepairRecordCommodity err := orm.Eloquent.Table("repair_record_commodity AS rc"). Select("rc.*, ec.name AS commodity_name"). Joins("LEFT JOIN erp_commodity ec ON rc.commodity_id = ec.id"). Where("rc.repair_record_id = ?", records[i].ID). Find(&commodities).Error if err != nil { return nil, err } records[i].Commodities = commodities } // 汇总数据 var sumData RepairDetailTotalData if err := sumQuery.Scan(&sumData).Error; err != nil { return nil, err } resp := &ErpRepairDetailReportResp{ Total: int(total), PageIndex: req.PageIndex, PageSize: req.PageSize, List: records, SumData: sumData, } // 处理导出逻辑 if req.IsExport == 1 { exportUrl, err := ExportRepairDetailExcel(records, sumData) if err != nil { return nil, err } resp.ExportUrl = exportUrl resp.List = nil } return resp, nil } func buildRepairDetailQuery(base *gorm.DB, req *ErpRepairDetailReportReq) *gorm.DB { if req.SerialNumber != "" { base = base.Where("rr.serial_number = ?", req.SerialNumber) } if req.Uid > 0 { base = base.Where("rr.uid = ?", req.Uid) } if req.Tel != "" { base = base.Where("rr.tel = ?", req.Tel) } if req.MemberLevel > 0 { base = base.Where("rr.member_level = ?", req.MemberLevel) } if len(req.StoreId) > 0 { base = base.Where("rr.store_id IN (?)", req.StoreId) } if req.HandlerId > 0 { base = base.Where("rr.handler_id = ?", req.HandlerId) } //if len(req.State) > 0 { // base = base.Where("rr.state IN (?)", req.State) //} if req.RepairUnitId > 0 { base = base.Where("rr.repair_unit_id = ?", req.RepairUnitId) } if req.MakeTimeStart != "" && req.MakeTimeEnd != "" { base = base.Where("rr.maker_time BETWEEN ? AND ?", req.MakeTimeStart, req.MakeTimeEnd) } if req.AuditTimeStart != "" && req.AuditTimeEnd != "" { base = base.Where("rr.audit_time BETWEEN ? AND ?", req.AuditTimeStart, req.AuditTimeEnd) } if req.SendTimeStart != "" && req.SendTimeEnd != "" { base = base.Where("rr.send_time BETWEEN ? AND ?", req.SendTimeStart, req.SendTimeEnd) } if req.CompleteTimeStart != "" && req.CompleteTimeEnd != "" { base = base.Where("rr.completed_time BETWEEN ? AND ?", req.CompleteTimeStart, req.CompleteTimeEnd) } return base } // ExportRepairDetailExcel 导出维修明细报表excel func ExportRepairDetailExcel(list []RepairRecord, sumData RepairDetailTotalData) (string, error) { file := excelize.NewFile() sheet := "Sheet1" url := config.ExportConfig.Url fileName := time.Now().Format(TimeFormat) + "维修明细.xlsx" savePath := config.ExportConfig.Path + fileName fmt.Println("生成路径:", url+fileName) storeMap, err := GetAllStoreData() if err != nil { return "", err } // 表头 title := []interface{}{ "维修单号", "门店", "用户ID", "联系电话", "会员等级", "状态", "制单人", "制单时间", "审核人", "审核时间", "送修时间", "送修备注", "邮寄方式", "快递单号", "快递费用", "维修单位", "维修费用", "完成时间", "完成备注", "商品名称", "旧机器编码", "新机器编码", "数量", "故障描述", } // 写表头 for i, v := range title { cell, _ := excelize.CoordinatesToCellName(i+1, 1) _ = file.SetCellValue(sheet, cell, v) } rowIndex := 2 for _, record := range list { memberLevelStr := GetUserTypeString(int(record.MemberLevel)) stateMap := map[uint8]string{ 1: "待审核", 2: "待送修", 3: "维修中", 4: "已完成", } stateStr := stateMap[record.State] sendTypeStr := map[uint8]string{ 1: "个人", 2: "门店", }[record.ExpressType] nFlag := 0 for _, comm := range record.Commodities { var row []interface{} if nFlag >= 1 { row = []interface{}{ record.SerialNumber, storeMap[record.StoreId].Name, record.Uid, record.Tel, memberLevelStr, stateStr, record.MakerName, formatDateTime(record.MakerTime), record.AuditorName, formatTime(record.AuditTime), formatTime(record.SendTime), record.SendRemark, sendTypeStr, record.ExpressNo, "", record.RepairUnitName, "", formatTime(record.CompletedTime), record.CompleteRemark, comm.CommodityName, comm.OldIMEI, comm.NewIMEI, comm.Count, comm.FaultDesc, } } else { row = []interface{}{ record.SerialNumber, storeMap[record.StoreId].Name, record.Uid, record.Tel, memberLevelStr, stateStr, record.MakerName, formatDateTime(record.MakerTime), record.AuditorName, formatTime(record.AuditTime), formatTime(record.SendTime), record.SendRemark, sendTypeStr, record.ExpressNo, record.ExpressFee, record.RepairUnitName, record.RepairFee, formatTime(record.CompletedTime), record.CompleteRemark, comm.CommodityName, comm.OldIMEI, comm.NewIMEI, comm.Count, comm.FaultDesc, } } for j, val := range row { cell, _ := excelize.CoordinatesToCellName(j+1, rowIndex) _ = file.SetCellValue(sheet, cell, val) } rowIndex++ nFlag++ } } // 汇总行 summary := []interface{}{ fmt.Sprintf("维修单数: %d", len(list)), "", "", "", "", "", "", "", "", "", "", "", "", "", sumData.TotalExpressFee, "", sumData.TotalRepairFee, } for i, val := range summary { cell, _ := excelize.CoordinatesToCellName(i+1, rowIndex) _ = file.SetCellValue(sheet, cell, val) } // 设置样式 style, _ := file.NewStyle(`{ "alignment":{"horizontal":"center","vertical":"center"}, "border":[ {"type":"left","color":"000000","style":1}, {"type":"top","color":"000000","style":1}, {"type":"right","color":"000000","style":1}, {"type":"bottom","color":"000000","style":1} ] }`) lastCol, _ := excelize.ColumnNumberToName(len(title)) endCell := fmt.Sprintf("%s%d", lastCol, rowIndex) _ = file.SetCellStyle(sheet, "A1", endCell, style) // 设置列宽(根据字段名称微调) file.SetColWidth(sheet, "A", "A", 18) file.SetColWidth(sheet, "B", "B", 25) file.SetColWidth(sheet, "C", "C", 10) file.SetColWidth(sheet, "D", "D", 15) file.SetColWidth(sheet, "E", "E", 15) file.SetColWidth(sheet, "J", "J", 18) file.SetColWidth(sheet, "K", "K", 18) file.SetColWidth(sheet, "N", "N", 20) file.SetColWidth(sheet, "S", "S", 18) file.SetColWidth(sheet, "T", "T", 25) file.SetColWidth(sheet, "X", "X", 30) // 保存 if err := file.SaveAs(savePath); err != nil { logger.Error("保存文件失败:", logger.Field("err", err)) return "", err } return url + fileName, nil } // formatTime 格式化时间为空判断 func formatTime(t *time.Time) string { if t == nil { return "" } return t.Format("2006-01-02 15:04:05") } // formatDateTime 格式化时间为空判断(仅保留日期) func formatDateTime(t *time.Time) string { if t == nil { return "" } return t.Format("2006-01-02") }