1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738 |
- // 导入导出功能
- package api
- import (
- "archive/zip"
- "bytes"
- "fmt"
- "io"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "sku3dweb/db/model"
- "sku3dweb/db/repo"
- "sku3dweb/log"
- "strconv"
- "strings"
- "time"
- "github.com/gin-gonic/gin"
- excelize "github.com/xuri/excelize/v2"
- "go.mongodb.org/mongo-driver/bson/primitive"
- "github.com/aliyun/aliyun-oss-go-sdk/oss"
- )
- // 固定Excel模板表头
- var fixedHeaders = []string{
- "公司商品编号", "商品中文名", "商品英文名", "分类", "图片",
- "单位包材毛重(KG)", "单位包材体积(CBM)", "长度(MM)", "门幅/宽(MM)", "厚度/高(MM)",
- "备注", "首选供应商", "默认采购单价", "样品搜集人编号", "样品搜集人", "开发日期",
- // "出口属性", "内销属性", "内购属性", "委外属性", 2025-4-29沟通去掉这几个属性
- "报关助记符", "报关商品编码", "报关商品中文名", "录入人名称", "适合的市场",
- "供应商编号", "种类分类", "种类分类名称", "基布", "基布名称",
- "表面工艺", "表面工艺名称", "产品克重(KG)", "运营周期", "商品单位体积",
- "商品分类代码", "产品系列", "产品系列", "产品用途", "产品用途",
- "样品编号", "留样册号", "原命名编号", "底布克重", "面布克重",
- // "原始大图", "封面图", "商品图片",
- }
- func RegExcelRouter(router *GinRouter) {
- // router.POSTJWT("/excel/import", ExcelImport)
- // router.GETJWT("/excel/export", ExcelExport)
- router.POSTJWT("/zip/import", ZipImport)
- router.POSTJWT("/zip/export", ZipExport)
- }
- func ParseMatObject(ctx *repo.RepoSession, row []string, headers []string, cates []*model.Category) (model.MatImage, error) {
- imageMat := model.MatImage{}
- // 构建基础数据
- imageMat.CusNum = row[0]
- imageMat.NameCN = row[1]
- imageMat.NameEN = row[2]
- //1.商品编号
- CusNumIndex := -1
- for i, header := range headers {
- if header == "公司商品编号" {
- CusNumIndex = i
- break
- }
- }
- if CusNumIndex == -1 {
- return imageMat, fmt.Errorf("公司商品编号列未找到")
- }
- imageMat.CusNum = row[CusNumIndex]
- //2中文名称
- NameCNIndex := -1
- for i, header := range headers {
- if header == "商品中文名" {
- NameCNIndex = i
- break
- }
- }
- if NameCNIndex == -1 {
- return imageMat, fmt.Errorf("商品中文名列未找到")
- }
- imageMat.NameCN = row[NameCNIndex]
- //3英文名称
- NameENIndex := -1
- for i, header := range headers {
- if header == "商品英文名" {
- NameENIndex = i
- break
- }
- }
- if NameENIndex == -1 {
- return imageMat, fmt.Errorf("商品英文名列未找到")
- }
- imageMat.NameEN = row[NameENIndex]
- //4.商品分类
- CategoryIndex := -1
- for i, header := range headers {
- if header == "分类" {
- CategoryIndex = i
- break
- }
- }
- if CategoryIndex == -1 {
- return imageMat, fmt.Errorf("分类列未找到")
- }
- //imageMat.Categories = append(imageMat.Categories, row[CategoryIndex])
- // 根据分类层级一的名字获取对应id,遍历一层获取对应数据
- rootCate := &model.Category{}
- for _, cate := range cates {
- if cate.Name == "商品分类" {
- for _, c := range cate.Children {
- if c.Name == row[CategoryIndex] {
- // 记录该分类为其他自动做准备
- rootCate = c
- break
- }
- }
- break
- }
- }
- if len(rootCate.IdStr) <= 0 {
- return imageMat, fmt.Errorf("%s的商品分类未找到定义", row[CategoryIndex])
- }
- // 获取rootCate下的二级分类
- var getRootCate2 = func(rootCate *model.Category, pName string, name string, cusNum string) *model.Category {
- for _, cate := range rootCate.Children {
- if cate.Name == pName {
- for _, c := range cate.Children {
- if c.Name == name {
- if len(cusNum) > 0 {
- if c.CusNum == cusNum {
- return c
- }
- return nil
- }
- return c
- }
- }
- }
- }
- return nil
- }
- //分类rootId
- imageMat.Categories = append(imageMat.Categories, rootCate.IdStr)
- //5 单位包材毛重(KG)
- PackageGrossWeightIndex := -1
- for i, header := range headers {
- if header == "单位包材毛重(KG)" {
- PackageGrossWeightIndex = i
- break
- }
- }
- if PackageGrossWeightIndex == -1 {
- return imageMat, fmt.Errorf("单位包材毛重(KG)列未找到")
- }
- var str2float64 = func(s string) *float64 {
- if len(s) == 0 {
- return nil
- }
- f := 0.0
- f, err := strconv.ParseFloat(s, 64)
- if err != nil {
- log.Errorf("解析浮点数失败: %v", err)
- return &f // 或 math.NaN() 表示无效值
- }
- return &f
- }
- row5 := str2float64(row[PackageGrossWeightIndex])
- imageMat.PackageGrossWeight = row5
- //6.单位包材体积(CBM)
- PackageVolumeIndex := -1
- for i, header := range headers {
- if header == "单位包材体积(CBM)" {
- PackageVolumeIndex = i
- break
- }
- }
- if PackageVolumeIndex == -1 {
- return imageMat, fmt.Errorf("单位包材体积(CBM)列未找到")
- }
- row6 := str2float64(row[PackageVolumeIndex])
- imageMat.PackageVolume = row6
- //7.长度(MM)
- PhyHeightIndex := -1
- for i, header := range headers {
- if header == "长度(MM)" {
- PhyHeightIndex = i
- break
- }
- }
- if PhyHeightIndex == -1 {
- return imageMat, fmt.Errorf("长度(MM)列未找到")
- }
- row7 := str2float64(row[PhyHeightIndex])
- imageMat.PhyHeight = row7
- //8.门幅/宽(MM)
- PhyWidthIndex := -1
- for i, header := range headers {
- if header == "门幅/宽(MM)" {
- PhyWidthIndex = i
- break
- }
- }
- if PhyWidthIndex == -1 {
- return imageMat, fmt.Errorf("门幅/宽(MM)列未找到")
- }
- row8 := str2float64(row[PhyWidthIndex])
- imageMat.PhyWidth = row8
- //9.厚度/高(MM)
- ThicknessIndex := -1
- for i, header := range headers {
- if header == "厚度/高(MM)" {
- ThicknessIndex = i
- break
- }
- }
- if ThicknessIndex == -1 {
- return imageMat, fmt.Errorf("厚度/高(MM)列未找到")
- }
- row9 := str2float64(row[ThicknessIndex])
- imageMat.Thickness = row9
- //10.备注
- RemarksIndex := -1
- for i, header := range headers {
- if header == "备注" {
- RemarksIndex = i
- break
- }
- }
- if RemarksIndex == -1 {
- return imageMat, fmt.Errorf("备注列未找到")
- }
- imageMat.Remarks = row[RemarksIndex]
- //11.首选供应商
- MainSupplierIndex := -1
- for i, header := range headers {
- if header == "首选供应商" {
- MainSupplierIndex = i
- break
- }
- }
- if MainSupplierIndex == -1 {
- return imageMat, fmt.Errorf("首选供应商列未找到")
- }
- row11Cate := &model.Category{}
- for _, cate := range cates {
- if cate.Name == "首选供应商" {
- for _, c := range cate.Children {
- if c.Name == row[MainSupplierIndex] {
- // 记录该分类为其他自动做准备
- row11Cate = c
- break
- }
- }
- break
- }
- }
- if len(row11Cate.IdStr) <= 0 {
- oid := primitive.NewObjectID()
- super := &model.Category{
- Id: oid,
- Name: row[MainSupplierIndex],
- IdStr: oid.Hex(),
- CusNum: "0000",
- Children: []*model.Category{},
- }
- for _, cate := range cates {
- if cate.Name == "首选供应商" {
- cate.Children = append(cate.Children, super)
- break
- }
- }
- row11Cate = super
- }
- //添加首先供应商
- imageMat.Categories = append(imageMat.Categories, row11Cate.IdStr)
- //12.默认采购单价
- PriceIndex := -1
- for i, header := range headers {
- if header == "默认采购单价" {
- PriceIndex = i
- break
- }
- }
- if PriceIndex == -1 {
- return imageMat, fmt.Errorf("默认采购单价列未找到")
- }
- row12 := str2float64(row[PriceIndex])
- imageMat.Price = row12
- //13.样品搜集人
- FromIndex := -1
- for i, header := range headers {
- if header == "样品搜集人" {
- FromIndex = i
- if i+1 < len(headers) && headers[i+1] == "样品搜集人" {
- FromIndex = i + 1
- }
- break
- }
- }
- if FromIndex == -1 {
- return imageMat, fmt.Errorf("样品搜集人列未找到")
- }
- staffName := row[FromIndex]
- if len(staffName) > 0 {
- staff := model.StaffUser{}
- // 验证样品收集人是否预设
- found, _ := repo.RepoSeachDoc(ctx, &repo.DocSearchOptions{
- CollectName: repo.CollectionStaffUser,
- Query: repo.Map{"name": staffName},
- }, &staff)
- if found {
- imageMat.From = staffName
- } else {
- return imageMat, fmt.Errorf("样品搜集人未配置")
- }
- }
- //14.开发日期
- DevTimeIndex := -1
- for i, header := range headers {
- if header == "开发日期" {
- DevTimeIndex = i
- break
- }
- }
- if DevTimeIndex == -1 {
- return imageMat, fmt.Errorf("开发日期列未找到")
- }
- if len(row[DevTimeIndex]) > 0 {
- layout := "2006/1/2"
- // 解析字符串
- devTime, _ := time.Parse(layout, row[DevTimeIndex])
- imageMat.DevTime = &devTime
- }
- //15.出口属性
- ExportPropertyIndex := -1
- for i, header := range headers {
- if header == "出口属性" {
- ExportPropertyIndex = i
- break
- }
- }
- if ExportPropertyIndex == -1 {
- return imageMat, fmt.Errorf("出口属性列未找到")
- }
- row15 := str2bool(row[ExportPropertyIndex])
- imageMat.ExportProperty = row15
- //16.内销属性
- DomesticPropertyIndex := -1
- for i, header := range headers {
- if header == "内销属性" {
- DomesticPropertyIndex = i
- break
- }
- }
- if DomesticPropertyIndex == -1 {
- return imageMat, fmt.Errorf("内销属性列未找到")
- }
- row16 := str2bool(row[DomesticPropertyIndex])
- imageMat.DomesticProperty = row16
- //17.内购属性
- InpurchasePropertyIndex := -1
- for i, header := range headers {
- if header == "内购属性" {
- InpurchasePropertyIndex = i
- break
- }
- }
- if InpurchasePropertyIndex == -1 {
- return imageMat, fmt.Errorf("内购属性列未找到")
- }
- row17 := str2bool(row[InpurchasePropertyIndex])
- imageMat.InpurchaseProperty = row17
- //18.委外属性
- OutsourcedPropertyIndex := -1
- for i, header := range headers {
- if header == "委外属性" {
- OutsourcedPropertyIndex = i
- break
- }
- }
- if OutsourcedPropertyIndex == -1 {
- return imageMat, fmt.Errorf("委外属性列未找到")
- }
- row18 := str2bool(row[OutsourcedPropertyIndex])
- imageMat.OutsourcedProperty = row18
- //19.报关助记符
- MnemonicSignIndex := -1
- for i, header := range headers {
- if header == "报关商品编码" {
- MnemonicSignIndex = i
- break
- }
- }
- TaxNameCNIndex := -1
- for i, header := range headers {
- if header == "报关商品中文名" {
- TaxNameCNIndex = i
- break
- }
- }
- if MnemonicSignIndex == -1 {
- return imageMat, fmt.Errorf("报关商品编码列未找到")
- }
- if TaxNameCNIndex != -1 && len(row[TaxNameCNIndex]) > 0 {
- imageMat.TaxNameCN = row[TaxNameCNIndex]
- row15Cate := &model.Category{}
- for _, cate := range cates {
- if cate.Name == "报关助记符" {
- for _, c := range cate.Children {
- if c.Name == row[TaxNameCNIndex] {
- row15Cate = c
- break
- }
- }
- break
- }
- }
- if len(row15Cate.IdStr) <= 0 {
- return imageMat, fmt.Errorf("%s的报关助记符未找到定义", row[TaxNameCNIndex])
- }
- imageMat.Categories = append(imageMat.Categories, row15Cate.IdStr)
- }
- //21.录入人名称
- RecordUserIndex := -1
- for i, header := range headers {
- if header == "录入人名称" {
- RecordUserIndex = i
- break
- }
- }
- if RecordUserIndex == -1 {
- return imageMat, fmt.Errorf("录入人名称列未找到")
- }
- imageMat.RecordUser = row[RecordUserIndex]
- //22.适合的市场
- FitMarketIndex := -1
- for i, header := range headers {
- if header == "适合的市场" {
- FitMarketIndex = i
- break
- }
- }
- if FitMarketIndex == -1 {
- return imageMat, fmt.Errorf("适合的市场列未找到")
- }
- imageMat.FitMarket = row[FitMarketIndex]
- //23.种类分类
- TypeCategoryIndex := -1
- for i, header := range headers {
- if header == "种类分类" {
- TypeCategoryIndex = i
- break
- }
- }
- if TypeCategoryIndex == -1 {
- return imageMat, fmt.Errorf("种类分类列未找到")
- }
- //24.种类分类名称
- TypeCategoryNameIndex := -1
- for i, header := range headers {
- if header == "种类分类名称" {
- TypeCategoryNameIndex = i
- break
- }
- }
- if TypeCategoryNameIndex == -1 {
- return imageMat, fmt.Errorf("种类分类名称列未找到")
- }
- typeCate := row[TypeCategoryIndex]
- typeCateName := row[TypeCategoryNameIndex]
- typeCateObj := getRootCate2(rootCate, "种类分类", typeCateName, typeCate)
- if typeCateObj == nil {
- return imageMat, fmt.Errorf("%s / %s 的种类分类未找到定义", typeCate, typeCateName)
- }
- imageMat.Categories = append(imageMat.Categories, typeCateObj.IdStr)
- //25.基布
- BaseClothIndex := -1
- for i, header := range headers {
- if header == "基布" {
- BaseClothIndex = i
- break
- }
- }
- if BaseClothIndex == -1 {
- return imageMat, fmt.Errorf("基布列未找到")
- }
- //26.基布名称
- BaseClothNameIndex := -1
- for i, header := range headers {
- if header == "基布名称" {
- BaseClothNameIndex = i
- break
- }
- }
- if BaseClothNameIndex == -1 {
- return imageMat, fmt.Errorf("基布名称列未找到")
- }
- baseCloth := row[BaseClothIndex]
- baseClothName := row[BaseClothNameIndex]
- baseClothObj := getRootCate2(rootCate, "基布", baseClothName, baseCloth)
- if baseClothObj == nil {
- return imageMat, fmt.Errorf("%s / %s 的基布未找到定义", baseCloth, baseClothName)
- }
- imageMat.Categories = append(imageMat.Categories, baseClothObj.IdStr)
- //27.表面工艺
- SurfaceProcessIndex := -1
- for i, header := range headers {
- if header == "表面工艺" {
- SurfaceProcessIndex = i
- break
- }
- }
- if SurfaceProcessIndex == -1 {
- return imageMat, fmt.Errorf("表面工艺列未找到")
- }
- //28.表面工艺名称
- SurfaceProcessNameIndex := -1
- for i, header := range headers {
- if header == "表面工艺名称" {
- SurfaceProcessNameIndex = i
- break
- }
- }
- if SurfaceProcessNameIndex == -1 {
- return imageMat, fmt.Errorf("表面工艺名称列未找到")
- }
- surfaceProcess := row[SurfaceProcessIndex]
- surfaceProcessName := row[SurfaceProcessNameIndex]
- surfaceProcessObj := getRootCate2(rootCate, "表面工艺", surfaceProcessName, surfaceProcess)
- if surfaceProcessObj == nil {
- return imageMat, fmt.Errorf("%s / %s 的表面工艺未找到定义", surfaceProcess, surfaceProcessName)
- }
- imageMat.Categories = append(imageMat.Categories, surfaceProcessObj.IdStr)
- //29.产品克重(KG)
- ProductWeightIndex := -1
- for i, header := range headers {
- if header == "产品克重(KG)" {
- ProductWeightIndex = i
- break
- }
- }
- if ProductWeightIndex == -1 {
- return imageMat, fmt.Errorf("产品克重(KG)列未找到")
- }
- pw := str2float64(row[ProductWeightIndex])
- imageMat.ProductWeight = pw
- //30.运营周期
- OperationCycleIndex := -1
- for i, header := range headers {
- if header == "运营周期" {
- OperationCycleIndex = i
- break
- }
- }
- if OperationCycleIndex == -1 {
- return imageMat, fmt.Errorf("运营周期列未找到")
- }
- imageMat.OperationCycle = row[OperationCycleIndex]
- //31.商品单位体积
- ProductVolumeIndex := -1
- for i, header := range headers {
- if header == "商品单位体积" {
- ProductVolumeIndex = i
- break
- }
- }
- if ProductVolumeIndex == -1 {
- return imageMat, fmt.Errorf("商品单位体积列未找到")
- }
- pv := str2float64(row[ProductVolumeIndex])
- imageMat.ProductVolume = pv
- //32.商品分类代码
- // ProductCategoryIndex := -1
- // for i, header := range headers {
- // if header == "商品分类代码" {
- // ProductCategoryIndex = i
- // break
- // }
- // }
- // if ProductCategoryIndex == -1 {
- // return imageMat, fmt.Errorf("商品分类代码列未找到")
- // }
- // imageMat.ProductCategory = row[ProductCategoryIndex]
- //33.产品系列
- ProductSeriesIndex := -1
- ProductSeriesCodeIndex := -1
- for i, header := range headers {
- if header == "产品系列" {
- ProductSeriesIndex = i
- ProductSeriesCodeIndex = i
- if i+1 < len(headers) && headers[i+1] == "产品系列" {
- ProductSeriesIndex = i + 1
- }
- break
- }
- }
- if ProductSeriesIndex == -1 {
- return imageMat, fmt.Errorf("产品系列列未找到")
- }
- imageMat.ProductSeries = row[ProductSeriesIndex]
- if ProductSeriesCodeIndex == -1 {
- return imageMat, fmt.Errorf("产品系列代码列未找到")
- }
- productSeriesCode := row[ProductSeriesCodeIndex]
- productSeriesCodeName := row[ProductSeriesCodeIndex+1]
- productSeriesCodeObj := getRootCate2(rootCate, "产品系列", productSeriesCodeName, productSeriesCode)
- if productSeriesCodeObj == nil {
- return imageMat, fmt.Errorf("%s / %s 的产品系列代码未找到定义", productSeriesCode, productSeriesCodeName)
- }
- imageMat.Categories = append(imageMat.Categories, productSeriesCodeObj.IdStr)
- //35.产品用途
- ProductUsageIndex := -1
- ProductUsageNameIndex := -1
- for i, header := range headers {
- if header == "产品用途" {
- ProductUsageIndex = i
- if i+1 < len(headers) && headers[i+1] == "产品用途" {
- ProductUsageNameIndex = i + 1
- }
- break
- }
- }
- if ProductUsageIndex == -1 {
- return imageMat, fmt.Errorf("产品用途列未找到")
- }
- if ProductUsageNameIndex == -1 {
- return imageMat, fmt.Errorf("产品用途名称列未找到")
- }
- imageMat.ProductUsage = row[ProductUsageIndex]
- ProductUsageCode := row[ProductUsageIndex]
- ProductUsageCodeName := row[ProductUsageNameIndex]
- ProductUsageObj := getRootCate2(rootCate, "产品用途", ProductUsageCodeName, ProductUsageCode)
- if ProductUsageObj == nil {
- return imageMat, fmt.Errorf("%s / %s 产品用途未找到定义", ProductUsageCode, ProductUsageCodeName)
- }
- imageMat.Categories = append(imageMat.Categories, ProductUsageObj.IdStr)
- //36.原命名编号
- OriginalNumberIndex := -1
- for i, header := range headers {
- if header == "原命名编号" {
- OriginalNumberIndex = i
- break
- }
- }
- if OriginalNumberIndex == -1 {
- return imageMat, fmt.Errorf("原命名编号列未找到")
- }
- imageMat.OriginalNumber = row[OriginalNumberIndex]
- //37.底布克重
- BackingWeightIndex := -1
- for i, header := range headers {
- if header == "底布克重" {
- BackingWeightIndex = i
- break
- }
- }
- if BackingWeightIndex == -1 {
- return imageMat, fmt.Errorf("底布克重列未找到")
- }
- bw := str2float64(row[BackingWeightIndex])
- imageMat.BackingWeight = bw
- //38.面布克重
- SurfaceWeightIndex := -1
- for i, header := range headers {
- if header == "面布克重" {
- SurfaceWeightIndex = i
- break
- }
- }
- if SurfaceWeightIndex == -1 {
- return imageMat, fmt.Errorf("面布克重列未找到")
- }
- sw := str2float64(row[SurfaceWeightIndex])
- imageMat.SurfaceWeight = sw
- return imageMat, nil
- }
- func str2bool(s string) *bool {
- s = strings.TrimSpace(strings.ToLower(s))
- if s == "true" || s == "1" || s == "yes" || s == "y" {
- return BoolValue(true)
- } else if s == "false" || s == "0" || s == "no" || s == "n" || s == "" {
- return BoolValue(false)
- }
- return nil
- }
- func ExcelImportWithImages(c *gin.Context, apictx *ApiSession, file io.Reader, goodsDir, textureDir string) (interface{}, error) {
- // 读取Excel文件
- xlsx, err := excelize.OpenReader(file)
- if err != nil {
- fmt.Println(err.Error())
- return nil, NewError("解析Excel文件失败")
- }
- defer func() {
- if err := xlsx.Close(); err != nil {
- log.Errorf("关闭Excel文件失败: %v", err)
- }
- }()
- // 获取第一个sheet
- sheetName := xlsx.GetSheetName(0)
- rows, err := xlsx.GetRows(sheetName)
- if err != nil {
- return nil, NewError("读取Excel内容失败")
- }
- // 确保至少有表头和一行数据
- if len(rows) < 2 {
- return nil, NewError("Excel文件内容不足")
- }
- // 预热云函数
- _, _ = QueryFassiImage("http://lymat.oss-cn-hangzhou.aliyuncs.com/images/1744072972845.png", 1, 0, 0)
- // 获取分类配置
- cat := []*model.Category{}
- err = repo.RepoSeachDocs(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
- CollectName: repo.CollectionCategory,
- Query: repo.Map{},
- Project: []string{"name", "type", "children", "createTime"},
- }, &cat)
- if err != nil {
- return nil, NewError("获取分类配置失败")
- }
- cates := cat[0].Children
- // 创建导入结果记录
- type ImportResult struct {
- RowIndex int
- Status string // "成功" 或 "失败"
- ErrorMessage string
- ImageID string
- }
- importResults := make([]ImportResult, 0, len(rows)-1)
- headers := rows[0]
- // 根据模板解析每列数据
- for i, row := range rows {
- // 跳过表头
- if i == 0 {
- continue
- }
- // 创建导入结果记录
- result := ImportResult{
- RowIndex: i,
- Status: "成功",
- }
- imageMat, err := ParseMatObject(apictx.CreateRepoCtx(), row, headers, cates)
- if err != nil {
- result.Status = "失败"
- result.ErrorMessage = err.Error()
- fmt.Println(result.ErrorMessage)
- importResults = append(importResults, result)
- continue
- }
- imageName := row[0] // 不包含后缀 .jpg .png .jpeg
- // 根据图片名称检查goods和texture中是否存在,图片可能是.jpg .png .jpeg后缀
- // 上传图片到oss 获取对应url,赋值到imageMat(Thumbnail, RawImage, ProductImage)
- // 在goods目录中查找图片
- goodsImagePath := findImageFile(goodsDir, imageName)
- textureImagePath := findImageFile(textureDir, imageName)
- // 如果找到了图片,上传到OSS
- if goodsImagePath != "" {
- // 上传原始图片作为RawImage
- goodsImage, err := uploadLocalImage(goodsImagePath, "goods", apictx)
- if err != nil {
- log.Errorf("上传图片失败: %v", err)
- } else {
- imageMat.ProductImage = goodsImage
- }
- }
- if textureImagePath != "" {
- // 上传原始图片作为RawImage
- textureImage, err := uploadLocalImage(textureImagePath, "texture", apictx)
- if err != nil {
- log.Errorf("上传图片失败: %v", err)
- } else {
- imageMat.RawImage = textureImage
- imageMat.Thumbnail = textureImage
- }
- }
- // 设置创建时间
- imageMat.CreateTime = time.Now()
- imageMat.UpdateTime = time.Now()
- // 写入到数据库中并获取创建记录的数据库id
- imgId, err := repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionMatImages, &imageMat)
- if err != nil {
- log.Errorf("写入记录失败: %v", err)
- result.Status = "失败"
- result.ErrorMessage = "数据库写入失败: " + err.Error()
- importResults = append(importResults, result)
- continue
- }
- result.ImageID = imgId
- // 如果texture存在,调用AddFassiImage创建图片特征和id的关联
- if textureImagePath != "" && imageMat.RawImage != nil {
- objId, err := primitive.ObjectIDFromHex(imgId)
- if err != nil {
- log.Errorf("转换ID失败: %v", err)
- } else {
- err = AddFassiImage(objId, imageMat.RawImage.Url)
- if err != nil {
- log.Errorf("创建Fassi图片关联失败: %v", err)
- }
- }
- }
- importResults = append(importResults, result)
- }
- // 创建一个新的Excel文件用于导出结果
- resultExcel := excelize.NewFile()
- sheet := "Sheet1"
- // 复制原始表头并添加状态列
- headers2 := append(rows[0], "导入状态", "失败原因", "数据库ID")
- for i, header := range headers2 {
- colName := columnIndexToName(i)
- resultExcel.SetCellValue(sheet, colName+"1", header)
- }
- // 写入每行数据和导入结果
- for i, row := range rows {
- if i == 0 {
- continue // 跳过表头
- }
- // 查找对应的导入结果
- var result ImportResult
- for _, r := range importResults {
- if r.RowIndex == i {
- result = r
- break
- }
- }
- // 写入原始数据
- for j, cell := range row {
- colName := columnIndexToName(j)
- resultExcel.SetCellValue(sheet, colName+strconv.Itoa(i+1), cell)
- }
- // 添加状态和错误信息
- statusCol := columnIndexToName(len(row))
- errorCol := columnIndexToName(len(row) + 1)
- idCol := columnIndexToName(len(row) + 2)
- resultExcel.SetCellValue(sheet, statusCol+strconv.Itoa(i+1), result.Status)
- resultExcel.SetCellValue(sheet, errorCol+strconv.Itoa(i+1), result.ErrorMessage)
- resultExcel.SetCellValue(sheet, idCol+strconv.Itoa(i+1), result.ImageID)
- }
- // 设置列宽
- for i := range headers2 {
- colName := columnIndexToName(i)
- resultExcel.SetColWidth(sheet, colName, colName, 15)
- }
- // 保存到内存缓冲区
- buffer := bytes.Buffer{}
- if err := resultExcel.Write(&buffer); err != nil {
- return nil, NewError("生成导入结果文件失败")
- }
- // 设置响应头,使浏览器下载文件
- fileName := "import_result_" + time.Now().Format("20060102150405") + ".xlsx"
- c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))
- c.Writer.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
- c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
- c.Writer.Write(buffer.Bytes())
- return nil, nil
- // 统计导入结果
- // successCount := 0
- // failCount := 0
- // partialCount := 0
- // for _, result := range importResults {
- // switch result.Status {
- // case "成功":
- // successCount++
- // case "失败":
- // failCount++
- // case "部分成功":
- // partialCount++
- // }
- // }
- // return map[string]interface{}{
- // "total": len(importResults),
- // "success": successCount,
- // "failed": failCount,
- // "partial": partialCount,
- // }, nil
- }
- // 新增ZIP文件导入处理函数
- func ZipImport(c *gin.Context, apictx *ApiSession) (interface{}, error) {
- // 获取上传的文件
- file, header, err := c.Request.FormFile("file")
- if err != nil {
- return nil, NewError("获取上传文件失败")
- }
- defer file.Close()
- // 检查文件大小
- if header.Size > 500*1024*1024 { // 限制100MB
- return nil, NewError("上传文件过大,请控制在500MB以内")
- }
- // 检查文件扩展名
- if !strings.HasSuffix(strings.ToLower(header.Filename), ".zip") {
- return nil, NewError("只支持上传ZIP格式的文件")
- }
- // 创建临时目录存放解压文件
- tempDir, err := os.MkdirTemp("", "sku3d_import_"+time.Now().Format("20060102150405"))
- if err != nil {
- return nil, NewError("创建临时目录失败")
- }
- defer os.RemoveAll(tempDir) // 确保处理完成后删除临时目录
- // 创建goods和texture子目录
- goodsDir := filepath.Join(tempDir, "goods")
- textureDir := filepath.Join(tempDir, "texture")
- if err := os.Mkdir(goodsDir, 0755); err != nil {
- return nil, NewError("创建goods目录失败")
- }
- if err := os.Mkdir(textureDir, 0755); err != nil {
- return nil, NewError("创建texture目录失败")
- }
- // 保存上传的ZIP文件
- zipFilePath := path.Join(tempDir, "upload.zip")
- tempZipFile, err := os.Create(zipFilePath)
- if err != nil {
- return nil, NewError("创建临时文件失败")
- }
- // 将上传的文件内容写入临时文件
- _, err = io.Copy(tempZipFile, file)
- tempZipFile.Close()
- if err != nil {
- return nil, NewError("保存上传文件失败")
- }
- // 解压ZIP文件
- extractDir := path.Join(tempDir, "extract")
- err = os.MkdirAll(extractDir, 0755)
- if err != nil {
- return nil, NewError("创建解压目录失败")
- }
- err = unzipFile(zipFilePath, extractDir)
- if err != nil {
- return nil, NewError("解压文件失败: " + err.Error())
- }
- // 查找Excel文件
- excelFilePath, err := findExcelFile(extractDir)
- if err != nil {
- return nil, NewError("未找到有效的Excel文件: " + err.Error())
- }
- // 打开Excel文件
- excelFile, err := os.Open(excelFilePath)
- if err != nil {
- return nil, NewError("打开Excel文件失败")
- }
- defer excelFile.Close()
- // 商品图片目录和纹理图片目录
- goodsDir = path.Join(extractDir, "goods")
- textureDir = path.Join(extractDir, "texture")
- // 检查目录是否存在
- if _, err := os.Stat(goodsDir); os.IsNotExist(err) {
- log.Errorf("商品图片目录不存在: %s", goodsDir)
- goodsDir = ""
- }
- if _, err := os.Stat(textureDir); os.IsNotExist(err) {
- log.Errorf("纹理图片目录不存在: %s", textureDir)
- textureDir = ""
- }
- // 传递给Excel导入函数处理,并指定图片目录
- return ExcelImportWithImages(c, apictx, excelFile, goodsDir, textureDir)
- }
- // 解压ZIP文件到指定目录
- func unzipFile(zipFile, destDir string) error {
- r, err := zip.OpenReader(zipFile)
- if err != nil {
- return err
- }
- defer r.Close()
- for _, f := range r.File {
- // 处理路径安全问题
- filePath := filepath.Join(destDir, f.Name)
- if !strings.HasPrefix(filePath, filepath.Clean(destDir)+string(os.PathSeparator)) {
- return fmt.Errorf("非法的ZIP文件路径: %s", f.Name)
- }
- if f.FileInfo().IsDir() {
- // 创建目录
- if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
- return err
- }
- continue
- }
- // 确保父目录存在
- if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
- return err
- }
- // 创建文件
- outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
- if err != nil {
- return err
- }
- // 打开压缩文件
- rc, err := f.Open()
- if err != nil {
- outFile.Close()
- return err
- }
- // 复制内容
- _, err = io.Copy(outFile, rc)
- outFile.Close()
- rc.Close()
- if err != nil {
- return err
- }
- }
- return nil
- }
- // 寻找目录中的Excel文件
- func findExcelFile(dir string) (string, error) {
- var excelFiles []string
- err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !info.IsDir() {
- lowerPath := strings.ToLower(path)
- if strings.HasSuffix(lowerPath, ".xlsx") || strings.HasSuffix(lowerPath, ".xls") {
- excelFiles = append(excelFiles, path)
- }
- }
- return nil
- })
- if err != nil {
- return "", err
- }
- if len(excelFiles) == 0 {
- return "", fmt.Errorf("未找到Excel文件")
- }
- // 返回第一个找到的Excel文件
- return excelFiles[0], nil
- }
- // 获取图片文件路径
- func findImageFile(dir, originalName string) string {
- if dir == "" || originalName == "" {
- return ""
- }
- // 检查不同扩展名的图片文件
- for _, ext := range []string{".png", ".jpg", ".jpeg"} {
- filePath := filepath.Join(dir, originalName+ext)
- if _, err := os.Stat(filePath); err == nil {
- return filePath
- }
- }
- return ""
- }
- // 上传本地图片到OSS
- func uploadLocalImage(filePath string, prefix string, apictx *ApiSession) (*model.OssType, error) {
- // 获取Alibaba Cloud OSS Client
- accessKeyID := apictx.Svc.Conf.Obs.AccessKeyId
- secretKey := apictx.Svc.Conf.Obs.SecrateKey
- endpoint := apictx.Svc.Conf.Obs.Endpoint
- // 创建Alibaba Cloud OSS Client
- client, err := oss.New(endpoint, accessKeyID, secretKey)
- if err != nil {
- return nil, fmt.Errorf("创建OSS Client失败: %v", err)
- }
- // 获取Bucket
- bucketName := apictx.Svc.Conf.Obs.Bucket
- bucket, err := client.Bucket(bucketName)
- if err != nil {
- return nil, fmt.Errorf("获取Bucket失败: %v", err)
- }
- // 上传图片到OSS
- ossPath := fmt.Sprintf("u/%s/%s", apictx.User.ID, prefix)
- ossPath = strings.TrimRight(strings.ReplaceAll(ossPath, "\\", "/"), "/")
- _, fileName := filepath.Split(filePath)
- objectKey := ossPath + "/" + fileName
- // 上传文件
- err = bucket.PutObjectFromFile(objectKey, filePath)
- if err != nil {
- // 重试一次
- err = bucket.PutObjectFromFile(objectKey, filePath)
- if err != nil {
- return nil, fmt.Errorf("上传文件到OSS失败: %v", err)
- }
- }
- // 获取文件大小
- fi, err := os.Stat(filePath)
- size := int64(1)
- if err == nil {
- size = fi.Size()
- }
- // 返回OSS文件信息
- return &model.OssType{
- Url: fmt.Sprintf("https://%s.%s/%s", bucketName, endpoint, objectKey),
- Size: size,
- }, nil
- }
- // 工具函数 - 获取图片URL
- func getImageUrl(oss *model.OssType) string {
- if oss == nil {
- return ""
- }
- return oss.Url
- }
- type ZipExportReq struct {
- MatIds []primitive.ObjectID `json:"matIds"`
- }
- // ZIP导出功能
- func ZipExport(c *gin.Context, apictx *ApiSession) (interface{}, error) {
- // 获取要导出的matIds参数
- var req ZipExportReq
- err := c.ShouldBindJSON(&req)
- if err != nil {
- return nil, fmt.Errorf("参数错误!")
- }
- if len(req.MatIds) == 0 {
- return nil, fmt.Errorf("参数错误!")
- }
- // matId, _ := primitive.ObjectIDFromHex("67f4711195ac3622e01cc073")
- // matId2, _ := primitive.ObjectIDFromHex("67f4710695ac3622e01cc072")
- // req.MatIds = []primitive.ObjectID{matId, matId2}
- // 创建临时目录
- tempDir, err := os.MkdirTemp("", "zipexport_"+time.Now().Format("2006"))
- if err != nil {
- return nil, NewError("创建临时目录失败")
- }
- defer os.RemoveAll(tempDir) // 函数结束时清理临时目录
- // 创建goods和texture子目录
- goodsDir := filepath.Join(tempDir, "goods")
- textureDir := filepath.Join(tempDir, "texture")
- if err := os.Mkdir(goodsDir, 0755); err != nil {
- return nil, NewError("创建goods目录失败")
- }
- if err := os.Mkdir(textureDir, 0755); err != nil {
- return nil, NewError("创建texture目录失败")
- }
- // 转换matIds为ObjectID数组
- objectIds := req.MatIds
- // 查询MatImage记录
- var matImages []model.MatImage
- err = repo.RepoSeachDocs(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
- CollectName: repo.CollectionMatImages,
- Query: repo.Map{"_id": repo.Map{"$in": objectIds}},
- }, &matImages)
- if err != nil {
- return nil, NewError("获取商品数据失败")
- }
- // 获取分类配置
- cat := []*model.Category{}
- err = repo.RepoSeachDocs(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
- CollectName: repo.CollectionCategory,
- Query: repo.Map{},
- Project: []string{"name", "type", "children", "createTime"},
- }, &cat)
- if err != nil {
- return nil, NewError("获取分类配置失败")
- }
- cates := cat[0].Children
- // 使用模板文件
- templatePath := "./template.xlsx"
- // 打开模板文件
- f, err := excelize.OpenFile(templatePath)
- if err != nil {
- return nil, NewError("打开模板文件失败")
- }
- defer f.Close()
- sheet := "Sheet1"
- // 填充数据
- for i, img := range matImages {
- rowIndex := i + 2 // 跳过表头,从第2行开始
- // 下载图片
- var goodsImagePath, textureImagePath string
- if img.ProductImage != nil && img.ProductImage.Url != "" {
- // 从URL中提取原始文件名
- // productImageFileName := getFileNameFromUrl(img.ProductImage.Url)
- productImageFileName := img.CusNum
- goodsImagePath = filepath.Join(goodsDir, productImageFileName)
- downloadImage(img.ProductImage.Url, goodsImagePath)
- }
- if img.RawImage != nil && img.RawImage.Url != "" {
- // 从URL中提取原始文件名
- rawImageFileName := img.CusNum
- // rawImageFileName := getFileNameFromUrl(img.RawImage.Url)
- textureImagePath = filepath.Join(textureDir, rawImageFileName)
- downloadImage(img.RawImage.Url, textureImagePath)
- }
- // 查找对应的分类名称
- var typeCategoryName, MainSupplierName, MnemonicSign, TypeCategory2, TypeCategory2Name, productSeriesName, productUsageName string
- var typeCategory, productSeries, productUsage, baseCloth, baseClothName, surfaceProcess, surfaceProcessName string
- // 先确定商品分类大类/其他大类 排除后用其他id匹配商品分类下面的小类
- var mainCate *model.Category
- matCatesMap := map[string]struct{}{}
- // 复制分类ID到Map中,便于删除已处理的ID
- for _, ic := range img.Categories {
- if ic != "" { // 确保分类ID不为空
- matCatesMap[ic] = struct{}{}
- }
- }
- // 第一轮:查找顶级分类(商品分类、首选供应商、报关助记符)
- for _, catId := range img.Categories {
- if catId == "" { // 跳过空分类ID
- continue
- }
- for _, parentCat := range cates {
- if parentCat == nil { // 防止空指针
- continue
- }
- for _, child := range parentCat.Children {
- if child == nil || child.IdStr == "" { // 防止空指针或空ID
- continue
- }
- if child.IdStr == catId {
- if parentCat.Name == "商品分类" {
- mainCate = child
- typeCategoryName = child.Name
- typeCategory = catId
- delete(matCatesMap, catId)
- } else if parentCat.Name == "首选供应商" {
- MainSupplierName = child.Name
- delete(matCatesMap, catId)
- } else if parentCat.Name == "报关助记符" {
- MnemonicSign = child.Name
- delete(matCatesMap, catId)
- }
- }
- }
- }
- }
- // 第二轮:如果找到了商品分类,查找其子分类
- if mainCate != nil && len(matCatesMap) > 0 {
- for k := range matCatesMap {
- if k == "" { // 跳过空ID
- continue
- }
- // 防止空指针
- if mainCate.Children == nil {
- continue
- }
- for _, mchild := range mainCate.Children {
- if mchild == nil || mchild.Children == nil { // 防止空指针
- continue
- }
- for _, mc := range mchild.Children {
- if mc == nil || mc.IdStr == "" { // 防止空指针或空ID
- continue
- }
- if mc.IdStr == k {
- if mchild.Name == "种类分类" {
- TypeCategory2 = mc.CusNum
- TypeCategory2Name = mc.Name
- } else if mchild.Name == "产品系列" {
- productSeriesName = mc.Name
- productSeries = mc.CusNum
- } else if mchild.Name == "产品用途" {
- productUsageName = mc.Name
- productUsage = mc.CusNum
- } else if mchild.Name == "基布" {
- baseCloth = mc.CusNum
- baseClothName = mc.Name
- } else if mchild.Name == "表面工艺" {
- surfaceProcess = mc.CusNum
- surfaceProcessName = mc.Name
- }
- }
- }
- }
- }
- }
- // 构建行数据
- f.SetCellValue(sheet, fmt.Sprintf("A%d", rowIndex), img.CusNum) // 公司商品编号
- f.SetCellValue(sheet, fmt.Sprintf("B%d", rowIndex), img.NameCN) // 商品中文名
- f.SetCellValue(sheet, fmt.Sprintf("C%d", rowIndex), img.NameEN) // 商品英文名
- f.SetCellValue(sheet, fmt.Sprintf("D%d", rowIndex), typeCategoryName) // 分类
- f.SetCellValue(sheet, fmt.Sprintf("E%d", rowIndex), "") // 图片
- // 体积重量信息
- if img.PackageGrossWeight != nil {
- f.SetCellValue(sheet, fmt.Sprintf("F%d", rowIndex), *img.PackageGrossWeight) // 单位包材毛重(KG)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("F%d", rowIndex), 0) // 默认为0
- }
- if img.PackageVolume != nil {
- f.SetCellValue(sheet, fmt.Sprintf("G%d", rowIndex), *img.PackageVolume) // 单位包材体积(CBM)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("G%d", rowIndex), 0) // 默认为0
- }
- if img.PhyHeight != nil {
- f.SetCellValue(sheet, fmt.Sprintf("H%d", rowIndex), *img.PhyHeight) // 长度(MM)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("H%d", rowIndex), 0) // 默认为0
- }
- if img.PhyWidth != nil {
- f.SetCellValue(sheet, fmt.Sprintf("I%d", rowIndex), *img.PhyWidth) // 门幅/宽(MM)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("I%d", rowIndex), 0) // 默认为0
- }
- if img.Thickness != nil {
- f.SetCellValue(sheet, fmt.Sprintf("J%d", rowIndex), *img.Thickness) // 厚度/高(MM)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("J%d", rowIndex), 0) // 默认为0
- }
- f.SetCellValue(sheet, fmt.Sprintf("K%d", rowIndex), img.Remarks) // 备注
- f.SetCellValue(sheet, fmt.Sprintf("L%d", rowIndex), MainSupplierName) // 首选供应商
- // 默认采购单价
- if img.Price != nil {
- f.SetCellValue(sheet, fmt.Sprintf("M%d", rowIndex), *img.Price)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("M%d", rowIndex), "")
- }
- // 查询样品搜集人的名称
- staffName := ""
- staffId := ""
- if img.From != "" {
- staff := model.StaffUser{}
- // 验证样品收集人是否预设
- found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
- CollectName: repo.CollectionStaffUser,
- Query: repo.Map{"name": img.From},
- }, &staff)
- if found {
- staffName = staff.Name
- staffId = staff.Id.Hex()
- }
- }
- // 样品搜集人 - 注意Excel示例中有两列样品搜集人
- f.SetCellValue(sheet, fmt.Sprintf("N%d", rowIndex), staffId) // 样品搜集人代码
- f.SetCellValue(sheet, fmt.Sprintf("O%d", rowIndex), staffName) // 样品搜集人名称
- // 开发日期
- if img.DevTime != nil {
- f.SetCellValue(sheet, fmt.Sprintf("P%d", rowIndex), img.DevTime.Format("2006/1/2"))
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("P%d", rowIndex), "")
- }
- // // 商品属性 - 使用True/False字符串而不是布尔值
- // if img.ExportProperty != nil {
- // f.SetCellValue(sheet, fmt.Sprintf("Q%d", rowIndex), boolToString(*img.ExportProperty)) // 出口属性
- // } else {
- // f.SetCellValue(sheet, fmt.Sprintf("Q%d", rowIndex), "False")
- // }
- // if img.DomesticProperty != nil {
- // f.SetCellValue(sheet, fmt.Sprintf("R%d", rowIndex), boolToString(*img.DomesticProperty)) // 内销属性
- // } else {
- // f.SetCellValue(sheet, fmt.Sprintf("R%d", rowIndex), "False")
- // }
- // if img.InpurchaseProperty != nil {
- // f.SetCellValue(sheet, fmt.Sprintf("S%d", rowIndex), boolToString(*img.InpurchaseProperty)) // 内购属性
- // } else {
- // f.SetCellValue(sheet, fmt.Sprintf("S%d", rowIndex), "False")
- // }
- // if img.OutsourcedProperty != nil {
- // f.SetCellValue(sheet, fmt.Sprintf("T%d", rowIndex), boolToString(*img.OutsourcedProperty)) // 委外属性
- // } else {
- // f.SetCellValue(sheet, fmt.Sprintf("T%d", rowIndex), "False")
- // }
- f.SetCellValue(sheet, fmt.Sprintf("Q%d", rowIndex), MnemonicSign) // 报关助记符
- f.SetCellValue(sheet, fmt.Sprintf("R%d", rowIndex), img.TaxGoodsNumber) // 报关商品编码
- f.SetCellValue(sheet, fmt.Sprintf("S%d", rowIndex), img.TaxNameCN) // 报关商品中文名
- // 录入人名称
- f.SetCellValue(sheet, fmt.Sprintf("T%d", rowIndex), apictx.User.Name) // 录入人名称
- // f.SetCellValue(sheet, fmt.Sprintf("X%d", rowIndex), "测试默认") // 录入人名称
- f.SetCellValue(sheet, fmt.Sprintf("U%d", rowIndex), img.FitMarket) // 适合的市场
- f.SetCellValue(sheet, fmt.Sprintf("V%d", rowIndex), img.SupplierID) // 供应商编号
- f.SetCellValue(sheet, fmt.Sprintf("W%d", rowIndex), TypeCategory2) // 种类分类
- f.SetCellValue(sheet, fmt.Sprintf("X%d", rowIndex), TypeCategory2Name) // 种类分类名称
- f.SetCellValue(sheet, fmt.Sprintf("Y%d", rowIndex), baseCloth) // 基布
- f.SetCellValue(sheet, fmt.Sprintf("Z%d", rowIndex), baseClothName) // 基布名称
- f.SetCellValue(sheet, fmt.Sprintf("AA%d", rowIndex), surfaceProcess) // 表面工艺
- f.SetCellValue(sheet, fmt.Sprintf("AB%d", rowIndex), surfaceProcessName) // 表面工艺名称
- // 产品克重
- if img.ProductWeight != nil {
- f.SetCellValue(sheet, fmt.Sprintf("AC%d", rowIndex), *img.ProductWeight) // 产品克重(KG)
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("AC%d", rowIndex), 0)
- }
- f.SetCellValue(sheet, fmt.Sprintf("AD%d", rowIndex), img.OperationCycle) // 运营周期
- // 商品单位体积
- if img.ProductVolume != nil {
- f.SetCellValue(sheet, fmt.Sprintf("AE%d", rowIndex), *img.ProductVolume) // 商品单位体积
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("AE%d", rowIndex), 0)
- }
- // 商品分类代码
- // !!!! 商品分类代码哪个字段未明确
- f.SetCellValue(sheet, fmt.Sprintf("AF%d", rowIndex), typeCategory) // 商品分类代码
- f.SetCellValue(sheet, fmt.Sprintf("AG%d", rowIndex), productSeries) // 产品系列
- f.SetCellValue(sheet, fmt.Sprintf("AH%d", rowIndex), productSeriesName) // 产品系列代码
- f.SetCellValue(sheet, fmt.Sprintf("AI%d", rowIndex), productUsage) // 产品用途
- f.SetCellValue(sheet, fmt.Sprintf("AJ%d", rowIndex), productUsageName) // 产品用途代码
- f.SetCellValue(sheet, fmt.Sprintf("AK%d", rowIndex), img.SampleNumber) // 样品编号
- f.SetCellValue(sheet, fmt.Sprintf("AL%d", rowIndex), img.CatalogNumber) // 留样册号
- f.SetCellValue(sheet, fmt.Sprintf("AM%d", rowIndex), img.OriginalNumber) // 原命名编号
- // 底布克重
- if img.BackingWeight != nil {
- f.SetCellValue(sheet, fmt.Sprintf("AN%d", rowIndex), *img.BackingWeight) // 底布克重
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("AN%d", rowIndex), 0)
- }
- // 面布克重
- if img.SurfaceWeight != nil {
- f.SetCellValue(sheet, fmt.Sprintf("AO%d", rowIndex), *img.SurfaceWeight) // 面布克重
- } else {
- f.SetCellValue(sheet, fmt.Sprintf("AO%d", rowIndex), 0)
- }
- }
- // 调整列宽
- for i := range fixedHeaders {
- colName := columnIndexToName(i)
- f.SetColWidth(sheet, colName, colName, 15)
- }
- // 保存Excel到临时目录
- excelPath := filepath.Join(tempDir, "export.xlsx")
- if err := f.SaveAs(excelPath); err != nil {
- return nil, NewError("保存Excel文件失败")
- }
- // 创建ZIP文件
- zipPath := filepath.Join(tempDir, "export.zip")
- zipFile, err := os.Create(zipPath)
- if err != nil {
- return nil, NewError("创建ZIP文件失败")
- }
- defer zipFile.Close()
- // 创建ZIP writer
- zipWriter := zip.NewWriter(zipFile)
- defer zipWriter.Close()
- // 添加Excel文件到ZIP
- if err := addFileToZip(zipWriter, excelPath, "export.xlsx"); err != nil {
- return nil, NewError("添加Excel文件到ZIP失败")
- }
- // 添加goods目录到ZIP
- if err := addDirToZip(zipWriter, goodsDir, "goods"); err != nil {
- return nil, NewError("添加goods目录到ZIP失败")
- }
- // 添加texture目录到ZIP
- if err := addDirToZip(zipWriter, textureDir, "texture"); err != nil {
- return nil, NewError("添加texture目录到ZIP失败")
- }
- // 关闭ZIP writer
- zipWriter.Close()
- // 读取ZIP文件内容
- zipData, err := os.ReadFile(zipPath)
- if err != nil {
- return nil, NewError("读取ZIP文件失败")
- }
- // 设置响应头,使浏览器下载文件
- c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=export_%s.zip", time.Now().Format("20060102150405")))
- c.Writer.Header().Set("Content-Type", "application/zip")
- c.Writer.Header().Set("Content-Transfer-Encoding", "binary")
- c.Writer.Write(zipData)
- return nil, nil
- }
- // 下载图片到本地文件
- func downloadImage(url string, destPath string) error {
- // 发起HTTP GET请求
- resp, err := http.Get(url)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- // 检查响应状态
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("下载图片失败,状态码: %d", resp.StatusCode)
- }
- // 创建目标文件
- out, err := os.Create(destPath)
- if err != nil {
- return err
- }
- defer out.Close()
- // 将响应内容写入文件
- _, err = io.Copy(out, resp.Body)
- return err
- }
- // 添加文件到ZIP
- func addFileToZip(zipWriter *zip.Writer, filePath, zipPath string) error {
- file, err := os.Open(filePath)
- if err != nil {
- return err
- }
- defer file.Close()
- info, err := file.Stat()
- if err != nil {
- return err
- }
- header, err := zip.FileInfoHeader(info)
- if err != nil {
- return err
- }
- header.Name = zipPath
- header.Method = zip.Deflate
- writer, err := zipWriter.CreateHeader(header)
- if err != nil {
- return err
- }
- _, err = io.Copy(writer, file)
- return err
- }
- // 添加目录到ZIP
- func addDirToZip(zipWriter *zip.Writer, dirPath, zipPath string) error {
- files, err := os.ReadDir(dirPath)
- if err != nil {
- return err
- }
- // 先创建目录条目
- if zipPath != "" {
- dirEntry := &zip.FileHeader{
- Name: zipPath + "/",
- Method: zip.Deflate,
- }
- dirEntry.SetMode(0755 | os.ModeDir)
- _, err = zipWriter.CreateHeader(dirEntry)
- if err != nil {
- return err
- }
- }
- for _, file := range files {
- filePath := filepath.Join(dirPath, file.Name())
- // 使用斜杠作为ZIP文件中的路径分隔符,确保跨平台兼容性
- zipFilePath := zipPath + "/" + file.Name()
- if zipPath == "" {
- zipFilePath = file.Name()
- }
- if file.IsDir() {
- // 递归添加子目录
- if err := addDirToZip(zipWriter, filePath, zipFilePath); err != nil {
- return err
- }
- } else {
- // 添加文件
- if err := addFileToZip(zipWriter, filePath, zipFilePath); err != nil {
- return err
- }
- }
- }
- return nil
- }
- // 工具函数 - 格式化日期
- func formatDate(t *time.Time) string {
- if t == nil {
- return ""
- }
- return t.Format("2006-01-02")
- }
- // 工具函数 - 将布尔值转换为字符串
- func boolToString(b bool) string {
- if b {
- return "True"
- }
- return "False"
- }
- // 工具函数 - 从URL中提取文件名
- func getFileNameFromUrl(url string) string {
- // 从URL中提取文件名
- fileName := path.Base(url)
- return fileName
- }
- // 工具函数 - 将列索引转换为Excel列名(支持多字母列名,如AA, AB等)
- func columnIndexToName(index int) string {
- result := ""
- for index >= 0 {
- remainder := index % 26
- result = string(rune('A'+remainder)) + result
- index = index/26 - 1
- }
- return result
- }
|