12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724 |
- // 导入导出功能
- 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 {
- return imageMat, fmt.Errorf("%s的首选供应商未找到定义", row[MainSupplierIndex])
- }
- //添加首先供应商
- 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
- }
|